- 论坛徽章:
- 0
|
1.3.2 网络软中断调用
在分析图1-3中的netisr_register函数前,必须清楚的了解网络软中断调用的原理.网络软中断调用及初始化的代码在netisr.h头文件和netisr.c中.网络软中断共有以下图中15种:
#define NETISR_POLL 0 /* 必须放置到第一位 */ ---netisr.h
#define NETISR_IP 2 /* 在if_ethersubr.c中我们可以看到它,IP分组软中断 */
#define NETISR_ROUTE 14 /* routing socket */
#define NETISR_AARP 15 /* Appletalk ARP */
#define NETISR_ATALK2 16 /* Appletalk phase 2 */
#define NETISR_ATALK1 17 /* Appletalk phase 1 */
#define NETISR_ARP 18 /* 也是在if_ethersubr.c中. */
#define NETISR_IPX 23 /* same as AF_IPX */
#define NETISR_USB 25 /* USB soft interrupt */
#define NETISR_PPP 26 /* PPP soft interrupt */
#define NETISR_IPV6 27#define NETISR_NATM 28
#define NETISR_ATM 29#define NETISR_NETGRAPH 30
#define NETISR_POLLMORE 31 /* 必须放到最后以测试POLL的效率 */ ---netisr.h
图 1-3-2
在讲述POLLING(轮询)软件中断技术之前,对以上软中断号比较熟悉的是NETISR_IP和NETISR_ARP软件中断.因为在我的《通用以太网络驱动程序代码详解》中已经介绍过。我们这里看到NETISR_POLL放在第一位置,NETISR_POLLMORE放在最后的位置.这样安排是为了POLLMORE可以查看POLL运行的结果,是否有剩余的residual_burst(在参数说明中的B.算法参数中).有则再进行POLL,也给中间部分的软中断(如NETISR_IP、NETISR_ROUTE…)有时间执行.
图1-3-2中定义的值是针对一个32位的全局变量netisr的各个bit(位).如下图所示:
netisr
0 1 2 3 4 …………………….. 30 31
NETISR_POLL NETISR_IP NETISR_NETGRAPH NETISR_POLLMORE
在系统初始化其间会加入一核心线程对该变量进行每一bit(位)的判断是否置位.如果置位.则调用位序号对应的netisrs结构数组中的支撑函数.这个过程就是网络的软中断过程. 图 1-3-2-1为网络软中断守护核心线程初始化过程.
static void ---netisr.cstart
_netisr(void *dummy){
if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, INTR_MPSAFE, &net_ih)) panic("start_netisr");}SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL)
图 1-3-2-1
SYSINIT宏使系统在初始时执行start_netisr函数.swi_add函数则把swi_net函数加入到核心线程队列中.net_ih是一intrhand结构指针.函数在成功返回后,net_ih指向的结构包含了中断句柄结构,该结构指针被用于软件中断调用函数swi_sched中.关于swi_add函数和swi_sched函数,本文不准备讨论(在kern_intr.c文件中),因为他们属于核心中断和调度部分了.
swi_net函数的作用是判断全局变量netisr各个位(bit)的置位情况.进而处理相关的输入队列和调用其中断处理函数.
swi_net(void *dummy) ---netisr.c
{ struct netisr *ni; u_int bits; int i;
#ifdef DEVICE_POLLING
const int polling = 1;
#else const int polling = 0;
#endif
do {
bits = atomic_readandclear_int(&netisr);
if (bits == 0)
break;
while ((i = ffs(bits)) != 0) {
isrstat.isrs_swi_count++;
i--;
bits &= ~(1 << i);
ni = &netisrs;
if (ni->ni_handler == NULL) {
printf("swi_net: unregistered isr %d.\n", i); continue;
}
if ((ni->ni_flags & NETISR_MPSAFE) == 0) { mtx_lock(&Giant);
if (ni->ni_queue == NULL) ni->ni_handler(NULL);
else
netisr_processqueue(ni); mtx_unlock(&Giant);
} else {
if (ni->ni_queue == NULL) ni->ni_handler(NULL);
else
netisr_processqueue(ni); }
}
}
while (polling);}
---netisr.c
图 1-3-2-1
图1-3-2-1是整个swi_net函数的代码,它被放入两个while循环当中.最外层的循环是为了轮询而设计的.当polling没有开启时.函数只是执行内层的while循环.该循环是读netisr的每一位(从低位到高位).ffs函数是一库支撑函数.位于:
lib\libc\string\ffs.c中.用来从低位到高位读参数的每一位已经置位的序号放入到变量i中.如:当netisr为二进制的0000,0000,0000,0010时(即NETISR_IP置位),这时ffs(netisr)返回的结果为2.代表是第二位置了位.因为在C语言中,数组的成员都是从0开始.所以要引用netisrs结构数组中的成员,i的值必须减去1.这就是我们看到代码中i - -的原因.语句bits &= ~(1 << i)告诉我们已经处理了此位.在下次循环前我们把此位置换为0才不至于重复处理该位.在得到该位相对应的软中断结构的指针到ni后,先判断该软中断的钩子函数是否存在.当然,不存在的唯一原因是在该软中断发出中断消息后立刻进行了卸载. NETISR_MPSAFE宏代表在下面的代码中不需要使用GAINT锁(即对多CPU也是安全的).
[ 本帖最后由 xie_minix 于 2006-5-3 23:19 编辑 ] |
|