1. athr_gmac_init(void) 模块初始化:(工作队列部分)
1)ATHR_MAC_INIT_WORK(mac, athr_gmac_tx_timeout_task);
此处定义为: #define ATHR_MAC_INIT_WORK(m, f)INIT_WORK(&m->mac_tx_timeout, (void *)f)
工作队列(work queue)是Linux kernel中将工作推后执行的一种机制。这种机制和BH或Tasklets不同之处在于工作队列是把推后的工作交由一个内核线程去执行,因此工作队列的优势就在于它允许重新调度甚至睡眠。
工作队列一般用来做滞后的工作,比如在中断里面要做很多事,但是比较耗时,这时就可以把耗时的工作放到工作队列。说白了就是系统延时调度的一个自定义函数。
1、定义struct work_struct irq_queue;
2、初始化INIT_WORK(&irq_queue,do_irq_queuework);
3、调用方法:schedule_work(&rq_queue);
注,调用完毕后系统会释放此函数,所以如果想再次执行的话,就再次调用schedule_work()即可。
另外,内核必须挂载文件系统才可以使用工作队列。我的理解是:工作队列也属于调度,如果内核挂了,他就不调度了,当然就不能用工作队列了。
下面我们来分析INIT_WORD();
#define INIT_WORK(_work, _func)\
do { \
(_work)->data = (atomic_long_t) WORK_DATA_INIT();\
INIT_LIST_HEAD(&(_work)->entry);\
PREPARE_WORK((_work), (_func));\
} while (0)
其中_work为结构体 work_struct
struct work_struct {
atomic_long_t data;/*传递跟函数的参数*/
#define WORK_STRUCT_PENDING 0/* T if work item pending execution这个工作正在等待处理吗*/
#define WORK_STRUCT_FLAG_MASK (3UL)
#define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK)
struct list_head entry; /*连接所有工作的链表,对工作进行调度,即把给定工作的处理函数提交给缺省的工作队列和工作者线程。工作者线程本质上是一个普通的内核线程,在默认情况下,每个CPU均有一个类型为“events”的工作者线程,当调用schedule_work时,这个工作者线程会被唤醒去执行工作链表上的所有工作。 */
work_func_t func; /*要执行的函数,func的参数是一个work_struct指针,指向的数据就是定义func的work_struct。*/
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
下面回到我们自己的代码,继续分析:
这个函数是工作队列中,我们自己定义的,需要推后执行的函数。
static void
athr_gmac_tx_timeout_task(ATHR_MAC_TASK_ARG)/*func的参数(ATHR_MAC_TASK_ARG)是一个work_struct指针,指向的数据就是定义func的work_struct。*/
{
ATHR_MAC_TASK_MAC(); /*利用container_of 从一个成员,来找到结构体的首地址,也就是mac结构体。 container_of:http://blog.csdn.net/yinkaizhong/article/details/4093795*/
athr_gmac_trc(mac,"mac");
if (mac->ops->check_dma_st)
mac->ops->check_dma_st(mac,0);
}
INIT_WORK的处理函数 athr_gmac_tx_timeout_task(ATHR_MAC_TASK_ARG)是如何取得参数的呢?看下面
#define PREPARE_WORK(_work, _func)\
do { \
(_work)->func = (_func);\
} while (0)
和
#define ATHR_MAC_TASK_MAC() \
athr_gmac_t *mac = (athr_gmac_t *)\
container_of(ws, athr_gmac_t, mac_tx_timeout)
func 的参数为结构体 struct work_struct(),此结构体正是INIT_WORK宏的第一个参数,然后通过调用container_of宏这个小技巧,
通过结构体中一个成员找到结构体的首地址(struct athr_gmac_t),func中所需要用的数据,就存在结构 athr_gmac_t中。