Linux内核设计与实现 中断I/O: 顶部

中断I/O

        CPU与外设之间的一种通信方式。  与CPU内部的异常类似。但区别就在于异常的发生是与处理器的时钟信号的同步的,所以异常有时也被称为同步中断。而中断是异步的,可能发生在任何时候(如果中断被允许的话)。

中断处理程序

        中断处理程序是内核用来响应相应中断的程序,通常来说每个设备都拥有对应的中断处理程序,来进行相应的处理。举例来说,如果用户按下键盘,则键盘会发送信号给中断控制器,接着中断控制器又通过CPU的中断引脚通知CPU,在执行完当前指令后,CPU立即检测中断引脚(似乎在每条指令执行后,都会进行一次检测),发现有中断发生。CPU经过一系列的检查后,如果当前允许中断,则确定中断是由键盘产生的,然后启动键盘的中断处理程序,读取用户的输入。

        中断程序必须执行得尽可能的快,这对于系统性能来说十分重要。但是通常来说,中断程序的工作量十分浩大,比如说网络设备的中断程序:首先需要向设备确认已了解到中断的发生(设备不再发出中断信号),然后将设备中的数据复制到内存中,进行甄别,把数据发送到其对应的协议的栈或者是应用程序中。显然,在今天巨大的网络吞吐量下,这是个耗时的工作。

        于是就产生了矛盾,所以我们把中断服务程序分为上下两部分。上半部分执行耗时极少的工作,比如确认已检测到中断或者将相应设备重置。然后将那些繁重的,却又不是很迫切而可以延迟的工作,交付给中断程序的下半部分。在顶部执行时,系统通常会禁止中断的投递,也就是说顶部的工作不会被其他中断打断(注意:此时在中断上下文),因为这部分工作相当重要。而底部的工作,会在未来某个恰当的时机执行,并且允许其他中断的发生。

登记中断处理程序

        我们可以调用request_irq()函数(Kernel/irq.c)来向系统注册一个中断服务程序。


request_irq()

        接下来解析每个参数的含义。irq指明要申请的的中断号,对某些设备来说,其对应的中断号是硬编码的——也就是说不可更改,比如系统定时器和键盘。至于其他的设备所使用的的中断号,则是可以动态分配的。handler顾名思义就是对应的中断处理程序。irqflags可以为0,或者从以下的值中选择(可以使一个或者多个):

        SA_INTERRUPT:这种取值的中断处理程序是快中断处理程序。Linux系统通常将中断程序相对地由快慢来划分。发展到了今天,个中的区    别就是,当快中断程序执行时,将当前处理器的中断禁用。这样做会使处理程序更快地完成执行,不会被其他中断打扰。默认情况下——也就是不启用该标志的情况下,除了与当前处理程序共享中断线的中断外,所有中断都是可用的。回忆《软硬件接口》中的中断屏蔽字位,可以建立起对应关系——对每个中断来说,确实存在私有的中断屏蔽字,当起处理程序执行时,禁用这些中断。

        SA_SAMPLE_RANDOM:暂时不知道这是干啥的。

        SA_SHIRQ:设置了此为的处理程序表示其irq参数所指定的中断线可以被其他中断处理程序分享。如果不设置此位,那么中断线是被单一设备独占的。早期的计算机系统中设备并不多,因此设备独占中断线号的方法是可行的,当往计算机里增加的设备越来越多时,独占的方式明显是不切实际的。因此产生了共享中断线号的思想。那么当一条共享中断线中发来中断信号,我们该如何辨别到底是哪个设备发生了中断?其实就是将该共享中断线上的所以处理程序调用,不过在每个中断处理程序的内部首先检查(参数信息以及设备硬件的支持)是不是这个中断处理程序对应的设备产生的中断,通常是通过读取该硬件设备提供的中断标志位进行判断。如果不是,立即返回,如果是,则处理完成,如果链表中没有一个是,则说明出现错误。

        下面回到对参数的介绍。顾名思义devname就是设备的名字,ASCII的文本。这个参数会被/proc/irq/proc/interrupts所使用。第五个参数dev_id是用于共享中断线的。如果不提供这样一个唯一的设备ID,那么我们就没有办法从共享中断线中移除指定的中断处理程序。想象一下,每个人都长得差不多,那么辨别我们的方法就是身份证了。通常来讲,这个参数会设置为硬件驱动的设备结构体——独一无二的,并且可能在处理程序中会被用到。

      注意:dev_id不是用于识别究竟是哪个设备产生中断的!!!


释放中断处理程序

        通过调用free_irq()来实现。


free_irq()

        可以看到dev_id发挥了重要作用,它被用于判定处理程序是否为我们想要移除和释放的处理程序。注意到第8行,用了一个没有释放内存但却很有趣的删除手段。

编写中断处理程序

        中断处理程序定义是这样的:

                static irqreturn_t  intr_handler(int irq, void *dev_id, struct pt_regs*regs)

        在这里,传递dev_id的原因是用于区分共享中断处理程序的不同设备。在早期每个设备独占中断线号,用Irq区分即可。但今非昔比。还有比较重要的是返回值类型irqreturn_t——实际上就是int。其值只有两种。我们用宏IRQ_RETVAL(val)来检测,val非0就返回IRQ_HANDLED,否则就返回IRQ_NONE。IRQ_HANDLED表示设备确实有中断请求,我们调用了正确的处理程序。如果是IRQ_NONE则表示未检测到设备的中断请求。每个中断处理程序的实现取决于设备,但通常来说都要向设备确认:我已了解到中断了。

        再次强调:当某中断服务程序执行时,其共享中断线号上的所有中断被屏蔽。并且相同的处理程序不可能在相同处理器并行地执行。


中断上下文

          当处理程序运行时,无论是上下部分,它都是处于中断上下文的。

          在Linux2.6里,每个进程的内核栈大小都初始地被分配为一个页面大小,减轻内存压力。中断处理进程也被单独地分配了一个页大小的空间用作栈——此前,中断进程将与被中断的进程共享其内核栈。如果自己新建中断服务程序也无须担心可用内存的大小——因为内核总是分配绝对的,最小的栈空间。

        个人猜想:中断处理程序是预先驻留在内存给定位置的,比如8086机器,是存放在0x0000H开始的一段内存空间。当中断发生时,便根据中断号启动相应的服务程序。在此过程中,内核并没有给中断程序创建进程描述符,所以其是不可调度的,这也呼应了中断程序上半部分必须执行地尽可能快的原则。并且在整个中断执行过程中,current的值依旧指向原进程的进程描述符。

        关于中断上下文的详细知识,我阅读更多源码后再补充。

中断控制

        以下是几个关于中断控制的接口函数。

        启用中断: local_irq_enable()

        禁用中断: local_irq_disable()

        保存中断状态:local_irq_save((unsigned long) flags)

        恢复中断状态:local_irq_restore((unsigned long) flags)

        禁止指定中断线:void disable_irq(unsigned int irq)

                                        void disable_irq_nosync(unsigned int irq)

                                        void sychronize_irq(unsigned int irq)

        以上函数禁止指定中断线向所有处理器的投递,但个中关系还不明朗。

        启用指定中断线:void enable_irq(unsigned int irq)

        检查中断状态:#define in_interrupt() (irq_count()) 如果内核处于中断上下文返回非0值,包括正在执行的中断处理程序或是下半部分程序。

                                    #define in_irq() (hardirq_count()) 当内核正在执行中断处理程序(特指顶部),则返回非0值。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,026评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,655评论 1 296
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,726评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,204评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,558评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,731评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,944评论 2 314
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,698评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,438评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,633评论 2 247
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,125评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,444评论 3 255
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,137评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,103评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,888评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,772评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,669评论 2 271

推荐阅读更多精彩内容

  • 1 中断介绍 1.1 简介 中断控制是计算机发展中一种重要的技术。最初它是为克服对I/O接口控制采用程序查询所带来...
    疯狂小王子阅读 7,978评论 0 9
  • 又来到了一个老生常谈的问题,应用层软件开发的程序员要不要了解和深入学习操作系统呢? 今天就这个问题开始,来谈谈操...
    tangsl阅读 4,006评论 0 23
  • 生活是可以被规划的,意味着你大概能想象未来的一年、二年、三年的自己是什么样子的。 从12月份起,花了将近两个月的时...
    我是十六阅读 362评论 1 0
  • 从没有丈量过那条路的距离,一公里?半公里?我记得不远,甚至很近,近得让人很心安。没错,真的不远,因为你总是每天能往...
    山鬼sg阅读 377评论 0 1
  • 麒麟阁上开皇宴 文武大臣坐两班 王子公主排座次 笙管歌舞帝尊前 文不加点成大赋 君恩特赏金箔扇 扇属公主号绿晴 赐...
    一叶茶阅读 682评论 2 4