对于进程来说,它既有内核空间(与其他进程共享),也有用户空间(进程私有私有)。不
管是内核空间还是用户空间,它们都处于虚拟地址空间。
内核空间和用户空间交换数据的方式有很多。用户空间发起的有系统调用、proc、虚拟文
件系统等。内核空间主动发起的有get_user/put_user、信号、netlink等。
Linux应用程序与内核程序交互主要有以下几种通信方式:
(1)系统调用
Linux系统下,设备即文件,也因此大部分设备驱动程序都实现了标准的系统接口,如:
● open(),read(),write(), ioctl(), mmap()
● get_user(x,ptr):在内核中被调用,获取用户空间指定地址的数值并保存到内核变量x中。
● put_user(x,ptr):在内核中被调用,将内核空间变量x的数值保存到到用户空间指定地址处
● Copy_from_user() / copy_to_user():主要应用于设备驱动读写函数中,通过系统调用触发
(2)虚拟文件系统
● proc文件系统
● sysfs文件系统
● debugfs文件系统
很多内核程序细节,如中断等,都在proc/目录下有所体现,虚拟文件系统提供了一种便捷的
用户空间和内核空间的交互方式;
(3)netlink
(4)内存映像
mmap共享内存。Linux通过mmap的把内核中特定部分的内存空间映射到用户级程序的内存
空间去,从而提供了用户程序对内存直接访问的能力。该方式尤其适合在那些内核和用户空间需要
快速大量交互数据的情况下。
(5)内核程序使用信号通知应用程序
信号在内核里的用途主要集中在通知用户程序出现重大错误,强行杀死当前进程,这时内核
通过发送SIGKILL信号通知进程终止。
信号发送必须要事先知道进程序号(pid),所以要想从内核中通过发信号的方式异步通
知用户进程执行某项任务,那么必须事先知道用户进程的进程号才可以(可以让应用程序通过oictl
函数,把自己的PID主动告诉驱动程序)。而一般内核运行时搜索特定进程的进程号是个费事的工
作,可能要遍历整个进程控制块链表。所以用信号通知特定用户进程的方法很糟糕,一般在内核不
会使用。内核中使用信号的情形只出现在通知当前进程(可以从current变量中方便获得pid)做某
些通用操作,如终止操作等。因此对内核开发者该方法用处不大。类似情况还有消息操作。
(6)从内核空间回调用户程序。
(7)自定义系统调用。
(8)文件