一、内核模块和应用程序的区别
1)所有的内核模块的初始化和加载方式都是事件驱动的(event-driven,),但是并不是所有的应用程序都这样。
2)退出方式的区别:应用程序可以延迟释放资源甚至完全不处理资源释放,但是内核模块必须小心谨慎地清理init函数初始化的内容,否则遗留下来的东西后保留到系统重启为止。
3)对于应用程序可以调用很多函数功能,在连接期间会对引用相应的库,但是对于内核模块,只能引用内核导出的函数,例如printk。
4)另外一个重要的区别是,应用程序在开发期间导致段错误对系统并没有多大的影响,而且通过调试工具很快就能定位错误;而对于内核模块,如果没有让整个系统挂掉,至少当前进程是会被搞挂的。
二、用户空间和内核空间
1、内核模块运行在内核空间,应用程序运行在用户空间。
2、当进程进行系统调用或者被硬件中断打断时,会发生从进程空间到内核空间的转换。执行系统调用的内核代码是基于当前进程的上下文的,它可以访问进程地址空间的数据。而对于处理中断的代码和进程是无关的,也不能访问进程空间。
3、内核模块的作用是扩展内核的功能,有的是通过系统系统调用实现的,有的是通过中断处理实现的。
三、内核空间的并发
1、Linux系统在存在多个进程并行的情况,也就存在同时有多个进程访问你的驱动。
2、大多数设备都可以中断处理器,中断处理程序也可以异步运行,它同时在你的驱动运行的时候也可以被调用,并且一些software abstractions(例如内核时钟)也是异步运行的。
3、linux也可以运行在对称多处理器(SMP)上,因而导致你的模块需要在多个CPU上运行
4、2.6的内核是可抢占的,这也导致了单核系统上需要面临和多核系统一样的问题。
四、当前进程
- printk(KERN_INFO "The process is \"%s\" (pid %i)\n",
- current->comm, current->pid);
五、几个细节
1、应用程序处在虚拟空间中,所以有一个很大的堆栈,但是内核模块只有一个很小的堆栈,4096字节的页,所以你的函数必须与内核空间调用链共用这个栈,因此尽量不要定义较大的自动变量,如果实在需要,就进行动态分配;
2、当你查看内核API时,你会发现很多以"__"开始的函数,这表明该函数是一个底层的系统组件,调用时要十分细心;
3、内核代码不能进行浮点数运算,如果允许浮点运算的话,则要求每次在进入和离开内核空间时,要保存和恢复浮点处理器的状态,这样是不值得的。
阅读(1262) | 评论(2) | 转发(0) |