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);