关键词:__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系统调用号,关联系统调用号和系统调用函数。

  1. diff --git a/arch/csky/include/uapi/asm/unistd.h b/arch/csky/include/uapi/asm/unistd.h
  2. index 98e62b9..a1b6503
  3. --- a/arch/csky/include/uapi/asm/unistd.h
  4. +++ b/arch/csky/include/uapi/asm/unistd.h
  5. @@ -, +, @@ __SYSCALL(__NR_ugetrlimit, sys_getrlimit)
  6. #define __NR_sysfs (__NR_arch_specific_syscall + 5)
  7. __SYSCALL(__NR_sysfs, sys_sysfs)
  8.  
  9. +#ifdef CONFIG_PERF_TIMER
  10. +#define __NR_basetime (__NR_arch_specific_syscall + 6)
  11. +__SYSCALL(__NR_basetime, sys_basetime)
  12. +#endif

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

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

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

  1. #ifdef CONFIG_PERF_TIMER
  2. long sys_basetime(void);
  3. #endif

最后就是sys_basetime()的实现:

  1. SYSCALL_DEFINE0(basetime)
  2. {
  3. return perf_timer_read_us();
  4. }

2.1 SYSCALL_DEFINEx()

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

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

  1. #define SYSCALL_DEFINE0(sname) \
  2. SYSCALL_METADATA(_##sname, ); \
  3. asmlinkage long sys_##sname(void)
  4.  
  5. #define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__)
  6. #define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)
  7. #define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__)
  8. #define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)
  9. #define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__)
  10. #define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__)
  11.  
  12. #define SYSCALL_DEFINEx(x, sname, ...) \
  13. SYSCALL_METADATA(sname, x, __VA_ARGS__) \
  14. __SYSCALL_DEFINEx(x, sname, __VA_ARGS__)
  15.  
  16. #define __PROTECT(...) asmlinkage_protect(__VA_ARGS__)
  17. #define __SYSCALL_DEFINEx(x, name, ...) \
  18. asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \
  19. __attribute__((alias(__stringify(SyS##name)))); \
  20. static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \
  21. asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \
  22. asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \
  23. { \
  24. long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \
  25. __MAP(x,__SC_TEST,__VA_ARGS__); \
  26. __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \
  27. return ret; \
  28. } \
  29. static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__))

3. 使用syscall

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

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

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

  1. #include <stdio.h>
  2. #include <unistd.h>
  3.  
  4. #define __NR_basetime 250
  5. void main(void)
  6. {
  7. unsigned int timestamp = , i = ;
  8.  
  9. for(i = ; i < ; i++) {
  10. timestamp = syscall(__NR_basetime);
  11. printf("timestamp=%u\n", timestamp);
  12. usleep();
  13. }
  14. }

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

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

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

Linux下新增和使用系统调用的更多相关文章

  1. linux下syscall函数 间接系统调用

    NAME              syscall - 间接系统调用 SYNOPSIS              #define _GNU_SOURCE               #include ...

  2. 在linux下新增一块硬盘的操作。(包含大于2T的硬盘在linux下挂载操作)

    转自:http://blog.csdn.net/season_hangzhou/article/details/36423223 一.安装硬盘到物理机上. 二.查看硬盘是否正确安装. 使用“fdisk ...

  3. Linux 下新增用户的流程

    一: 新增用户 1.添加新的用户账号使用useradd命令,其语法如下: 代码:useradd 选项 用户名其中各选项含义如下: 代码:-c comment 指定一段注释性描述.-d 目录 指定用户主 ...

  4. Linux 下 新增Oracle10g 实例

    主要分为5步:创建实例目录,创建密码文件,创建参数文件,创建建库脚本并建库,创建数据字典. 其中,需要特别注意2点: 目录的权限,即用户和所属用户组都要是oracle.可以切换到已存在的oracle用 ...

  5. Linux 下新增虚拟内存

    问题描述,电脑内存1G.在启用elasticsearch的时候,报错 Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memor ...

  6. Linux 下系统调用的三种方法

    系统调用(System Call)是操作系统为在用户态运行的进程与硬件设备(如CPU.磁盘.打印机等)进行交互提供的一组接口.当用户进程需要发生系统调用时,CPU 通过软中断切换到内核态开始执行内核系 ...

  7. Linux C 文件操作,系统调用 -- open()、read() 和 标准I/O库 -- fopen()、fread()

    函数汇总: open().write().read().close() fopen().fwrite().fread().fclose() 一.什么是文件 在讲述文件操作之前,我们首先要知道什么是文件 ...

  8. linux下64位汇编的系统调用(5)

    看到这里大家都基本知道了如何进行linux下的汇编系统调用:不过有些童鞋可能会问:那些C库中函数里为我们解决的额外汇编代码你是怎么知道的? 好吧,我承认:我是通过逆向知道的,这貌似有点犯规的嫌疑- 比 ...

  9. linux下64位汇编的系统调用(3)

    背景知识基本交代清楚了,下面我们实际写一个小例子看一下.代码的功能很简单,显示一行文本,然后退出.我们使用了syscall中的write和exit调用,查一下前面的调用号和参数,我们初步总结如下: w ...

随机推荐

  1. CMake工程找不到相应的cuDNN版本的问题

    (1) 去官网下载相应的版本,因为电脑之前安装的是 CUDA8. ,找跟 CUDA 版本兼容的 cuDNN 下载即可,我选择的是 cuDNN v7.(Deb) 和  cuDNN v7.1.4 Deve ...

  2. 创建mysql索引的方式

    创建索引方式: 1.create index 索引名   on 表名 (字段) 2.alter table 表  add index 索引名  (字段) -- 普通索引 alter table 表名 ...

  3. java8新特性之——lambda表达式的使用

    lambda表达式简介 个人理解,lambda表达式就是一种新的语法,没有什么新奇的,简化了开发者的编码,其实底层还是一些常规的代码.Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解 ...

  4. 带你自行搭建虚拟机和Redis集群环境,值得收藏!

    前言: 我们看到分析 Redis 使用或原理的文章不少,但是完整搭建一套独立的 redis 集群环境的介绍,并不是很多或者说还不够详细. 那么,本文会手把手带着大家搭建一套 Redis 集群环境,Re ...

  5. 部署vue-element-admin流程

    1.修改环境变量: 在以下两个文件: .env_staging [如果修改这个,需要以npm run build:stage启动] .env_production [如果修改这个,需要以npm run ...

  6. 前端开发规范:2-HTML

    HTML标签 文档声明,除非必须要兼容IE6等远古浏览器,否则一律使用HTML5文档类型申明<!DOCTYPE html> 标签闭合,img.br.hr 等自闭合标签不使用闭合斜杠 met ...

  7. 49-在 overlay 中运行容器

    上一节我们创建了 overlay 网络 ov_net1,今天将运行一个 busybox 容器并连接到 ov_net1: 查看容器的网络配置: bbox1 有两个网络接口 eth0 和 eth1.eth ...

  8. Mac录制或保存视频后如何放大?

    想要在录制和拍摄视频后在喜欢的场景(例如Mark)中放大视频吗?本文将向您展示如何放大视频并通过裁剪视频和“平移和缩放”效果来制作Ken Burns效果.Filmora9是一款功能强大的视频编辑器,具 ...

  9. CentOS高可用集群LVS+Keepalived(DR模式)

    操作系统:CentOS6.5_x64 mini 负载均衡模式:DR(直接路由) LVS与Keepalived简述: LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是 ...

  10. C语言和其他语言的区别

    一.嵌入式开发中为什么选择C语言? 首先嵌入式是在已有的硬件基础上,移植操作系统,而现在操作系统的内核都是用C实现的 二.为什么用C语言开发操作系统内核? C语言有三大特点(优点): ①C语言具有出色 ...