linux 中断与时钟

转自:http://hi.baidu.com/yyangjjun/item/505847d46ab2091621e250b9

 

中断
中断就是CPU在执行程序的过程中,出现了突发事情时CPU暂停执行当前的程序,转去处理突发事情,处理完毕后返回到原来程序中断的位置并继续执行

申请IRQ
int request_irq(unsigned int irq, void (*handler)(int irq, void *dev_id, struct pt_regs *regs), unsigned long irqflags, const char *devname, void *dev_id);
返回0表示成功,返回-INVAL表示中断号无效或者中断处理函数为NULL,返回-EBUSY表示中断号已经被占用且不能共享

释放IRQ
void free_irq(unsigned int irq, void *dev_id);

使能/关闭中断
void disable_irq(int irq); //等目前中断处理完成
void disable_irq_nosync(int irq); //立即返回
void enable_irq(int irq);

屏蔽本CPU内的所有中断
void local_irq_save(unsigned long flags);
void local_irq_disable(void);
void local_irq_restore(unsigned long flags);
void local_irq_enable(void);

中断的处理程序一般分为顶半部和底半部,底半部机制主要有tasklet、工作队列和软中断

tasklet

void my_tasklet_func(unsigned long); //定义一个处理函数
DECLARE_TASKLET(my_tasklet, my_tasklet_func, data);
//定义一个tasklet结构my_tasklet,与my_tasklet_func()函数关联

tasklet_schedule(&my_tasklet);//调度my_tasklet
系统会在适当的时候进行调度运行

/******** tasklet 使用模板 ************/
/*定义tasklet和底半部函数并关联*/
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet, 0);

/*中断处理函数底半部*/
void xxx_do_tasklet(unsigned long)
{
......
}

/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
...
tasklet_schedule(&xxx_tasklet);
...
}

/*设备驱动模块加载函数*/
int __init xxx_int(void)
{
...
/*申请中断*/
result = request_irq(xxx_irq, xxx_interrupt, SA_INTERRUPT, "xxx", NULL);
....
}

/*设备驱动模块卸载函数*/
void __exit xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq, xxx_interrupt);
...
}

工作队列
struct work_struct my_wq; /*定义一个工作队列*/
void my_wq_func(unsigned long); /*定义一个处理函数*/

INIT_WORK(&my_wq, (void (*)(void *))my_wq_func, NULL);
//初始化工作队列并将其与处理函数绑定

schedule_work(&my_wq); //调度工作队列执行

********** 工作队列使用模板 **************
/*定义工作队列和关联函数*/
struct work_struct xxx_wq;
void xxx_do_work();

/*中断处理底半部*/
void xxx_do_work(unsigned long)
{
...
}

/*中断处理顶半部*/
irqreturn_t xxx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
...
schedule_work(&xxx_wq);
...   
}

/*设备驱动模块加载函数*/
int __init xxx_init(void)
{
...
/*申请中断*/
result = request_irq(xxx_irq, xxx_interrupt, SA_INTERRUPT, "xxx", NULL);
...

/*初始化工作队列*/
INIT_WORK(&my_wq, (void(*)(void *))xxx_do_work, NULL);
...
}

/*设备驱动模块卸载函数*/
void __exit xxx_exit(void)
{
...
/*释放中断*/
free_irq(xxx_irq, xxx_interrupt);
...
}
NOTE:最好的在设备第一次打时在申请设备的中断并在最后一次关闭时释放中断,以减少中断被这个设备占用的时间。
为方便,有可以把申请中断和释放的工作分别放在加载函数和释放函数中


软中断是用软件方式模拟硬件中断的概念,实现宏观上异步执行的效果,tasklet也是基于软中断实现的。

softirq_action 结构体表现一个软中断,结构体中包含软中断处理函数指针和传递给该函数的参数。
open_softirq()函数可注册软中断对应的处理函数
raise_softirq()函数触发一个软中断

NOTE:软中断和tasklet运行中断上下文,而工作队列运行于进程上下文,因此软中断和tasklet处理函数中不能睡眠,工作队列处理函数中允许睡眠

内核定时器
timer_list结构体的一个实例对应一个定时器
struct time_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long);
unsigned long data;
struct time_base_s *base;
}

struct timer_list my_timer; //定义一个定时器
void init_timer(struct timer_list *timer); //初始化定时器

DEFINE_TIMER(_name, _function, _expires, _data); //宏是定义并初始化定时器成员

void setup_timer(struct timer_list *temer, void(*func)(unsigned long), unsigned long);
//setup_timer()也用于初始化定时器并赋值其成员

void add_timer(struct timer_list *timer); //增加定时器,注册内核定时器,将定时器加到内核动态定时器链表中
int del_timer(struct timer_list *timer); //删除定时器
int mod_timer(struct timer_list *timer, unsigned long expires); //修改定时器的到期时间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值