您的位置:首页 > 理论基础 > 计算机网络

中断和网络驱动程序

2016-04-27 09:03 525 查看
内核准备处理进入l2层的帧之前,必须先处理精妙而复杂的中断系统,设立中断系统,才可以每秒处理成千的帧。

网络设备与内核通信有两种方式:

轮询:不断读取设备的一个内存寄存器,或当一个定时器到期后检查那个内存寄存器,从而获取设备状态,是否有需要处理的网络数据包。这种方式看起来会比中断浪费很多系统资源,但当中断过于频繁,系统需要不断切换进程上下文时,反而是一种非常好的方式。

中断:当网络数据包到达时,设备驱动程序会代表内核指示设备产生硬件中断。内核将中断其他的活动,然后调用设备驱动程序注册的中断处理例程,让内核来处理数据包。当事件是接收到一个帧时,处理函数就会把该帧排入队列某处,然后通知内核。这种方式在低流量负载下是最佳的选择,但在高流量负载下会让CPU为处理中断事件不断切换环境而浪费时间。

接收数据帧分为两部分工作

首先驱动程序将该数据包复制到内核可访问的输入队列,然后内核再予以处理,通常将该帧传给相关协议专用的处理函数。第一部分是在中断环境中完成的,可以抢占第二部分的执行。接受侦并复制到接收队列的代码优先级高于实际处理帧的代码。处理数据包时可能被新到来的数据帧打断。

下图描述了网络设备接收和发送数据帧的内核处理流程



最简单的中断机制

1.设备产生一个中断事件,硬件通知内核;

2.若内核没有正处理其他中断(或中断没有因其他原因而被关闭),则可以处理该中断;

3.内核首先关闭本地CPU的中断功能,然后执行中断事件的中断服务函数;

4.内核会离开该中断处理函数,然后重启本地CPU的中断功能。



下半部(BH)

简言之,中断处理函数是非抢占的,而且是不可再进入的。这种设计有助于降低竞争情况的可能性,但CPU能做的事情有限,内核做非抢占设计以及等待被CPU服务的进程,就会对性能有严重的影响。因此,中断处理函数所做的工作应该尽快完成。这就引入了中断处理函数的上半部(Top
Half)和下半部(Bottom Half)。上半部就是释放CPU之前必须执行的一切事物,以此保留数据,下半部则包含所有可以从容做完的一切事情。

Linux中断下半部处理有三种方式:软中断、tasklet、工作队列



软IRQ
软中断作为下半部机制的代表,是随着SMP(share memory processor)的出现应运而生的,它也是tasklet实现的基础(tasklet实际上只是在软中断的基础上添加了一定的机制)。软中断一般是“可延迟函数”的总称,有时候也包括了tasklet。它的出现就是因为要满足上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,而且可以在多个CPU上并行执行,使得总的系统效率可以更高。它的特性包括:

产生后并不是马上可以执行,必须要等待内核的调度才能执行。软中断不能被自己打断,只能被硬件中断打断(上半部)。
可以并发运行在多个CPU上(即使同一类型的也可以)。所以软中断必须设计为可重入的函数(允许多个CPU同时操作),因此也需要使用自旋锁来保护其数据结构。



tasklet
由于软中断必须使用可重入函数,这就导致设计上的复杂度变高,作为设备驱动程序的开发者来说,增加了负担。而如果某种应用并不需要在多个CPU上并行执行,那么软中断其实是没有必要的。因此诞生了弥补以上两个要求的tasklet。它具有以下特性:

一种特定类型的tasklet只能运行在一个CPU上,不能并行,只能串行执行。
多个不同类型的tasklet可以并行在多个CPU上。
软中断是静态分配的,在内核编译好之后,就不能改变。但tasklet就灵活许多,可以在运行时改变(比如添加模块时)。

tasklet是在两种软中断类型的基础上实现的,因此如果不需要软中断的并行特性,tasklet就是最好的选择。也就是说tasklet是软中断的一种特殊用法,即延迟情况下的串行执行。



工作队列
从上面的介绍看以看出,软中断运行在中断上下文中,因此不能阻塞和睡眠,而tasklet使用软中断实现,当然也不能阻塞和睡眠。但如果某延迟处理函数需要睡眠或者阻塞呢?没关系工作队列就可以如您所愿了。

工作队列(work queue)是另外一种将工作推后执行的形式。工作队列可以把工作推后,交由一个内核线程去执行--这个下半部分总是会在进程上下文执行,但由于是内核线程,其不能访问用户空间。最重要特点的就是工作队列允许重新调度甚至是睡眠。

通常,在工作队列和软中断/tasklet中作出选择非常容易。可使用以下规则:       

如果推后执行的任务需要睡眠,那么只能选择工作队列;       
如果推后执行的任务需要延时指定的时间再触发,那么使用工作队列,因为其可以利用timer延时(内核定时器实现);    
如果推后执行的任务需要在一个tick之内处理,则使用软中断或tasklet,因为其可以抢占普通进程和内核线程,同时不可睡眠;
如果推后执行的任务对延迟的时间没有任何要求,则使用工作队列,此时通常为无关紧要的任务。

实际上,工作队列的本质就是将工作交给内核线程处理,因此其可以用内核线程替换。但是内核线程的创建和销毁对编程者的要求较高,而工作队列实现了内核线程的封装,不易出错,所以我们也推荐使用工作队列。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: