Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1727610
  • 博文数量: 782
  • 博客积分: 2455
  • 博客等级: 大尉
  • 技术积分: 4140
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-06 21:37
个人简介

Linux ,c/c++, web,前端,php,js

文章分类

全部博文(782)

文章存档

2015年(8)

2014年(28)

2013年(110)

2012年(307)

2011年(329)

分类: LINUX

2013-05-29 09:12:02

数据包在网络协议栈中所走的路径根据数据包是传输、接收还是转发不同而不同:

image

但虚拟设备可能有所不同,如回环设备不会使用硬件设备的协议栈,而有些虚拟设备可以避免硬件的某些限制如MTU等,因而可以提高性能。

image

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

  1. 轮询:不断读取设备的一个内存寄存器,或当一个定时器到期后检查那个内存寄存器,从而获取设备状态,是否有需要处理的网络数据包。这种方式看起来会比中断浪费很多系统资源,但当中断过于频繁,系统需要不断切换进程上下文时,反而是一种非常好的方式。
  2. 中断:当网络数据包到达时,设备会产生硬件中断调用设备驱动程序注册的中断处理例程,让内核来处理数据包。在低流量负载下是最佳的选择,但在高流量负载下会让CPU为处理中断事件不断切换环境而浪费时间。

接收数据帧分为两部分工作:首先驱动程序将该数据包复制到内核可访问的输入队列,然后内核再予以处理,通常将该帧传给相关协议专用的处理函数。第一部分是在中断中完成的,可以抢占第二部分的执行。接受侦并复制到接收队列的代码优先级高于实际处理帧的代码。处理数据包时可能被新到来的数据帧打断。因此,当流量很大时,实际处理数据包的CPU可能被不断打断去接收数据包,而旧数据包得不到处理,输入队列就会溢出。这种情况就是receive-livelock现象,虽没有死锁,但系统也会崩溃。

       当CPU接收到一个中断通知后,就会调用与该中断事件相关联的处理函数,这种关联性由编号识别。在处理函数执行期间,内核程序就处于中断环境,服务于该中断事件的CPU就会关闭其中断功能,而不能被抢占。无论相同类型还是不同类型的中断事件都不能打断该中断事件。

      中断事件产生的一般流程是:

  1. 设备产生一个中断事件,硬件通知内核;
  2. 若内核没有正处理其他中断,或中断因其他原因而关闭,则可以处理该中断;
  3. 内核首先关闭本地CPU的中断功能,然后执行中断事件的中断服务函数;
  4. 内核会在处理该中断后,重启本地CPU的中断功能。

 

     因此,中断处理函数是非抢占和非可重入的函数,这种设计可以降低竞争的可能性,但对CPU的性能有很大的影响。若处理一个中断的动作中有很多操作可以等待,则可以引入下半部分机制来进行处理。现代中断处理函数分为上半部和下半部两部分,上半部完成在释放CPU前必须执行的操作,以保留数据,而下半部则处理剩余可以慢慢完成的工作。

    实现下半部机制有多种方式,目前常见的是由软中断soft IRQ实现的任务tasklet方式和工作队列两种方式,但工作队列可以休眠,而tasklet是在中断环境中完成的不能休眠。Linux网络系统部分主要采用tasklet方式实现下半部延期操作。

    bottom half、tasklet和softirq在并发性上的区别:

  1. 不管CPU的数目有多少个,任意时刻都只能有一个bottom half在运行;
  2. 每个tasklet在任何时刻只能有一个实例在运行,但不同的tasklet可以在不同的CPU上运行,因此tasklet不需要程序员再进行任何串化限制,内核已经强制了同一个tasklet不能有多个实例同时执行;
  3. 任何时刻,一个CPU中每个softirq只能有一个实例在执行,但像他的softirq可以在不同的CPU上同时执行。因此,程序员必须确保不同的CPU对共享数据的正确访问就需要上锁机制。因此,为了提高并行性,softirq应该设计为尽可能只访问每个CPU的数据,以减少大量使用上锁机制。
阅读(1001) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~