深入浅出Linux之内核基础层(2)

linux内核把中断的执行分拆成两部分。和硬件关系紧密,必须关中断执行的操作放在中断上下文中执行,而可以开中断执行的操作则放在软中断上下文执行。 

为此目的,linux内核定义了几个缺省的软中断,网络设备有自己的发送和接收软中断,块设备也有自己的软中断。为了方便使用,内核还定义了一个TASKLET软中断。TASKLET一种特殊的软中断,一个TASKLET只能由一个CPU 执行,同一刻,不同的TASKLET可以在不同的CPU上执行,而同样的TASKLET只能有一个在执行。这个和软中断不同,软中断同一刻可以在不同的CPU并行执行,因此软中断必须考虑重入的问题。

内核中很多地方使用了tasklet。先分析一个例子:

======================================================================

DECLARE_TASKLET_DISABLED(hil_mlcs_tasklet, hil_mlcs_process, 0);

tasklet_schedule(&hil_mlcs_tasklet);

上面的例子首先定义了一个tasklet,它的执行函数是hil_mlcs_process。当程序中调用

tasklet_schedule,会把要执行的结构插入到一个tasklet链表。然后触发一个TASKLET

中断。每个CPU都有自己的tasklet链表,内核会根据情况,确定在何时执行tasklet

可以看到,TASKLET使用起来很简单。本节只需要了解在内核如何使用即可。 

4.工作队列

工作队列和tasklet相似,都是一种延缓执行的机制。不同之处是工作队列有自己的进程上下文,所以工作队列可以睡眠,可以被调度。而tasklet一般要在软中断上下文中执行。

看一个工作队列的例子:

======================================================================

INIT_WORK(&ioc->sas_persist_task,

mptsas_persist_clear_table,

(void *)ioc);

schedule_work(&ioc->sas_persist_task);

使用工作队列很简单,schedule_work就把用户定义的work_struct加入系统的队列中,并唤醒系统线程去执行。那么是那一个系统线程执行用户的work_struct?实际上,内核初始化的时候,就要创建一个工作队列keventd_wq,同时为这个工作队列创建系统线程(缺省是为每个CPU创建一个系统线程)。 

内核同时还提供了create_workqueuecreate_singlethread_workqueue函数,这样用户可以创建自己的工作队列和执行线程,而不用内核提供的工作队列。看内核的例子:

======================================================================

kblockd_workqueue = create_workqueue("kblockd");

int kblockd_schedule_work(struct work_struct *work)

{

return queue_work(kblockd_workqueue, work);

}

kblockd_workqueue是内核通用块层提供的工作队列,需要由kblockd_workqueue执行的工作,就要调用kblockd_schedule_work,其实就是调用queue_work把work加入到kblockd_workqueued工作队列的任务链表。 

create_singlethread_workqueuecreate_workqueue类似,不同之处像名字揭示的一样,create_singlethread_workqueue只创建一个内核线程,而不是为每个CPU创建一个内核线程。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/22851.html