操作系统课上老师只用了一页ppt讲了三个kthread的api, 就出了如标题的这么一个问题
顺手就当做之前理论学习的上手实践了(逃
首先给出一段非百分百原创的代码
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/module.h>
#include <linux/init.h>
static struct task_struct *test_task;
int threadfuc(void)
{
int i = 0;
while(1)
{
set_current_state(TASK_UNINTERRUPTIBLE);
if (kthread_should_stop()) break;
if (1)
{
printk(KERN_INFO "i = %d\n", i);
i++;
}
schedule_timeout(HZ);
}
return 0;
}
static int test_init(void)
{
test_task = kthread_run(threadfuc, NULL, "test_task");
printk(KERN_INFO"module enter");
return 0;
}
static void test_cleanup(void)
{
if(test_task)
{
kthread_stop(test_task);
test_task = NULL;
printk(KERN_INFO"module remove");
}
}
module_init(test_init);
module_exit(test_cleanup);
1. 首先是module程序的编写与加载
module程序使用c语言编写
这个程序不需要main入口
module程序使用insmod和rmmod两个命令加载
(加载编译出来的 .ko文件, 下文会提到如何编译
在加载insmod命令的时候
module_init(test_init);
test_init这个函数名作为参数传入, 并且模块程序从test_init处开始运行
同理, 在rmmod的时候
module_exit(test_cleanup);
中的test_cleanup函数执行, 进行清理善后工作.
2. 内核模块程序的编译
同样先给出makefile(完全非原创)(逃
(是可以直接使用的, 可移植性蛮好的(强行
KVERS = $(shell uname -r)
obj-m := task_test.o
build: kernel_modules
kernel_modules:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) modules
clean:
make -C /lib/modules/$(KVERS)/build M=$(CURDIR) clean
姑且先把它当成一个模板来用(真不负责
要改的地方大概只有obj-m 后面的文件名了,改成自己的就可以了
小小的解释一下:
/lib/modules/$(KVERS)/build 指定到已经编译的内核的目录
M=$(CURDIR) 要编译的源文件的目录
具体的解释以后挖个坑以后慢慢填,坑++
3. 内核模块程序的交互
不像命令行程序, 内核模块的交互并不通过printf在命令行里输出结果
在这里介绍一下printf的孪生姐妹printk(太太和小姨子)
printk与printf的差异,是什么导致一个运行在内核态而另一个运行用户态?其实这两个函数几乎是相同的,出现这种差异是因为tty_write函数需要使用fs指向的被显示的字符串,而fs是专门用于存放用户态段选择符的,因此,在内核态时,为了配合tty_write函数,printk会把fs修改为内核态数据段选择符ds中的值,这样才能正确指向内核的数据缓冲区,当然这个操作会先对fs进行压栈保存,调用tty_write完毕后再出栈恢复。总结说来,printk与printf的差异是由fs造成的,所以差异也是围绕对fs的处理。
来源于百度百科
对于上面这个程序, printk的输出可以使用dmesg命令查看, 当然对于这种工具使用管道( | )配合上文字处理工具(tail, more, grep等)来使用就非常舒服了
比如 dmesg | tail -3 就可以查看最后三条记录
当然 , 使用ps aux或top加上grep也是可以的
雷区预警
- 代码函数中的void不能省略
- 由于网页上编码格式等问题, 复制下来的代码最好重新抄码一遍
网友评论