zoukankan      html  css  js  c++  java
  • Linux下新增和使用系统调用

    关键词:__SYSCALL()、SYSCALL_DEFINEx()、syscall()等等。

    1. 为什么使用syscall

    内核和用户空间数据交换有很多种方式:sysfs、proc、信号等等。

    但是syscall效率要高于这些方式,使用起来也更加简单。

    缺点是可移植性差,对于新增的系统调用,需要内核和用户空间同步。

    2. 如何添加syscall

    每个系统调用都有一个系统调用号,这个系统调用号对应sys_call_table[]下标。

    通过sys_call_table[syscallid]就可以对应到此系统调用的函数。

    在include/uapi/asm/unistd.h中添加__NR_basetime系统调用号,关联系统调用号和系统调用函数。

    diff --git a/arch/csky/include/uapi/asm/unistd.h b/arch/csky/include/uapi/asm/unistd.h
    index 98e62b9..a1b6503 100644
    --- a/arch/csky/include/uapi/asm/unistd.h
    +++ b/arch/csky/include/uapi/asm/unistd.h
    @@ -43,6 +43,11 @@ __SYSCALL(__NR_ugetrlimit, sys_getrlimit)
     #define __NR_sysfs             (__NR_arch_specific_syscall + 5)
     __SYSCALL(__NR_sysfs, sys_sysfs)
     
    +#ifdef CONFIG_PERF_TIMER
    +#define __NR_basetime  (__NR_arch_specific_syscall + 6)
    +__SYSCALL(__NR_basetime, sys_basetime)
    +#endif

    __SYSCALL()将sys_call_table[]中的系统调用号和系统调用函数关联起来。

    #undef __SYSCALL
    #define __SYSCALL(nr, call) [nr] = (call),
    
    #define sys_fadvise64_64 sys_csky_fadvise64_64
    void * const sys_call_table[__NR_syscalls] __page_aligned_data = {
        [0 ... __NR_syscalls - 1] = sys_ni_syscall,
    #include <asm/unistd.h>
    };

    在include/asm/syscalls.h中添加sys_basetime()引用。

    #ifdef CONFIG_PERF_TIMER
    long sys_basetime(void);
    #endif

    最后就是sys_basetime()的实现:

    SYSCALL_DEFINE0(basetime)
    {
           return perf_timer_read_us();
    }

    2.1 SYSCALL_DEFINEx()

    当SYSCALL_DEFINEx()的x为0时,很简单就是调用sys_##name()函数。

    x为其他值时,同时定义了几个函数,并使用了别名属性。

    #define SYSCALL_DEFINE0(sname)                    
        SYSCALL_METADATA(_##sname, 0);                
        asmlinkage long sys_##sname(void)
    
    #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
    #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
    #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
    #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
    #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
    #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
    
    #define SYSCALL_DEFINEx(x, sname, ...)                
        SYSCALL_METADATA(sname, x, __VA_ARGS__)            
        __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
    
    #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
    #define __SYSCALL_DEFINEx(x, name, ...)                    
        asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))    
            __attribute__((alias(__stringify(SyS##name))));        
        static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));    
        asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));    
        asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))    
        {                                
            long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__));    
            __MAP(x,__SC_TEST,__VA_ARGS__);                
            __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));    
            return ret;                        
        }                                
        static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))

    3. 使用syscall

    用户空间系统调用的使用通过syscall函数:

    #define _GNU_SOURCE         /* See feature_test_macros(7) */
    #include <unistd.h>
    #include <sys/syscall.h>   /* For SYS_xxx definitions */
    
    long syscall(long number, ...);

    第一个参数是系统调用号,后面的参数是内核对应sys_##name()函数一致的。

    #include <stdio.h>
    #include <unistd.h>
    
    #define __NR_basetime    250
    void main(void)
    {
        unsigned int timestamp = 0, i = 0;
    
        for(i = 0; i < 100; i++) {
            timestamp = syscall(__NR_basetime);
            printf("timestamp=%u
    ", timestamp);
            usleep(1000);
        }
    }

    用户空间通过syscall()函数,触发系统调用,使系统由用户态陷入到内核态。

    在系统个调用异常里面获取到系统调用号,以及必须的参数。根据系统调用号和sys_call_table[]找到对应系统调用函数。

    以syscall()其余部分参数为入参,执行相关结果。完成后返还给用户空间。

  • 相关阅读:
    GoCN每日新闻(2019-10-14)
    GoCN每日新闻(2019-10-13)
    GoCN每日新闻(2019-10-12)
    GoCN每日新闻(2019-10-11)
    [xms]西软xms试算平衡报表-穿透明细报表-增加储值卡卡号列
    GoCN每日新闻(2019-10-10)
    GoCN每日新闻(2019-10-09)
    GoCN每日新闻(2019-10-08)
    GoCN每日新闻(2019-10-07)
    [golang]Golang实现高并发的调度模型---MPG模式
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/11149648.html
Copyright © 2011-2022 走看看