workqueue是除了softirq和tasklet之外最常用的下半部分机制之一。workqueue的本质是将工作交给一个内核线程,在进程上下文调度的时候执行。由于这个特性,workqueue允许重新调度和休眠。这种异步执行进程上下文可以解决softirq和tasklet执行时间过长导致的系统实时性能下降的问题。当驱动程序有在进程上下文中异步执行的工作任务时,可以使用Work来描述工作任务。将工作添加到一个链表worklist中,然后一个内核线程worker遍历链表,串行执行挂在worklist中的所有工作。如果worklist中没有工作,内核线程worker会变为IDLE;如果有工作,则执行工作中的回调函数。workqueue相关的数据结构workqueue中的几个概念都是和work相关的。数据结构非常混乱。可以这样理解:work_struct:工作。一个工作被初始化并加入工作队列后,会被传递给合适的内核线程进行处理,这是进行调度的最小单位。structwork_struct{atomic_long_tdata;structlist_headentry;work_func_tfunc;#ifdefCONFIG_LOCKDEPstructlockdep_maplockdep_map;#endif};data:低位存储状态位,高位存储worker_poolID或pool_workqueue指针entry:用于添加到其他队列中func:工作任务的处理函数,在内核线程中回调workqueue_struct:工作的集合。workqueue和work是一对多的关系。内核中有两种类型的工作队列:bound:绑定处理器的工作队列,每个worker创建的内核线程绑定在特定的CPU上运行。未绑定:未绑定到处理器的工作队列。创建时需要指定WQ_UNBOUND标志,内核线程可以在处理器之间迁移。structworkqueue_struct{structlist_headpwqs;/*WR:allpwqsofthiswq*/structlist_headlist;/*PR:listofallworkqueues*/structlist_headmaydays;/*MD:pwqsrequestingrescue*/structworker*rescuer;/*I:rescueworker*/structpool_workqueon*q*Punlybound;dfl_pw:/charname[WQ_NAME_LEN];/*I:workqueuename*//*hotfieldsusedduringcommandissue,alignedtocacheline*/unsignedintflags____cacheline_aligned;/*WQ:WQ_*flags*/structpool_workqueue__percpu*cpu_pwqs;/*I:per-cpupwqs*q*q*workqueue_pbl__r/*PWR:unboundpwqsindexedbynode*///每个节点创建pool_workqueue...};pwqs:allpool_workqueuesareaddedtothislinkedlistlist:用于将工作队列加入到全局链表workqueuesmaydays:pool_workqueueinrescuestate添加到该链表rescue:rescicerkernelthread,用于处理工作线程创建失败内存紧张时cpu_pwqs:Per-CPUcreatepool_workqueuenuma_pwq_tbl[]:Per-Nodecreatepool_workqueue之间的关系。workqueue和pool_workqueue是一对多的关系。structpool_workqueue{structworker_pool*pool;/*I:theassociatedpool*/structworkqueue_struct*wq;/*I:theowningworkqueue*/intnr_active;/*L:nrofactiveworks*/intmax_active;/*L:maxactiveworks*/structlist_headdelayed_works;/*L:delayedworks*/structlist_headpwqs_node;/*WR:nodeonwq->pwqs*/structlist_headmayday_node;/*MD:nodeonwq->maydays*///用于添加到工作队列列表...}__aligned(1<
