Linux kernel 中的work queue原理
分成两大部分,第一部分是用来执行work queue中每个节点上挂载的函数的内核线程,第二部分是从驱动程序的角度看work queue的使用。
第一部分 worker_thread内核线程
Linux系统启动期间会创建一名为worker_thread线程,该线程创建之后就处于sleep状态。这里所谓的内核线程,从调度器的角度就是一可以调度的进程,从代码的表现形式看,就是一函数。系统创建的这个worker_thread线程基于一workqueue_struct结构变量上(该结构体变量的成员name为"events").
第二部分 work queue的使用
1.只考虑使用系统的keventd管理的工作队列
驱动程序调用schedule_work向工作队列递交新的工作节点,schedule_work内部会唤醒worker_thread内核线程(使之进程状态为可调度)。在下一次进程调度时刻,worker_thread被调度执行,其主要任务便是调用它所管理工作队列中每个工作节点上挂载的函数,调用完毕该工作节点会从任务队列中被删除。当所有节点上的函数调用完毕,worker_thread继续sleep,直到schedule_work再次被某个驱动程序调用。
与使用驱动程序自己创建的工作对列的区别是:schedule_work内部是调用queue_work(keventd_wq, work),而使用驱动程序自己创建的工作队列在调用queue_work时的第一个参数是驱动程序自己创建的工作队列。
2.驱动程序使用自己创建的工作队列
这种情况驱动程序调用create_workqueue。该函数的原理跟1中基本是一样的,只不过再会创建一个内核进程,该内核进程的内核函数名字依然为worker_thread,只不过这个worker_thread工作在新的属于驱动程序自己的工作队列。
使用方法是:
a. 调用create_workqueue生成属于驱动程序自己的work queue. struct workqueue_struct *my_workqueue = create_workqueue("my_workqueue");
b.调用queue_work象a中生成的my_workqueue中注册工作节点, queue_work(my_workqueue, work)
这两种情况下的内核线程其实都是利用了一个名为kthreadd的内核线程来创建工作队列的worker_thread,其本质是向全局列表kthread_create_list中加入相应的内核线程函数节点,由kthreadd来负责创建进程框架,然后运行kthread_create_list中加入的节点上的内核线程函数。
向kthread_create_list中每加入一个内核线程函数节点,都会唤醒kthreadd线程。
当等待队列是空时,worker_thread会睡眠在该等待队列中。当driver调用queue_work时,再向等待队列中加入工作节点的同时,会唤醒睡眠在该等待队列上的worker_thread线程。
更多推荐
所有评论(0)