Chinaunix

标题: 软中断是如何实现的? [打印本页]

作者: ocean390    时间: 2006-05-03 20:27
标题: 软中断是如何实现的?
看过不少书上面都讲到软中断,一直搞不清到底什么是软中断,还有就是和AST(asynchronous system trap),DPC(deferred procedure call),APC(asynchronous procdure call)的关系,后面两个是这
这几天看widows internals看到的,
哪位老大能解释一下啊!
作者: 雨丝风片    时间: 2006-05-03 20:42
原帖由 ocean390 于 2006-5-3 20:27 发表
看过不少书上面都讲到软中断,一直搞不清到底什么是软中断,还有就是和AST(asynchronous system trap),DPC(deferred procedure call),APC(asynchronous procdure call)的关系,后面两个是这
这几天看widows inte ...


这些区别可以借助研究中断和系统调用过程的实现来理解,放假期间不便查资料,难免言论有误,等上班后再详细讨论一下!
作者: gvim    时间: 2006-05-03 20:51
相对于软中断的是硬中断。这个概念很清晰,硬件在完成操作之后,向处理器中断控制芯片引脚发出的一个跳变电平。
软中断,顾名思义就是以软件方式产生的中断。一般以int指令提供。除此之外,我们常见的/0错误,换页异常,处理器权限错误等,都会导致软件异常/中断的产生。BSD采用的是int 80中断。dos没有记错的话好像是int 21

异步的意思是“你只能说明当xxx发生时,系统可以执行什么操作;而你却不能预测xxx的发生。”
至于AST,DPC,APC,在BSD里面我暂时只遇到AST,我的理解,Intel将软件中断分成中断和异常两种类型,他们都是提供的异步机制。AST的概念应该和异步系统中断差不多。
作者: gvim    时间: 2006-05-03 20:53
原帖由 雨丝风片 于 2006-5-3 20:42 发表


这些区别可以借助研究中断和系统调用过程的实现来理解,放假期间不便查资料,难免言论有误,等上班后再详细讨论一下!


LZ,现在版主大哥的脑子里在盘算明天怎么去看mm
作者: ocean390    时间: 2006-05-03 21:11
刚才用百度搜索了一下,发现了不少讲软中断的文章,发现在搜索中文方面,百度还是要比google强不少。
不过搜索到的都是关于Linux方面的。上面讲到的软中断的意思就是相当于一般上讲的Linux中的中断的bottom down的处理,BSD中有中断线程的方法,是不是就不再需要软中断的方法了。在TCP/IP详解的卷二
接口:以太网 中讲到当网卡收到一个数据包之后,如果是一个IP分组就调度一个ip软件中断,如果是一个ARP分组就调度一个arp软件中断。我的意思就是这样的软中断是什么意思,是怎么实现的。
DPC,APC我也说了是在Windows internals上面看到的,BSD中没有这样的说法。
作者: gvim    时间: 2006-05-03 21:19
原帖由 ocean390 于 2006-5-3 21:11 发表
不过搜索到的都是关于Linux方面的。上面讲到的软中断的意思就是相当于一般上讲的Linux中的中断的bottom down的处理,BSD中有中断线程的方法,是不是就不再需要软中断的方法了。在TCP/IP详解的卷二
接口:以太网 中讲到当网卡收到一个数据包之后,如果是一个IP分组就调度一个ip软件中断,如果是一个ARP分组就调度一个arp软件中断。我的意思就是这样的软中断是什么意思,是怎么实现的。

Linux我脑子里现在没有什么映像。
BSD的中断线程??我只知道中断上下文。

软中断,我不知道你说的实现是指什么。
软中断是一种机制,是处理器提供的,0-31是保留给intel的,32-255是可以给用户的,硬件怎么实现,那需要找处理器的资料了。
你要是问软中断是怎么安装的,在置顶的<程序开发资料汇总>里面有相关联接。
作者: ocean390    时间: 2006-05-03 21:34
我想一般书中讲的调度一个软中断不会是通过一个int指令实现的吧,这样的指令有什么意义呢?intel把通过int指令产生的中断或者执行过程中产生的异常如被0除称为软中断,这个不是太清楚。已经很长时间没看intel 的手册了。
我个人感觉如tcp/ip这本书中讲的软中断,应该和windows下的deferred procedure call差不多吧。
老大不会还没听说过BSD中的中断线程吧!
作者: gvim    时间: 2006-05-03 21:58
原帖由 ocean390 于 2006-5-3 21:34 发表
我想一般书中讲的调度一个软中断不会是通过一个int指令实现的吧,这样的指令有什么意义呢?intel把通过int指令产生的中断或者执行过程中产生的异常如被0除称为软中断,这个不是太清楚。已经很长时间没看intel 的手 ...

我不是很清楚你说的tcp/ip这本书中讲的"软中断"。不过,按照术语来说,"软中断"是一个标准的名称,这个名称不太可能由int指令和其他什么东西共享。
中断线程,恩,我理解错了你的意思。不过"BSD中有中断线程的方法,是不是就不再需要软中断的方法了"是错误的。中断上下文的出现是为了提供一个细粒度的中断处理周期,这样做的好处在于SMP和RealTime. 它其实还是中断,也就是说系统可以没有中断线程,但是不能没有(硬、软)中断。两者不是如你理解的那样独立的关系。
作者: gvim    时间: 2006-05-03 22:25
原帖由 ocean390 于 2006-5-3 20:27 发表
看过不少书上面都讲到软中断,一直搞不清到底什么是软中断,还有就是和AST(asynchronous system trap),DPC(deferred procedure call),APC(asynchronous procdure call)的关系,后面两个是这
这几天看widows inte ...


你可以看看freebsd设计与实现一书的3.3节。
作者: ocean390    时间: 2006-05-03 22:26
应该是”软件中断“吧,不过网上关于Linux的分析都是叫做”软中断“,我感觉两者应该是相同的意思,就一直叫”软中断“了,在
http://www.freebsdchina.org/forum/topic_11120.html
FreeBSD 5 内核源代码分析之中断处理,这片文章中也提到了软件中断,不过介绍的不是很详细,没有讲软件中断是怎么被调度的。
作者: gvim    时间: 2006-05-03 22:35
"没有讲软件中断是怎么被调度的。 "

引入中断上下文之后也就是中断线程,调度与一般线程调度无异。不过它们的优先级比普通线程优先级高罢了。
具体实现可以参考freebsd设计与实现的4.3和4.4两节
作者: ocean390    时间: 2006-05-03 22:40
有点明白了
作者: xie_minix    时间: 2006-05-03 22:42
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 编辑 ]
作者: xie_minix    时间: 2006-05-03 22:44
???
怎么发出来的东西都变了?格式什么的都没了?
另外:
int 80是核心外(用户区)的软中断,和核心内的不一样.
核心内是一轻量级的线程序.freebsd通过
schednetisr
schednetisrbits
来调度,是个非常简单的例程
netbsd的软中断有点不一样,可以比较下看看,
kern_kcont.c和/sys/arch/x86/x86下的文件建议看看,都在那了.

[ 本帖最后由 xie_minix 于 2006-5-3 22:52 编辑 ]
作者: 雨丝风片    时间: 2006-05-03 22:46
原帖由 xie_minix 于 2006-5-3 22:44 发表
???
怎么发出来的东西都变了?格式什么的都没了?


老大用【code】功能编译一下?
作者: gvim    时间: 2006-05-03 22:46
原帖由 xie_minix 于 2006-5-3 22:42 发表
1.3.2 网络软中断调用
        在分析图1-3中的netisr_register函数前,必须清楚的了解网络软中断调用的原理.网络软中断调用及初始化的代码在netisr.h头文件和netisr.c中.网络软中断共有以下图中15种:

#define        NETISR ...


报告,发现大牛牛xie_minix出现
作者: ocean390    时间: 2006-05-03 22:49
在没有引入中断线程时,系统时如何处理的呢?
作者: gvim    时间: 2006-05-03 22:53
原帖由 ocean390 于 2006-5-3 22:49 发表
在没有引入中断线程时,系统时如何处理的呢?


在当前进程的上下文中处理。这部分也就是传统的组成原理中中断处理部分的内容。
我觉得除了去考试之外,对于这种上个世纪7,80年代的"过时"的东西,没有必要深究下去。
作者: xie_minix    时间: 2006-05-03 22:53
我是在word下写的.哈哈
最近一直在分析NETBSD和FREEBSD的软件中断对
轮询技术性能的影响.嗯,应该是有问题的.
我们可以看看,在一个稍大一点的局域网内,由于ARP
和其他链路层广播的增加.对软中断驱动的POLLING
来说会有影响.到底会影响到什么程度,或构建一些特殊
的有规律的包是否会对POLLING造成攻击还不清楚.

[ 本帖最后由 xie_minix 于 2006-5-3 22:59 编辑 ]
作者: xie_minix    时间: 2006-05-03 23:02
这是freebsd的i386
/*
* 中断优先级别.
* 因为在tty,network,disk驱动中要使用free,所以imp优先权是要大于tty,net,bio的.
* 又因为运行队列可以在时钟中断态下操作,所以时钟又大于imp
*
* IPL_HIGH中断因其可以操作运行队列,所以也必须阻塞其他操作.
* 设备驱动程序连续性处理在最高优先权,所以连续性大于IP_HIGH
*
* 注意:各结构体系对此定义不同,可以参照HP300,HP700,POWERPC等体系看看
*/
#define        IPL_NONE        0x0        /* nothing */
#define        IPL_SOFTCLOCK        0x4        /* timeouts软件定时器看样子是最低的 */
#define        IPL_SOFTNET        0x5        /* 网络软件中断(这里是指由if_ethersubr中发出的ARP,IP,IPX各协议相关的软件中断) */
#define        IPL_BIO                0x6        /* 块设备 I/O */
#define        IPL_NET                0x7        /* 一般在网卡驱动程序的attach部分用pci_intr_establish建立硬件中断*/
                                                /*他调用pci_mathdep.c的intr_establish*/
#define        IPL_SOFTSERIAL        0x8        /* 好象是为了保持软中断的延续性的一中断*/
#define        IPL_TTY                0x9        /* 控制台*/
#define        IPL_VM                0xa        /* 内存分配 */
#define        IPL_AUDIO        0xb        /* 声音 */
#define        IPL_CLOCK        0xc        /* 时钟 */
#define IPL_SCHED        IPL_CLOCK  /*调度中断和时钟是同一级别*/
#define        IPL_HIGH        0xd        /* 该中断可屏蔽掉上面那些中断 */
#define        IPL_SERIAL        0xd        /* 应该是保持所要保护的其他中断延续性的最高级别 */
#define IPL_IPI                0xe        /* 处理器间中断,多CPU时用 */
#define        NIPL                16
作者: xie_minix    时间: 2006-05-03 23:07
这是freebsd优先权问题没检查自己是否为胡说八道,大家只做为一参考吧)
*
* 优先权范围从 0 到 255,两线程优先权在值小于4的时候没什么影响
*
* 中断线程:                0 - 63
* 顶半核心线程:        64 - 127
* 实时用户区线程:        128 - 159
* 分时的用户区线程序:        160 - 223
* 空闲的线程:                224 - 255
*
* 还未实现的:如果中断和顶半部线程的范围合并??? 那就使用户区进程能有更大范围
*/

#define        PRI_MIN                        (0)                /* 最高优先权. */
#define        PRI_MAX                        (255)                /* 最低优先权. */

#define        PRI_MIN_ITHD                (PRI_MIN) /*这是中断线程优先权开始值*/
#define        PRI_MAX_ITHD                (PRI_MIN_KERN - 1)/*这是中断线程优先权结束值(PRI_MIN_KERN是64)*/

#define        PI_REALTIME                (PRI_MIN_ITHD + 0)/*实时中断优先权最高*/
#define        PI_AV                        (PRI_MIN_ITHD + 4)/*音频,视频中断排第二位(干嘛叫AV???)*/
#define        PI_TTYHIGH                (PRI_MIN_ITHD + /*高优先权的控制台线程*/
#define        PI_TAPE                        (PRI_MIN_ITHD + 12)/*ATAPI中断*/
#define        PI_NET                        (PRI_MIN_ITHD + 16)/*网络中断*/
#define        PI_DISK                        (PRI_MIN_ITHD + 20)/*磁盘中断*/
#define        PI_TTYLOW                (PRI_MIN_ITHD + 24)/*低优先权的控制台线程*/
#define        PI_DISKLOW                (PRI_MIN_ITHD + 2/*低速度磁盘中断*/
#define        PI_DULL                        (PRI_MIN_ITHD + 32)/*什么东西*/
#define        PI_SOFT                        (PRI_MIN_ITHD + 36)/*软件中断.如POLLING,IP软中断,由swi_add函数使用*/

#define        PRI_MIN_KERN                (64)
#define        PRI_MAX_KERN                (PRI_MIN_REALTIME - 1)

#define        PSWP                        (PRI_MIN_KERN + 0)  /*内存交换进程使用*/
#define        PVM                        (PRI_MIN_KERN + 4)      /*内存页的换入换出*/
#define        PINOD                        (PRI_MIN_KERN +   /*文件系统使用*/
#define        PRIBIO                        (PRI_MIN_KERN + 12) /*磁盘等存储使用*/
#define        PVFS                        (PRI_MIN_KERN + 16) /*虚拟文件系统*/
#define        PZERO                        (PRI_MIN_KERN + 20) /*使用的此优先权的进程(或设备)太多,说不清.可能比较中性的*/
#define        PSOCK                        (PRI_MIN_KERN + 24) /*使用套接字的一些进程,NFS,RPC等等*/
#define        PWAIT                        (PRI_MIN_KERN + 2 /*真不知道了*/
#define        PCONFIG                        (PRI_MIN_KERN + 32) /*AUTOCONF使用的*/
#define        PLOCK                        (PRI_MIN_KERN + 36) /*文件锁使用*/
#define        PPAUSE                        (PRI_MIN_KERN + 40)
作者: gvim    时间: 2006-05-03 23:20
continuration-passing 看起来很难的样子
http://www.blogjava.net/canonical/archive/2005/12/12/23406.html
http://tech.ccidnet.com/art/1077/20050722/292705_1.html

另外,请教一下老大kc是什么的缩写?

[ 本帖最后由 gvim 于 2006-5-3 23:28 编辑 ]
作者: xie_minix    时间: 2006-05-03 23:31
/* 这是他说的
* kcont -- Continuation-passing for BSD kernels.
*
* This module defines structures that implement a
* continuation-passing model in C which can be used as a
* ``callback''-like alternative to using a process context to
* tsleep() on an object address, waiting for some event or status
* change on that object.  Since ANSI C provides neither
* lexically-nested functions nor heap allocation of activation
* records, we implement a continuation as a struct containing:
* 1. A function pointer, pointing to the continuation.
* 2. A object pointer: the object being "slept" upon.
* 3. An argument pointer: a pointer to private storage containing
*    other arguments to the continuation function, including any
*    additional state beyond the "slept-upon" object.
*/
作者: ocean390    时间: 2006-05-03 23:34
没有中断线程前,中断当然是在当前的进程或者线程中处理的。这个我也清楚。
我想问的是在没有中断线程前,是如何处理软件中断的。
作者: gvim    时间: 2006-05-03 23:35
k(ern)c(ontinuation)?这个缩写也缩的有点多哦
恩,看了看Continuation,确实对我来说比较新鲜。多谢老大指点
作者: xie_minix    时间: 2006-05-04 00:20
原帖由 ocean390 于 2006-5-3 23:34 发表
没有中断线程前,中断当然是在当前的进程或者线程中处理的。这个我也清楚。
我想问的是在没有中断线程前,是如何处理软件中断的。

嗯,在中断线程的守护线程建立前,首先用户区是不会发出软件中断的.
而且守护线程在系统初始化时就建立(使用SYSINIT,比如NET的建立过程)
SYSINIT(start_netisr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_netisr, NULL)
就通过SYSINIT建立swi_net守护线程.
整个过程是:
SYSINIT->start_netisr->调用swi_add加入net_net到核心中断线程队列->
swi_add | ->ithread_create建立->kthread_create一守护线程ithread_loop
            | ->ithread_add_handler加入建立后的线程到中断线程队列.
代码涉及的文件到是不多,但涵盖了软件中断和硬件中断的一些原理.

[ 本帖最后由 xie_minix 于 2006-5-4 00:21 编辑 ]
作者: ocean390    时间: 2006-05-04 01:28
我想问一下在FreeBSD以前的没有使用中断线程这个方法的版本中,是如何处理软件中断的。我的理解软件中断就是把中断处理中不太紧急的进行延期处理,不知道对不对?
作者: xie_minix    时间: 2006-05-04 09:30
首先,我没看过这种版本.也许是很老的版本.
估计虽然没有轻量级线程,但从进程的角度
来看,应该是一样的.软件中断本身就是下一
轮执行(还要看优先权排第几),我从没考虑过
用户区的陷入(比如int 80)的情况,主要是从
核心内的软中断调用实现来考虑,不知道我讲
清楚了没有.
比如在网络驱动程序(通用部分)处理包的情况
也是如此,比如接收到ARP包,在schednetisr
函数设置运行队列后,整个驱动程序运行结束
调度程序接管,进行调度作业.
作者: mingyanguo    时间: 2006-05-04 13:48
看一下中断返回的代码就比较清楚了。

  1. 281 doreti_ast:
  2. 282         /*
  3. 283          * Check for ASTs atomically with returning.  Disabling CPU
  4. 284          * interrupts provides sufficient locking even in the SMP case,
  5. 285          * since we will be informed of any new ASTs by an IPI.
  6. 286          */
  7. 287         cli
  8. 288         movl    PCPU(CURTHREAD),%eax
  9. 289         testl   $TDF_ASTPENDING | TDF_NEEDRESCHED,TD_FLAGS(%eax)
  10. 290         je      doreti_exit
  11. 291         sti
  12. 292         pushl   %esp                    /* pass a pointer to the trapframe */
  13. 293         call    ast
  14. 294         add     $4,%esp
  15. 295         jmp     doreti_ast
复制代码

其实就是异常/中断返回的时候检查一下标志位。
作者: zhuzj    时间: 2006-05-04 15:40
软中断是一种推后执行的机制,定时器,网卡的数据的处理是很典型的软中断,这个和中断向量表里的中断是完全不一样的,以网络数据的处理为例,当网卡接到一个数据包后,其中断处理程序只是把数据复制到缓冲区,然后就告诉网卡,你可以再传数据给我了,也就是中断返回,但在此之前,网卡的中断处理程序要置一个标志位,告诉操作系统有事要做,这个事就是软中断,但软中断只是很多中断返回时要做的事情之一,操作系统每次中断返回时会检查着个标志位,看是否有事要做,如果有,就会去处理,象前面提到的网卡,这时候操作系统就回调用软中断的处理函数,网卡的软中断程序就是做分析数据包啊,这个数据应该传给谁啊等这些工作.没有,就返回了,除了必须的部分,中断处理程序都是在开中断的情况下运行的.linux-2.6.12的kernel/目录下有一个文件叫softirq.c就是软中断的实现,里面有个函数叫do_softirq();他好象是在do_IRQ中被调用的(在irq_exit()中),netbsd的现在还没看懂,所以说不好

[ 本帖最后由 zhuzj 于 2006-5-4 15:47 编辑 ]
作者: zhengwei_zw    时间: 2006-05-06 21:38
www.baidu.com在中文方面确实比www.google.com要强!但baidu把关键性词语处理过的~比如比较敏感的字眼~
作者: 雨丝风片    时间: 2006-05-08 11:06
原帖由 ocean390 于 2006-5-4 01:28 发表
我想问一下在FreeBSD以前的没有使用中断线程这个方法的版本中,是如何处理软件中断的。


对比一下两本书的同一段落,不知道能不能解答你的疑问?

【4.4BSD操作系统设计与实现】:
实现低优先级处理的机制被称作软件中断。一般来说,都是由一个高优先级的中断创建一个将在低优先级中完成的工作队列。在把工作请求放到队列中之后,高优先级的中断会把这些请求安排在某个低优先级中运行。当机器的优先级低于那个低优先级之后,就会产生一个中断来调用所需的函数。如果在处理请求期间又来了一个高优先级的中断,处理过程就会像任何其它的低优先级任务一样被抢占。在某些架构上,前述中断就是由软件指令产生的真实的硬件陷阱。而其它的一些架构则通过在恰当的时候监视由中断处理程序设置的标志并直接调用请求处理函数的方式来实现同样的功能。


【FreeBSD操作系统设计与实现】:
实现低优先级处理的机制被称作软件中断。一般来说,都是由一个高优先级的中断创建一个将在低优先级中完成的工作队列。和FreeBSD5.2中的硬件设备一样,每个软件中断都有一个与之相关联的进程上下文。软件中断进程的调度优先级一般比设备驱动程序进程低,但却比用户进程的优先级高。只要有硬件中断到达,和设备驱动程序关联的进程就会获得最高优先级,并被调度运行。如果没有设备驱动程序进程处于可运行状态,优先级最高的软件中断进程就会被调度运行。如果没有软件中断进程处于可运行状态,就会运行优先级最高的用户进程。如果在一个软件中断进程或者用户进程正在运行的时候来了一个中断并使其设备驱动程序进程处于可运行状态,调度程序将会抢占软件中断或用户进程来运行设备驱动程序进程。
作者: gvim    时间: 2006-05-08 11:15
为什么要用这个词"软中断"?namespace很冲突阿。
我那天翻了翻书,才知道LZ想要的答案是这个软中断,不是int
作者: 雨丝风片    时间: 2006-05-08 11:23
原帖由 gvim 于 2006-5-8 11:15 发表
为什么要用这个词"软中断"?namespace很冲突阿。
我那天翻了翻书,才知道LZ想要的答案是这个软中断,不是int


把int叫做软件中断应该是DOS的流毒,UNIX这边还没看到过这种说法。BSD的“软件中断”应该是Linux的“软中断”是一个意思,这里的“软”都应当做“软性”解,即时间要求上的软性。
作者: 雨丝风片    时间: 2006-05-08 11:28
原帖由 雨丝风片 于 2006-5-8 11:23 发表


把int叫做软件中断应该是DOS的流毒,UNIX这边还没看到过这种说法。BSD的“软件中断”应该是Linux的“软中断”是一个意思,这里的“软”都应当做“软性”解,即时间要求上的软性。


我错了,Intel的手册里就是把int叫软件中断的。看来得根据上下文来区分,是CPU还是内核。
作者: gvim    时间: 2006-05-08 11:33
原帖由 雨丝风片 于 2006-5-8 11:23 发表


把int叫做软件中断应该是DOS的流毒,UNIX这边还没看到过这种说法。BSD的“软件中断”应该是Linux的“软中断”是一个意思,这里的“软”都应当做“软性”解,即时间要求上的软性。


我查了查intel的book,确实,他自己也是称的"software-generated interrupts/exceptions",这两个名称感觉很重复的类似。

出qiu了,qiu大了
作者: 雨丝风片    时间: 2006-05-08 11:44
原帖由 gvim 于 2006-5-8 11:33 发表


我查了查intel的book,确实,他自己也是称的"software-generated interrupts/exceptions",这两个名称感觉很重复的类似。

出qiu了,qiu大了


名不正,言不顺。
作者: ocean390    时间: 2006-05-08 18:29
原帖由 gvim 于 2006-5-8 11:33 发表


我查了查intel的book,确实,他自己也是称的"software-generated interrupts/exceptions",这两个名称感觉很重复的类似。

出qiu了,qiu大了

当时我一再重复和Linux中的软中断的关系,老大却一直在说int指令,搞的当时我也很郁闷。
哎,不知怎么搞的,现在用的最多的一个词,竟然是“郁闷”,没来南京上学前,从来就没听过这个词。
作者: gvim    时间: 2006-05-08 18:41
原帖由 ocean390 于 2006-5-8 18:29 发表

当时我一再重复和Linux中的软中断的关系,老大却一直在说int指令,搞的当时我也很郁闷。
哎,不知怎么搞的,现在用的最多的一个词,竟然是“郁闷”,没来南京上学前,从来就没听过这个词。


呵,我以前是搞硬件的,所以对"软中断"的第一反映就是int,偶也一时半会没有反映过来,等回过神来时已经出qiu了
很抱歉把你搞郁闷,被我搞恶的人一般选择疯掉
作者: 雨丝风片    时间: 2006-05-08 19:16
原帖由 gvim 于 2006-5-8 18:41 发表
被我搞恶的人一般选择疯掉


罚你明天贴一份“自杀报告+述职报告+怀念书店mm”出来。
作者: sinister    时间: 2006-12-19 19:43
标题: 不知这个问题是否还在讨论?
下面是一些我个人理解。

在非中断线程化的 OS 中,如果把响应中断的所有工作都在 ISR 中完成,系统
是无法忍受的,我们要做的是在 ISR 中尽量的减少代码,只做一些必要性的工作,
如 in / out 操作,把一些其他不必要在 ISR 中工作放到其他地方,比如数据的
处理,这也就是软中断目的所在。其实即使在中断线程化的 OS 当中(如:SOLARIS)
也一样有软中断,但这里的软中断含义和那种推迟调度不是一个概念了。以下仅针
对此帖题目举例说明硬件中断如何触发软中断,关于如何注册软中断和注册步骤就不
说了。这里所说的软中断是与题目相关的。


在 NT KERNEL 中把软件运行环境又分为三个软件中断 IRQL 等级,DISPATCH_LEVEL
(DPC_LEVEL),APC_LEVEL,PASSVIE_LEVEL。系统提供的 DPC 是为了处理硬件中断
后续工作提供的一种机制,DPC 与 Linux Kernel 提供的基于 tasklet 实现的 Bottom
Half 作用上有些相似,但又不一样。在使用 DPC 处理硬件中断后续的工作前,需显示
调用相关的 kernel api 注册 DPC。关于硬件中断如何触发 DPC 调用,可以看
HalEndSystemInterrupt() 这个函数,在这个函数中,首先确定没有其他嵌套硬件
中断后(没有高于 DPC_LEVEL 的 IRQL),把 IRQL 降低,并判断是否有 DPC 调用
(之前使用 IoRequestDpc() 向系统注册的 DPC 回调函数,当把 DPC 回调函数插入
DPC LIST 后,系统调用 HalRequestSoftwareInterrupt() 设置当前 IRQL 为
DPC_LEVEL,如果当前有硬件级的 IRQL 高于 DPC_LEVEL 则 pending DPC),
如果有则设置 IRQL 为 DPC_LEVEL 并调用 KiDispatchInterrupt() 处理之前注册
的 DPC 回调函数。KiDispatchInterrupt() 函数本身是在 IRQL == DPC_LEVEL 上
运行的,它同样是处理线程调度的主函数。也就是说 DPC 调用点不光是在所有硬件
ISR 处理完成后调用 DPC。还有是处理任务调度时也会判断是否需要执行 DPC。这
里注意,DPC 与 DPC_LEVEL 不是一回事,DPC 回调函数运行级别在 DPC_LEVEL,
但并不是说所有 DPC_LEVEL 级别都是要运行 DPC 回调函数的。在非 SMP 环境下
spinlock 的实现就是简单的提升当前 IRQL 为 DPC_LEVEL,因为在这个级别的
IRQL 下所有其他软件级别运行的代码都将被阻塞,所以说线程调度主函数运行在这个
级别是不会被任何线程抢占的,另 DPC_LEVEL 虽然不是中断上下文,但在这个级别
下,任何引起睡眠的机制都将导致系统崩溃。扯的有点远了。再简单说下 APC(
Asynchronous Procedure Call),故名思意,既然是“异步过程调用”那么当前执
行环境很可能是任意线程上下文。其实到了 APC 这里就跟硬件中断扯不上边了,
虽然是这样系统还是把 APC 实现也定位为一种软中断,APC 运行在 APC_LEVEL 级
别(同样系统调用 HalRequestSoftwareInterrupt() 函数设置当前IRQL 为
APC_LEVEL)。关于如何触发 APC 可以去看一些读/写函数,当一个读/写函数设置了
异步标志时,有几种情况(因为是异步的),首先说一下触发条件,条件是:“系
统处理的当前线程是调用者线程且 IRQL 小于 APC_LEVEL 时从当前线程 APC 队列里
取出 APC 回调函数并把 IRQL 提升到 APC_LEVEL 进行调用”。继续看这几种情况,
如果系统当前处理线程不是调用者者线程,则清除 APC_LEVEL 标志,并将此 APC(
回调函数)插入调用者线程的 APC 列然后返回。如果系统当前处理线程正是调用者
线程,那么判断当前 IRQL 是否高于 APC_LEVEL,如果高于则插入调用者线程 APC
队列,此次 APC 中断被记录并返回。如果系统当前处理线程是调用者线程且 IRQL
小于 APC_LEVEL 则满足调用条件,APC 回调函数立刻被调用。处理 APC 的调用点
是在 syscall 返回时检查。


在 Linux Kernel 里引入 softirq 机制后,使用 tasklet 来实现 Bottom Half。
tasklet 也是 softirq 的一种应用,在使用 Bootom Half(tasklet)处理硬件
中断后续工作前,需显示调用相关的 kernel api 注册 Bootom Half(tasklet)。
关于硬件中断如何触发 softirq,可以看 do_IRQ() 这个函数,这个函数在处理
完设备驱动程序调用 request_irq() 注册的 ISR 后,会接着调用 irq_exit(),在
irq_exit() 中会检测是否注册了 softirq 回调函数,且在确定所有硬件中断都返
回后调用 do_softirq(),在这个函数当中会遍历软中断向量表,并调用相应的回
调函数,被调用的函数就是 tasklet 注册的回调函数,也就是你注册的 Bottom
Half。上面只是针对硬件中断而言,其实处理软中断的调用点,不光是在硬件中断
后触发,还有一些地方也调用了 do_softirq()。如在任务调度中 schedule() 函
数里也会判断是否需要执行软中断。还有在 syscall 调用时也有判断是否需要执
行软中断的地方。软中断的运行环境同样是中断上下文,在中断上下文中任何引起
睡眠的机制都将导致系统崩溃。


在 SOLARIS Kernel 中,有很大一部分硬件中断被线程化,如磁盘和网络中断,包
括时钟中断。实现中断上下文可阻塞。被线程化的中断,与普通线程共用一个
dispatcher。中断线程使用区别于 TS/IA/RT 调度等级的优先级,即全局优先级最
高的等级。我个人认为在这种响应硬件中断时可阻塞的中断线程化的处理机制中无
需提供像 DPC,Bottom Half 这种机制,这也是跟以上两种非中断线程化 OS 主要
区别。以上两种 OS 的中断处理机制,是为了不让在 ISR 中处理过多耗时操作,
而提供了一个系统回调函数接口,把那些相对耗时的处理操作放在回调函数中延迟
调用。而现在中断线程化并可阻塞了,我完全可以创建一个中断线程,所有处理工
作由系统负责,这样就无需再提供这种回调函数的接口了。既然不需要 DPC /
tasklet 的Bootom Half 的这种推迟机制那么在 SOLAIRS 内核中软中断的实现自
然也就不一样,它本身也是作为一种中断线程形式存在。关于软中断(softint)
的调用可以查看 interrupt.s 的代码。在中断处理的入口中首先判断了是否为软
中断调用 T_SOFTINT。如果是,则跳转到 dosoftint() 去执行,首先会判断如果
有比自身更高级的 pending 软中断,则直接返回。如果没有则判断当前处理线程
优先级比自身高的话马上返回。如果可以处理当前软中断则先 lock BUS 防止其他
CPU 重入这个软中断,设置当前 IPL 为软中断级。然后比较当前要中断的线程是
否是一个中断线程,如果不是则再继续判断是否要设置时间片。如果需要则进行设
置。如果当前是中断线程,则没有以上的步骤。然后就是中断当前线程,并使用被
中断线程的 LWP。接下来保存被中断的线程,切换到新软中断线程运行,继续使用
av_dispatch_softvect() 函数来执行被注册到 struct autovec 结构里的软中断
回调函数。等到调用完成后,退出软中断线程返回。以上步骤是在没有更高级的硬
件中断线程在运行。如果当前有更高级别的硬件中断正在执行的话,那么会在处理
完硬件中断后无条件的跳转到软中断处理中执行。注意,这里没有判断。从以上流
程可以看出软中断是有优先级的,即可以进行抢占。软中断的调用是无条件调用的,
即我可以直接显示的调用。这样我们可以看出系统在处理软中断时,从处理机制来
讲是与硬中断平级的,当然有优先级之分。这也意味着与 DPC 和 Bootom Half 这
种被动调用机制有这明显的不同。之所以设计成可以直接显示调用,应该是为了某
种性能调优而考虑的。在 SOLAIRS 的解释中,软中断是为一些伪设备所提供的。



最后 FIXME。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2