设备一般都比CPU慢得多。因此一般情况下,当一个进程通过设备驱动程序向设备发出读写请求后,CPU并不等待I/O操作的完成,而是让正在执行的进程去睡眠,CPU自己做别的事情,例如唤醒另一个进程执行。当设备完成I/O操作需要通知CPU时,会向CPU发出一个中断请求;然后CPU根据中断请求来决定调用相应的设备驱动程序。
当设备执行某个命令时,如“将读取磁头移动到软盘的第42扇区上”,设备驱动程序可以从查询方式和中断方式中选择一种来判断设备是否已经完成此命令。
查询方式意味着需要经常读取设备的状态,一直到设备状态表明请求已经完成为止。如果设备驱动程序被连接进内核,这时使用查询方式将会带来灾难性后果:内核将在此过程中无所事事,直到设备完成目前的请求。有一种方法可以有效的改善这一弊端,就是通过使用系统定时器,使内核周期性调用设备驱动程序中的某个例程来检查设备状态。使用定时器是查询方式中最好的一种,但更有效的方法是使用中断。
基于中断的设备驱动程序,指的是在硬件设备需要服务时向 CPU 发一个中断信号,引发中断服务子程序执行 。这样就大大地提高了系统资源的利用率,使内核不必一直等到设备执行完任务后才开始有事可干,而是在设备工作期间内核就可以转去处理其它的事务,收到中断请求信号时再回头响应设备
1. Linux 对中断的管理
Linux 内核为了将来自硬件设备的中断传递到相应的设备驱动程序,在驱动程序初始化的时候就将其对应的中断程序进行了登记,即通过调用函数 request_irq ( ) 将其中断信息添加到结构为irqaction的数组中,从而使中断号和中断服务程序联系起来
8static inline int __must_check 129request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, 130 const char *name, void *dev) 131{ 132 return request_threaded_irq(irq, handler, NULL, flags, name, dev); 133} 134
typedef irqreturn_t (*irq_handler_t)(int, void *);
92/** 93 * struct irqaction - per interrupt action descriptor 94 * @handler: interrupt handler function 95 * @flags: flags (see IRQF_* above) 96 * @name: name of the device 97 * @dev_id: cookie to identify the device 98 * @next: pointer to the next irqaction for shared interrupts 99 * @irq: interrupt number 100 * @dir: pointer to the proc/irq/NN/name entry 101 * @thread_fn: interrupt handler function for threaded interrupts 102 * @thread: thread pointer for threaded interrupts 103 * @thread_flags: flags related to @thread 104 * @thread_mask: bitmask for keeping track of @thread activity 105 */ 106struct irqaction { 107 irq_handler_t handler; 108 unsigned long flags; 109 void *dev_id; 110 struct irqaction *next; 111 int irq; 112 irq_handler_t thread_fn; 113 struct task_struct *thread; 114 unsigned long thread_flags; 115 unsigned long thread_mask; 116 const char *name; 117 struct proc_dir_entry *dir; 118} ____cacheline_internodealigned_in_smp; 119