实验题目:

http://gauss.ececs.uc.edu/Courses/c4029/labs/lab2.html

题目是来自国外某知名大学的作业。具体翻译就不说了,大致就是用kthread和workqueue循环打印日志。

因为是第一次编译内核模块,而且c语言的水平也是渣渣,所以中间遇到了不少的坑。

写在这里,大家共勉。

实验环境:
uname -a
Linux GSX 3.10.0-514.6.2.el7.x86_64 #1 SMP Thu Feb 23 03:04:39 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux

发行版本:CentOS 7

kthread

源码:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/timer.h>
#include <linux/kthread.h>

MODULE_LICENSE("GPL");

static struct timer_list my_timer;
static struct task_struct *ts;
int id = 101;

static int count = 0;

//标志:如果function()运行结束,kthread也就结束,那么卸载内核模块的时候就不用调用kthread_stop(ts)函数(否则会出现严重错误);反之,需要调用kthread_stop(ts)函数来使kthread终止。
static bool fun_flag = true;

int function(void * data)
{


    int n = *(int*)data;

//注意到这里调用了kthread_should_stop()函数,用来检查终止信号:判断是继续执行还是终止执行
    while(!kthread_should_stop() && count <10 )
    {
        printk(KERN_EMERG "thread_function: %d data\n", n);

        count++;

        set_current_state(TASK_INTERRUPTIBLE);

        schedule_timeout(HZ);

    }

    fun_flag = false;

    return 0;

}



//关键函数一:加载内核模块时调用
int init_module( void ) {

    printk("Timer module installing\n");


    ts = kthread_run(function,(void*)&id , "spawn");   


    return 0;
}

//关键函数二:卸载内核模块时调用
void cleanup_module( void ) {

    if(fun_flag)
    {
        int ret = kthread_stop(ts);  
        printk(KERN_INFO "thread has been stopped . %d", ret );  

    }else{

        printk(KERN_INFO "kthread is already dead.");

    }

    return;
}

编译:

#保存文件为Makefile。。。。注意一定是大写的Makefile,大写的M,M。。。。

obj-m := kthread_module.o


all :
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) modules

clean:
    make -C /lib/modules/$(shell uname -r)/build M=$(shell pwd) clean

由于时间久远,忘了从那位大神博客那里弄来的Makefile文件,抱歉抱歉。。。
这个Makefile文件具有通用性。以后编译内核时,只需要修改开头的目标文件名,就可以了。欢迎收藏!

运行

#加载内核模块
sudo insmod kthread_module.ko   #在上面编译好后,会出现以ko结尾的文件

#查看日志
dmesg

#卸载模块
sudo remmod kthread_module

总结:万事开头难。。第一个作业就写了好久。。。。有了这个经验,后面的作业就很容易上手了哦。。。


workqueue

源码

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/workqueue.h>

MODULE_LICENSE("GPL");

struct workqueue_struct *queue;
//定义workqueue
struct delayed_work *dwork;
int count = 0;

void function(struct work_struct *work)
{
  printk(KERN_INFO "workqueue_function called\n");
  if (count++ < 10) 
    queue_delayed_work(queue, dwork, HZ );
}
//初始化模块时
int init_module( void ) {
//初始化workqueue
 queue = create_workqueue("queue");
 dwork = (struct delayed_work*)kmalloc(sizeof(struct delayed_work), GFP_KERNEL);
 INIT_DELAYED_WORK((struct delayed_work*)dwork, function);

 queue_delayed_work(queue,dwork,HZ);
 return 0;
}
//卸载模块时
void cleanup_module( void ) {

  if (dwork && delayed_work_pending(dwork))
    cancel_delayed_work(dwork);

  flush_workqueue(queue);
  destroy_workqueue(queue);
  printk(KERN_EMERG "workqueue_module has been cleaned up!\n");
  return;
}

编译

同上

运行

同上


系列博客:
相信当你需要其中一个的时候,也一定需要剩下的两个

Linux OS内核 作业一:kthread和workqueue


Linux OS内核 作业二:多线程访问


Linux OS内核 作业三:设备驱动与读写信号量

Logo

更多推荐