《Linux内核设计与实现》读书笔记—中断与系统调用

本文介绍了Linux系统调用的基本概念,包括系统调用号的作用、数据传输函数及权限检查等。同时,详细解释了中断的概念,包括异常与中断的区别、中断处理程序的上下文特性、上半部与下半部的工作原理,以及如何注册和编写中断处理程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

系统调用简介

  1. 在Linux中,每个系统调用被赋予一个系统调用号,用户空间的进程执行一个系统调用时,这个系统调用号就用来指明到底是要执行哪个系统调用。
  2. 用户空间的程序无法直接执行内核代码,因为内核驻留在受保护的地址空间上。所以,当用户进程执行系统调用时,通过软中断陷入到内核中,内核上该软中断对应的异常处理程序通过读取对应的系统调用号,知道用户进程执行了那种系统调用后,变开始执行对应的系统调用处理程序完成任务。
  3. 内核提供了copy_to_user()和copy_from_user()两个函数来分别完成向用户空间写入数据和从用户空间读取数据的处理。copy_to_user()和copy_from_user()都有可能引起进程阻塞,当包含用户数据的页被换出到硬盘上而不是在物理内存上时,这种情况便会发生。
  4. capable()函数用来检查调用系统调用的进程是否拥有某项权限。

中断简介

  1. 异常和中断不同,异常在产生时必须考虑与处理器时钟同步,而中断不需要。因此异常也被称为同步中断。在处理器执行到由于编程失误而导致的错误指令(例如除0)时,或者在执行期间出现特殊情况(例如缺页),必须靠内核处理的时候,处理器就会产生一个异常。
  2. 一个设备的中断处理程序是它设备驱动程序的一部分,设备驱动程序是用于对设备进行管理的内核代码。中断处理程序与其他内核函数的真正区别在于,中断处理程序是被内核调用来响应中断的,而它们运行于我们称之为中断上下文的特殊上下文中。

上半部与下半部的对比

  1. 通常,中断服务程序需要快速完成,以便能够快速恢复中断代码的执行。但是中断处理程序往往还要完成大量其他的工作。因此在快速完成相应和处理大量工作间便存在矛盾
  2. 鉴于此矛盾,我们一般把中断处理切位两个部分。中断处理程序是上半部,它立即开始执行,但只做有严格时限的工作。能够被允许稍后完成的工作会推迟到下半部去。

注册中断处理程序

  1. 驱动程序可以通过request_irq()函数注册一个中断处理程序,并且激活给定的中断号。
  2. request_irq()的函数原型为int request(unsigned int irq,irq_handler_t handler,unsigned long flags,const char* name,void*dev)。
  • 其中第一个参数irq为中断号,
  • 第二个参数为中断处理程序的函数指针,中断处理程序原型为typedef irqreturn_t(*irq_handler_t)(int, void*)。
  • 第三个参数为中断处理标志,例如IRQF_DISABLED表示内核在处理中断处理程序本身期间,禁止其他所有中断。IRQF_TIMER是特别为系统定时器的中断处理准备的等等。IRQF_SHARED表明多个中断处理程序之间共享中断线。
  • 第四个参数name是中断的设备名,这些名字会被/proc/irq和/proc/interrupts文件使用
  • 第五个参数dev用于共享中断线。当一个中断处理程序需要释放时,dev将提供唯一的标志信息,以便从共享中断线的诸多中断处理程序中删除指定的哪一个。
  1. request_irq()函数可能会引起睡眠。在注册的过程中,内核需要在/Proc/irq文件中创建一个与中断对应的项,函数proc_mkdir()用来创建这个新的procfs项,最终会调用kmalloc()请求分配内存,而kmalloc()会引起睡眠。
  2. 卸载驱动程序时,需要注销相应的中断处理程序,并释放中断线。void free_irq(unsigned int irq, void * dev)用来释放中断处理程序。如果该中断线不共享,则函数删除处理程序的同时将禁用这条中断线。如果中断线是共享的,则仅删除dev所对应的处理程序。

编写中断处理程序

  1. 中断处理程序的函数原型为typedef irqreturn_t (*irq_handler_t) (int irq, void* dev)。
  • 第一个参数表示中断发生的中断号。
  • 第二个参数必须与注册时传递给request_irq()的参数一致。
  1. 中断处理程序的返回值的类型为irqreturn_t,一般返回值为IRQ_NONE,表示该中断对应的设备并不是在注册处理函数期间指定的产生源;或者IRQ_HANDLED,表示中断处理程序被正确调用,确实是它所对应的设备产生了中断。

中断上下文

  1. 中断上下文不可以睡眠,因此中断上下文中不可以调度某些引起睡眠的函数。
  2. 中断上下文具有较为严格的时间限制,因为它打断了其他代码。因此,中断处理程序应该尽量只做一些必须处理的操作,然后把处理程序中大部分的工作挪出来,放到下半部中去执行。

中断处理机制的实现

  1. 中断发送给处理器后,处理器会立即停止它正在做的事,关闭中断系统,然后跳到内存中预定义的位置执行那里的代码。
  2. 通过预定义入口点,内核获取中断对应的中断号(IRQ),然后调用do_IRQ()。
  3. 接下来,do_IRQ()需要确保在这条中断线上有一个有效的处理程序,而且这个程序已经启动,但是当前没有执行,这样的话,do_IRQ()就调用handle_IRQ_event()来运行为这条中断线所安装的中断处理程序。如果没有有效的处理程序,或者handle_IRQ_event()执行完毕后,会调用ret_from_intr()函数执行一些清理工作。

中断控制

  1. 一般而言,控制中断系统的原因归根结底是需要提供同步,但是不管是禁止中断还是禁止内核抢占,没无法防止来自其他处理器的并发访问。因此再多处理器中,内核代码一般需要获取锁,防止来自其他处理器的并发访问。
  2. 禁止和激活中断:local_irq_disable()和local_irq_enable()。
  3. 禁止指定的中断线:disable_irq(unsigned int irq),disable_irq_nosync(unsigned int irq)和enable_irq(unsigned int irq),synchronize_irq(unsigned int irq)。
  4. 中断系统的状态:宏irqs_disable()检查本地处理器上的中断系统,如果被禁止,则返回非0,否则返回0值。in_interrupt()检查内核是否处于任何类型的中断处理程序或者下半部处理程序中,如果是,则返回非0。而宏in_irq()只有内核出在执行中断处理程序时才返回非0。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值