中断和异常

中断和异常

这周主要学习了中断和异常,在这里把整章知识梳理一下,做一个总结。(工作队列没有完成)
一、什么是中段
中断(外部中段)是对外部设备而言,I/O需要服务时处理器去相应。
异常(内部中断)是为了解决机器运行时所出现的某些随机事件及编程方便而出现的。
中断可分为屏蔽中断和不可屏蔽中断;异常分为故障、陷阱和终止三类。
二、中断程序的基本框架
注册中断函数:通过request_irq函数申请一根中断请求线。
第一个函数:中断号,对应中断控制器上IRQ的编号。
第二个函数:irt_handler_t类型个函数指针,handler所指向的函数即为需要具体实现的中断处理程序。
第三个函数:标志位。IRQF_SHARED:多个设备可共享一条IRQ线。IRQF_DISABLED:在执行该中断服务程序时会屏蔽所有其他的中断。IRQF_SAMPLE_RANDOM:设备看作是事件随机发生源。
第四个函数:请求中断的设备名称。
第五个函数:void型的指针型变量用于共享中断线。当一个中断服务程序需要释放时,将提供唯一的标识信息,以便在共享中断线的众多中断服务程序中删除指定的那一个。
中断和异常
中断和异常

free_irq函数会注销相应的中断处理程序,并释放中断线。如果中断线是共享的,只释放与mydev对应的中断处理程序,除非为中断线上的最后一员,此条中断线才会被禁用。如果不是共享的,在释放中断处理程序的同时也将禁用此条中断线。
中断和异常

附带参数模块:首先定义两个参数,然后用宏module_param来接收参数。
中断和异常

三、中断下半部分-tasklet
一个使用tasklet的中断程序首先会通过执行中断处理程序来快速完成上半部分的工作,接着通过调用taklet使得下半部分的工作得以完成。tasklet以一个数据结构形式存在,使用前必须得被初始化。初始化能够通过一个特定函数或者通过某些宏定义声明结构:
中断和异常

在这个结构体中,第一个成员代表链表中的下一个tasklet.第二个代表tasklet的状态,TASKLET_STATE_SCHED表示此tasklet被调度且正准备运行;TASKLET_STATE_RUN表示正在运行。count成员是引用计数器,为0时被**。func是一个函数指针,指向tasklet处理函数,data为它的唯一参数。
在内核中有两种方法创建tasklet_struct类型的变量,通常有两种方法:静态创建和动态创建。如下图宏定义中,通过两种静态创建的方法创建定义了一个名为name的tasklet_struct类型的变量,将宏中各个参数相应的赋值给name变量的各个成员。这两种创建差异在于name变量的第三个成员count的赋值上。
中断和异常

我们对第三个变量ATOMIC_INIT()进行解析:若给i赋值为0,相应的counter为0,tasklet可以被**,相反为1则不能被执行。
中断和异常
中断和异常

接下来分析动态创建:通过事先定义的指针来动态创建一个tasklet.第249行和第250行没理解清楚。
中断和异常

不管是静态创建还是动态创建,都要有func参数,func是一个函数指针,指向tasklet_handler函数。相当于中断处理程序,需要自己实现。创建好之后,通过tasklet_schedule进行调度。通过次函数的调用,tasklet被挂起,等待机会被执行。(我觉得里面是分析到硬件了,emmmmm看不懂还目前,先贴上。)
中断和异常

中断和异常

四、中断下半部分-工作队列
中断上下文:硬件传递过来的参数和内核保存的环境,主要是被中断的进程的的环境。
内核上下文:当前进程的进程上下文(用户空间的一些寄存器、变量),表现出进程的一些特性,因此可以被执行。
中断下半部分的另一种方式,主要是实现tasklet不能实现的工作,主要是工作队列机制可以睡眠。在该机制中,内核在执行中断的剩余工作时就处在进程上下文,将推后的工作交给工作者线程的内核线程去完成。
work_struct结构:改变了类型(原子类型)的data为之前版本pending和wq_data的复合体,entry链接所有工作的链表,形成工作队列。第三个为函数指针,指向工作队列。

中断和异常