Linux 内核 线程

来源:互联网 发布:漳州网络安全教育平台 编辑:程序博客网 时间:2024/06/05 00:53

内核线程的概念:

内核线程类似于用户进程,通常用于并发处理些工作,它是一种在内核空间实现后台任务的方式,并且可以参与时间片轮转调度

内核线程可以进行繁忙的异步事件处理,也可以睡眠等待某事件的发生,内核线程可以访问内核函数和数据结构

很多设备驱动程序都是用了内核线程来完成辅助任务,例如:USB设备驱动程序中的khubd内核线程用来监控USB集线器,并在USB被热插拔的时候配置USB设备

内核线程的查看:

用户使用ps命令可以查看系统中正在运行的内核线程(也称内核进程)




内核线程的实现流程:



内核线程的创建及开启:

#include <linux/kthread.h> //内核线程接口函数头文件
struct task_struct *kernel_thread; //定义线程指针
创建内核线程(方法一),返回值为创建线程的指针
struct task_struct *kthread_create(int (*threadfn) \
(void *data),void *data,const char namefmt[], ...);
参数1:线程函数指针,线程开启后将运行此函数
参数2:函数参数data,传递给线程函数
参数3:线程名称,这个函数可以像printk一样传入某种格式的线程名
内核线程创建后不会马上运行,需要通过以下函数启动
int wake_up_process(struct task_struct *p);
创建内核线程函数并运行(方法二)
kthread_run(threadfn, data, namefmt, ...); //宏

内核线程的停止:

停止线程检测函数 (线程函数内使用)
int kthread_should_stop(void)
/*接收到停止信号,返回真.*/
停止内核线程函数 (线程函数外使用)
int kthread_stop(struct task_struct *k);
1.该函数发送信号给内核线程,如果线程函数不检测信号也不返回,那么此函数它将一直进行等待
2.在调用kthread_stop函数时,线程函数不能已经运行结束,否则,kthread_stop函数会一直进行等待。

线程函数的运行:

线程函数,内核线程开启后会运行该函数
int threadfunc(void *data);
1.该函数由用户自己实现,函数格式如上所示
2.该函数必须能让出CPU,以便其他线程能够得到执行,也必须能重新得到调度

实例代码:

#include <linux/module.h>    /*module_init()*/#include <linux/kernel.h>/* printk() */#include <linux/init.h>/* __init __exit */#include <linux/fs.h>/* file_operation */#include <asm/uaccess.h>/* copy_to_user, copy_from_user */#include <linux/device.h>  /*class ,class_create ,device_create 等*/#include <linux/errno.h>/* Error number */#include <linux/delay.h>/* udelay */#include <mach/regs-gpio.h>  #include <linux/types.h>#include <asm/io.h>#include <mach/gpio.h>#include <linux/kthread.h>#define DRIVER_NAME"s5pv210-key15"#define err(msg) printk(KERN_ERR "%s: " msg "\n", DRIVER_NAME)#define __debug(fmt, arg...)printk(KERN_DEBUG fmt, ##arg)#define GPH2CON(unsigned long)(S5PV210_GPH2_BASE+ 0x00)#define GPH2DAT(unsigned long)(S5PV210_GPH2_BASE + 0x04)#define GPH2UP(unsigned long)(S5PV210_GPH2_BASE + 0x08)#define GPH2DRV(unsigned long)(S5PV210_GPH2_BASE+ 0x0C)#define GPH3CON(unsigned long)(S5PV210_GPH3_BASE+ 0x00)#define GPH3DAT(unsigned long)(S5PV210_GPH3_BASE + 0x04)#define GPH3UP(unsigned long)(S5PV210_GPH3_BASE + 0x08)#define GPH3DRV(unsigned long)(S5PV210_GPH3_BASE+ 0x0C)static int major = 0;/* Driver Major Number */static int minor = 0;/* Driver Minor Number */struct class *key15_class;static struct device *key15_device;static wait_queue_head_t wait_queue;static struct task_struct *key_thread;//线程指针static unsigned char key;/*思考:可否将上面全局变量封装为结构体,让代码 * 看起来更规范,请自行改进...... */static int key_conversion(int key_vlaue){int key;switch(key_vlaue){case 0xf0://1111 0000key=2;break;case 0xe8://1110 1000key=3;break;case 0xd8://1101 1000key=9;break;case 0xb8:key=10;break;case 0x78:key=11;break;default:break;}return key;}int keynum_scan(void){int dat_val;int key = -1;dat_val = readl(GPH2DAT);//if there has a key pressedif((dat_val & 0xf8) != 0xf8){msleep(100);if((readl(GPH2DAT) & 0xf8)!=0xf8){key = key_conversion(dat_val);}}return key;}static int key_thread_func(void *data){unsigned char *pkey = (unsigned char *)data;int key;for(;;){//while循环实现线程任务if(kthread_should_stop())break;key = keynum_scan();if(key >= 0){*pkey = key;wake_up_interruptible(&wait_queue);//唤醒等待队列}schedule_timeout(1);   //调度,没执行完就让出cpu一次}return 0;}static ssize_t key15_read(struct file *filp, char *buf, size_t count, loff_t *f_pos){int keynum;int cpy_len;int retval;interruptible_sleep_on(&wait_queue);keynum = key;cpy_len = min(sizeof(keynum), count);retval = copy_to_user(buf, &keynum, cpy_len);return (cpy_len - retval);}/* Driver Operation structure */static struct file_operations key15_fops = {owner:THIS_MODULE,read:key15_read,};static int io_port_init(void){unsigned long reg_val;//GPH3  0  1为输出功能,数据初始化为0reg_val = readl(GPH3CON);reg_val &= ~((0x0f<<0) | (0x0f<<4));reg_val |= ((0x01<<0) | (0x01<<4));writel(reg_val, GPH3CON);reg_val = readl(GPH3DAT);reg_val &= ~((0x01<<0) | (0x01<<1));writel(reg_val, GPH3DAT);//GPH2  3 4 5 6 7  为输入功能,上拉使能,驱动能力为2级reg_val = readl(GPH2CON);reg_val &= ~((0x0f<<12) | (0x0f<<16) | (0x0f<<20) | (0x0f<<24) | (0x0f<<28));writel(reg_val, GPH2CON);reg_val = readl(GPH2UP);reg_val &= ~((0x03<<6) | (0x03<<8) | (0x03<<10) | (0x03<<12) | (0x03<<14));reg_val |= ((0x02<<6) | (0x02<<8) | (0x02<<10) | (0x02<<12) | (0x02<<14));writel(reg_val, GPH2UP);reg_val = readl(GPH2DRV);reg_val &= ~((0x03<<6) | (0x03<<8) | (0x03<<10) | (0x03<<12) | (0x03<<14));reg_val |= ((0x02<<6) | (0x02<<8) | (0x02<<10) | (0x02<<12) | (0x02<<14));writel(reg_val, GPH2DRV);__debug("key15 open called!\n");return 0;}/* Module Init & Exit function */static int __init key15_module_init(void){int retval = 0;/* Module init code */__debug("key15_init\n");io_port_init();init_waitqueue_head(&wait_queue);//初始化等待队列头/*创建内核线程*/key_thread = kthread_create(key_thread_func, &key, "key15_task");if(IS_ERR(key_thread)){err("create kernel thread failed\n");retval = PTR_ERR(key_thread);goto error;}/*运行内核线程*/wake_up_process(key_thread);/* Driver register */major = register_chrdev(major, DRIVER_NAME, &key15_fops);if(major < 0){err("register char device fail!\n");retval = major;goto error;}key15_class=class_create(THIS_MODULE,DRIVER_NAME);if(IS_ERR(key15_class)){err("class create failed!");retval =  PTR_ERR(key15_class);goto error_class;}key15_device=device_create(key15_class,NULL, MKDEV(major, minor), NULL,DRIVER_NAME);if(IS_ERR(key15_device)){err("device create failed!");retval = PTR_ERR(key15_device);goto error_device;}__debug("register myDriver OK! Major = %d\n", major);return 0;error_device:class_destroy(key15_class);error_class:unregister_chrdev(major, DRIVER_NAME);error:return retval;}static void __exit key15_module_exit(void){/* Module exit code */__debug("key15_exit\n");kthread_stop(key_thread);//线程停止函数/* Driver unregister */unregister_chrdev(major, DRIVER_NAME);device_destroy(key15_class,MKDEV(major, minor));class_destroy(key15_class);return;}module_init(key15_module_init);module_exit(key15_module_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("Eric");



原创粉丝点击