Linux之时钟中断详解

2019-09-23 08:59:42丽君

struct irqaction { 
  irq_handler_t handler;  //中断处理函数,注册时提供  
  unsigned long flags;   //中断标志,注册时提供  
  cpumask_t mask;    //中断掩码  
  const char *name;   //中断名称 
  void *dev_id;      //设备id,本文后面部分介绍中断共享时会详细说明这个参数的作用 
  struct irqaction *next;  //如果有中断共享,则继续执行,  
  int irq;        //中断号,注册时提供 
  struct proc_dir_entry *dir; //指向IRQn相关的/proc/irq/n目录的描述符 
}; 

这个结构体包含了处理一种中断所需要的各种信息,它代表了内核接受到特定IRQ之后应该采取的操作。

1.handler:该指针所指向的函数就是在中断服务程序,当中断发生时内核便会调用这个指针指向的函数。

2.flags:该标志位可以是0,也可以是:

SA_INTERRUPT:表示此中断处理程序是一个快速中断处理程序,在2.6中默认情况下没有这个标志;设置该标志位,中断处理程序禁止任何中断运行,没有该标志,仅屏蔽正在运行的IRQ线;

SA_SAMPLE_RANDOM:表示这个中断对内核池有贡献,在中断时产生一些随机数;

SA_SHIRQ:此标志位表示允许多个中断服务程序共享一个中断号,如不设则一个程序对应一个中断线;

3.mask:在x86上不会用到。

4.name:产生中断的硬件的名字.

5.dev_id:该标志位主要在共享中断号时使用,即你设置flags=SA_SHIRQ时,有多个中断服务程序共享一个中断号时,内核就需要知道在用完中断程序后该删除那个中断服务程序。不共享时此成员为null。

6.next:如果flags=SA_SHIRQ,那么这就是指向对列中下一个struct irqaction结构体的指针,否则为空。

7.irq:不用说这就是中断号了。

到现在为止,我们仅仅是把时钟中断程序挂入中断请求队列,什么时候执行,怎样执行,这是一个复杂的过程(参见第三章),为了让读者对时钟中断有一个完整的认识,我们忽略中间过程,而给出一个整体描述。我们将有关函数改写如下,体现时钟中断的大意:

do_timer_interrupt( )   /*这是一个伪函数 */ 
{            
 SAVE_ALL     /*保存处理机现场 */ 
 intr_count += 1;    /* 这段操作不允许被中断 */ 
 timer_interrupt()    /* 调用时钟中断程序 */ 
 intr_count -= 1;    
 jmp ret_from_intr    /* 中断返回函数 */ 
} 

其中,jmp ret_from_intr 是一段汇编代码,也是一个较为复杂的过程,它最终要调用jmp ret_from_sys_call,即系统调用返回函数,而这个函数与进程的调度又密切相关,,因此,我们重点分析 jmp ret_from_sys_call。

3.系统调用返回函数:

系统调用返回函数的源代码在/arch/i386/kernel/entry.S中

ENTRY(ret_from_sys_call) 
   cli     # need_resched and signals atomic test 
   cmpl $0,need_resched(%ebx) 
   jne reschedule 
   cmpl $0,sigpending(%ebx) 
   jne signal_return 
 restore_all: 
   RESTORE_ALL 
   ALIGN 
 signal_return: 
   sti    # we can get here from an interrupt handler 
   testl $(VM_MASK),EFLAGS(%esp) 
   movl %esp,%eax 
   jne v86_signal_return 
   xorl %edx,%edx 
   call SYMBOL_NAME(do_signal) 
   jmp restore_all 
   ALIGN 
  v86_signal_return: 
   call SYMBOL_NAME(save_v86_state) 
   movl %eax,%esp 
   xorl %edx,%edx 
   call SYMBOL_NAME(do_signal) 
   jmp restore_all 
 …. 
 reschedule: 
   call SYMBOL_NAME(schedule) # test 
  jmp ret_from_sys_call