http://blog.csdn.net/jin13277480598/article/details/51019762
感谢博主讲的关于为什么需要中断底半部,什么是中断底半部
下半部运行时是允许中断请求的,而上半部运行时是关中断的
头文件:<linux/Workqueue.h>
/**
*工作的数据类型是结构体类型
*/
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
/**
*功能:将_func指向的工作处理函数,赋值给_work结构体中的fun函数指针,即创建工作结构,给工作结构填充一个处理函数。
*_work的类型是 struct work_struct
*_func的类型是函数指针,typedef void (*work_func_t)(struct work_struct *work);
*/
INIT_WORK(_work, _func) 这是个宏定义
在大多数情况下, 并不需要自己建立工作队列,而是只定义工作, 将工作结构挂接到内核预定义的事件工作队列中调度, 在kernel/workqueue.c中定义了一个静态全局量的工作队列static struct workqueue_struct *keventd_wq,keventd_wq由内核自己维护,创建,销毁。这样work马上就会被调度,一旦其所在的处理器上的工作者线程被唤醒,它就会被执行。
/**
*功能:调度工作结构, 将工作结构添加到全局的事件工作队列keventd_wq
*/
bool schedule_work(struct work_struct *work);
static void work_handler(struct work_struct *work) { printk("--%s--%s--&d--\n",__FILE__,__func__,__line__); } struct work_struct wq; INIT_WORK(&wq,work_handler); //这个放到内核模块加载函数中 schedule_work(&wq); //这个放到中断处理函数中去
Tasklet 头文件:<linux/interrupt.h>
struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long); //处理函数
unsigned long data; //给处理函数的参数
};
/**
*功能:定义并初始化一个struct tasklet_struct结构体类型的变量,并绑定中断处理函数(也可以说是底半部函数)
*name:数据类型是struct tasklet_struct
*func函数指针指向一个void (*func)(unsigned long); 的处理函数
*data给处理函数的参数
*/
#define DECLARE_TASKLET(name, func, data) struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } //这是个宏,完成了定义及初始化
/**
*功能:调用自己的中断处理程序
*/
void tasklet_schedule(struct tasklet_struct *t);