什么是系统调用
系统调用在用户进程和硬件设备之间添加了一个中间层。该层的作用有三个:
- 首先,它为用户空间提供了一种硬件抽象接口,举例来说,当需要读写文件的时候,应用程序就可以不去管磁盘类型和介质,甚至不用去管文件所在的文件系统是那种类型。
- 第二,系统调用保证了系统的稳定和安全。作为硬件设备和应用程序之间的中间人,内核可以基于权限、用户类型和其它一些规则对需要进行的访问进行裁决。
- 第三,每个进程都运行在虚拟系统中,而在用户空间和系统的其余部分提供这样一层公共接口,也是出于这种考虑。
系统调用是用户空间访问内核的唯一手段;除异常和陷入外,它们是内核唯一的合法入口,实际上其它设备文件和/proc之类的方式,最终也还是要通过系统调用进行访问。
一般情况下,应用程序通过用户空间时线的应用编程接口(API)而不是直接通过系统调用来编程,好处在于,API可以在各种不同的操作系统上使用相应的系统调用来实现而给应用程序提供完全相同的接口。
系统调用过程
arm 平台系统调用的具体过程参考之前的一篇文章:Arm Linux系统调用流程详细解析-SWI
系统调用上下文
内核在执行系统调用的时候处于进程上下文,内核可以休眠(比如在系统调用中阻塞或显示调用schedule()),并且可以抢占。
为什么不适用系统调用的方式来实现
建立一个新的系统调用非常容易,但绝不提倡这么做,通常都有更好的办法来替代新建一个系统调用以作实现。
建立一个新的系统调用的好处:
- 系统调用创建容易而且使用方便。
- Linux 系统调用的高性能显而易见。
问题是:
- 你需要一个系统调用号,而这需要在一个内核处于开发版本的时候由官方分配给你。
- 系统调用被加入稳定内核后就被固化了,为了避免应用程序的崩溃,它的接口不允许做改动。
- 需要将系统调用分别注册到每个需要支持的体系结构中去。
- 在脚本中不容易调用系统调用,而不能从文件系统中直接访问系统调用。
- 由于你需要系统调用号,因此在主内核树之外是很难维护和使用系统调用的。
- 如果仅仅是简单的信息交换,系统调用就大材小用了。
替代方法
- 实现一个设备节点,并对此实现 read() write() ,使用 ioctl() 对特定的设置进行操作或者对特定的信息进行检索。
- 像信号量这样的某些接口,可以用文件描述符来表示,因此也就可以按上述方法进行操作。
- 把增加的信息作为一个文件放在 sysfs 的合适位置。