中断与时钟

1、申请IRQ

int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id);

irq是要申请的硬件中断号;

handler 是向系统登记的中断处理函数(顶半部),是一个回调函数,中段发生时,系统调用这个函数,dev_id参数将被传递给它。

request_irq() 返回0表示成功,返回-EINVAL 表示中断号无效或处理函数指针为NULL, 返回-EBUSY 表示中断已经被占用且不能共享。

2、释放IRQ

void free_irq(unsigned int irq, void *dev_id);

3、使能和屏蔽中断

void disable_irq(int irq);

void disable_irq_nosync(int irq);

void enable_irq(int irq);


#define local_irq_save(flags) ...

void local_irq_disable(void);


#define local_irq_restore(flags) ...

void local_irq_enable(void);

以上local_开头的方法的作用范围是本CPU内。

4、底半部机制

linux实现底半部机制主要有tasklet、工作队列和软中断。

1、tasklet

void my_tasklet_func(unsigned long); /*定义一个处理函数*/

DECLARE_TASKLET(my_tasklet, my_tasklet_func, data); /*定义一个tasklet结构my_tasklet, 与my_tasklet_func(data)函数相关联*/

在需要调度tasklet的时候引用一个 tasklet_schedule() 函数就能使系统在适当的时候进行调度运行:

tasklet_schedule(&my_tasklet);

2、工作队列

struct work_struct my_wq; /*定义一个工作队列*/

void my_wq_func(unsigned long); /*定义一个处理函数*/

通过INIT_WORK() 可以初始化这个工作队列并将工作队列与处理函数绑定:

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

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

3、软中断

软中断(softirq)也是一种传统的底半部处理机制,它的执行时机通常是顶半部返回的时候,tasklet 是基于软中断实现的,因此也运行于软中断上下文。

在linux内核中,用softirq_action结构体表征一个软中断,包含软中断处理函数指针和传递给该函数的参数。使用open_softirq() 函数可以注册软中断对应的处理函数,而raise_softirq() 函数可以触发一个软中断。

local_bh_disable()和local_bh_enable() 是内核中用于禁止和使能软中断和tasklet底半部机制的函数。

5、内核定时器

linux内核所提供的用于操作定时器的数据结构和函数如下。

1. timer_list

struct timer_list {

struct list_head entry; //定时器列表

unsigned long expires; //定时器到期时间

void (*function) (unsigned long); //定时器处理函数

unsigned long data; //作为参数被传入定时器处理函数

struct timer_base_s *base;

......

};

struct timer_list my_timer; //定义一个名为my_timer的定时器

2、初始化定时器

void init_timer(struct timer_list * timer);

3、增加定时器

void  add_timer(struct timer_list *time);

4、删除定时器

void del_timer(stuct timer_list *time);

del_timer_sync() 是del_timer()的同步版,在删除一个定时器时需等待其被处理完,因此该函数的调用不能发生在中断上下文。

5、修改定时器的expire

int mod_timer(struct timer_list *timer, unsigned  long expires);//用于修改定时器的到期时间,在新的被传入的expires到来后才会执行定时器函数。

6、 睡着延迟

schedule_timeout()可以使当前任务睡眠指定的jiffies 之后重新被调度执行。

总结:

Linux的中断处理分为两个半部,顶半部处理紧急的硬件操作,底半部处理不紧急的耗时操作。tasklet 和工作队列都是调度中断底半部的良好机制,tasklet 基于软中断实现。内核定时器也依靠软中断实现。

内核中的延时可以采用忙等待或睡眠等待,为了充分利用CPU资源,使系统有更好的吞吐性能,在对延迟时间的要求并不是很精确的情况下,睡眠等待通常是指的推荐的。而ndelay()、udelay()忙等待机制在驱动中通常是为了配合硬件上短时延时要求。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值