一、中断基本概念
1、中断的定义
因此一个中断有如下几个主要部分:
中断源:中断源是指打断CPU的事件,没有中断源便没有中断,它可以是硬件的也可以是软件的。
CPU:中断就是要用CPU来处理一些事情的
中断控制器8259A:硬件中断源与CPU之间的桥梁,没有它中断就无法被CPU所知道。
中断服务程序:你打断了CPU,CPU就得根据这个程序来为你办事。
2、 Linux的中断分类:
3、中断向量
Inter x86共支持256个向量中断,并将它们从0到255进行编号,Inter将这个整数叫做中断向量,Linux对这256个中断向量的分配如下:
1)0~31为异常和非屏蔽中断
2)32~47为可屏蔽中断(硬件中断)
3)48~255用来表示软中断,Linux只用了其中的一个(即128或0x80向量)作为系统调用。
4、中断描述符表
中断描述符表,也叫中断向量表,每个表项叫做门描述符占8个字节,简单的说是用来存放中断处理程序入口函数地址,当然还包括了一些其他信息。其作用就是当一个中断发生时我们根据它的中断号确定其中断向量,然后在此表中找到它的入口函数从而执行它。这个表存放在内存中的一片区域中。我们需要一个系统寄存器——中断描述符寄存器IDTR来存放中断描述符表在内存的起始地址。IDTR占48位,在低字节(低16位)中装的是界 限,在高字节(高32位)中装的是基址。如下图所示:
| |
二、认识linux中断
中断号的查看可以使用下面的命令:“cat /proc/interrupts”。
eg:小任务tasklet的实现
其数据结构为struct tasklet_struct,每一个结构体代表一个独立的小任务,定义如下
struct tasklet_struct
{
};
声明和使用小任务tasklet
静态的创建一个小任务的宏有一下两个:
#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
#define DECLARE_TASKLET_DISABLED(name, func, data) \
struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }
这两个宏的区别在于计数器设置的初始值不同,前者可以看出为0,后者为1。为0的表示激活状态,为1的表示禁止状态。
三、中断应用
1、时钟中断
struct
};
struct
};
Linux中时钟中断处理程序的每一次时钟中断的产生都触发下列几个主要操作:
(1)自系统启动以来所花费的时间
(2)更新时间和日期
(3)确定当前进程在CPU上已运行了多长时间,如果已经超过了分配给它的时间,则抢占它
(4)更新资源使用统计数
(5)检查定时器时间间隔是否已到达,如果是,则调用适当的函数
2、中断机制核心数据机构
中断机制的核心数据结构是 irq_desc, 它完整地描述了一条中断线。以下为程序源码:
typedef
struct irq_desc {
#ifdef CONFIG_INTR_REMAP
#endif
#ifdef CONFIG_SMP
#ifdef CONFIG_GENERIC_PENDING_IRQ
#endif
#endif
#ifdef CONFIG_PROC_FS
#endif
} ____cacheline_internodealigned_in_smp;
request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev);
函数参数说明
unsigned int irq:所要申请的硬件中断号
irq_handler_t handler:中断服务程序的入口地址,中断发生时,系统调用handler这个函数。
irq_handler_t为自定义类型,其原型为:
typedef irqreturn_t (*irq_handler_t)(int, void *);
而irqreturn_t的原型为:typedef enum irqreturn irqreturn_t;
enum irqreturn {
};
此枚举类型irqreturn定义在include/linux/irqreturn.h文件中。
unsigned long flags:中断处理的属性。
const char *dev_name:设备描述,表示那一个设备在使用这个中断。
void *dev_id:用作共享中断线的指针。
释放中断,函数原型为:
void free_irq(unsigned int irq, void *dev_id);