美文网首页
实现Linux中的可加载的内核模块(包含一个内核线程)

实现Linux中的可加载的内核模块(包含一个内核线程)

作者: TsushimaAlice | 来源:发表于2018-04-07 22:44 被阅读0次

    操作系统课上老师只用了一页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 auxtop加上grep也是可以的


    雷区预警

    • 代码函数中的void不能省略
    • 由于网页上编码格式等问题, 复制下来的代码最好重新抄码一遍

    相关文章

      网友评论

          本文标题:实现Linux中的可加载的内核模块(包含一个内核线程)

          本文链接:https://www.haomeiwen.com/subject/oljuhftx.html