件顺序。
1) 当插口层以级别
s p l 0
执行时,一个以太网设备驱动程序中断发生,使接口层以级别
s p l i m p
执行。这个中断抢占了插口层代码的执行。这就是异步执行接口输入例程。
2) 当以太网设备驱动程序在运行时,它把一个接收的分组放置到 I P输出队列中并调度一
个
s p l n e t
级别的软中断。软中断不会立即有效,因为内核正在一个更高的优先级 (
s p l i m p
)
上运行。
3) 当以太网设备驱动程序完成后,协议层以级别
s p l n e t
执行。这就是异步执行I P输入例程。
4) 一个终端设备中断发生 (完成一个S L I P 分组),它立即被处理,抢占协议层,因为终端
输入/输出(
s p l t t y
)优先级比图1 - 1 3中的协议层(
s p l n e t
)更高。
5) SLIP驱动程序把接收的分组放到 I P输入队列中并为协议层调度另一个软中断。
6) 当S L I P 驱动程序结束时,被抢占的协议层继续以级别 s p l n e t执行,处理完从以太网设备
驱动程序收到的分组后,处理从 S L I P驱动程序接收的分组。仅当没有其他输入分组要处理时,
它会把控制权交还给被它抢占的进程 (在本例中是插口层)。
7) 插口层从它被中断的地方继续执行。
对于这些不同优先级,一个要关心的问题就是如何处理那些在不同级别的进程间共享的
数据结构。在图1 - 2 中显示了三种在不同优先级进程间共享的数据结构
—
插口队列、接口队
列和协议队列。例如,当 I P 输入例程正在从它的输入队列中取出一个接收的分组时,一个设
备中断发生,抢占了协议层,并且那个设备驱动程序可能添加另一个分组到 I P 输入队列。这
些共享的数据结构(本例中的I P 输入队列,它共享于协议层和接口层 ),如果不协调对它们的访
问,可能会破坏数据的完整性。
N e t / 3的代码经常调用函数 s p l i m p 和s p l n e t。这两个调用总是与s p l x成对出现,s p l x
使处理器返回到原来的优先级。例如下面这段代码,被协议层 I P 输入函数执行,去检查是否
有其他分组在它的输入队列中等待处理:
struct mbuf *m;
int s;
s = splimp ();
IF_DEQUEUE (&ipintrq, m);
splx(s);
if (m == 0)
return;
调用s p l i m p 把C P U 的优先级升高到网络设备驱动程序级,防止任何网络设备驱动程序中断发
生。原来的优先级作为函数的返回值存储到变量 s中。然后执行宏I F _ D E Q U E U E 把I P 输入队列
(i p i n t r q )头部的第二个分组删去,并把指向此 m b u f 链表的指针放到变量 m中。最后,通过
调用带有参数 s ( 其保存着前面调用 s p l i m p 的返回值 )的s p l x ,C P U 的优先级恢复到调用
s p l i m p 前的级别。
由于在调用s p l i m p 和s p l x之间所有的网络设备驱动程序的中断被禁止,在这两个调用
间的代码应尽可能的少。如果中断被禁止过长的时间,其他设备会被忽略,数据会被丢失。
因此,对变量m的测试(看是否有其他分组要处理)被放在调用s p l x 之后而不是之前。
当以太网输出例程把一个要输出的分组放到一个接口队列,并测试接口当前是否忙时,
若接口不忙则启动接口,这时例程需要调用这些 s p l调用。
第1章 概 述计计19