Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1260033
  • 博文数量: 842
  • 博客积分: 12411
  • 博客等级: 上将
  • 技术积分: 5772
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-14 14:43
文章分类

全部博文(842)

文章存档

2013年(157)

2012年(685)

分类:

2012-04-26 23:14:46

原文地址:Linux内核-tasklet机制 作者:JGFNTU

参考自:http://hi.baidu.com/greatren518/blog/item/25b349c7126e8fd9d10060b1.html

      最近在做一个有关USB CAMERA的项目,发现我们的MUSB控制器驱动在收到一个完整的URB之后会回调UVC驱动去拷贝urb缓冲区的32个包的数据做后续处理。只是在我们的平台上,在进行urb切换的时候开销比较大,会造成在1ms之内未发出请求包,导致ISO类型的camera数据丢失一个包,导致图片出错。

     单纯为解决这个开销问题,可以将原UVC驱动着数据拷贝的代码从中断函数中挪到中断底半部中执行。当然,原UVC驱动之所以这么设计应该是为了保证数据的实时性,并且是建立在一定的系统性能上的,实测这套代码在mini2440的板子上是可以顺畅跑QVGA-30fs的。

     特此对中断底半部的机制之一tasklet做一个简要的描述,虽简单,参考网上的文章,做个记录。以下为转载:

     一个有关于定时的内核设施是 tasklet。它类似内核定时器:在中断时间运行且运行同一个 CPU 上, 并接收一个 unsigned long 参数。不同的是:无法要求在一个指定的时间执行函数,只能简单地要求它在以后的一个由内核选择的时间执行。它对于中断处理特别有用:硬件中断必须尽快处理, 但大部分的数据管理可以延后到以后安全的时间执行。 实际上, 一个 tasket, 就象一个内核定时器, 在一个"软中断"的上下文中执行(以原子模式)。软件中断是在使能硬件中断时执行异步任务的一个内核机制。

tasklet 以一个数据结构形式存在,使用前必须被初始化。初始化能够通过调用一个特定函数或者通过使用某些宏定义声明结构:

#include <linux/interrupt.h> 
struct tasklet_struct
{
    struct tasklet_struct *next;
    unsigned long state;
     atomic_t count;
    void (*func)(unsigned long);
    unsigned long data;
};
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data);

#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 }

void tasklet_disable(struct tasklet_struct *t); 
/*函数暂时禁止给定的 tasklet被 tasklet_schedule 调度,直到这个 tasklet 被再次被enable;若这个 tasklet 当前在运行, 这个函数忙等待直到这个tasklet退出*/
void tasklet_disable_nosync(struct tasklet_struct *t); 
/*和tasklet_disable类似,但是tasklet可能仍然运行在另一个 CPU */
void tasklet_enable(struct tasklet_struct *t); 
/*使能一个之前被disable的 tasklet;若这个 tasklet 已经被调度, 它会很快运行。 tasklet_enable 和tasklet_disable必须匹配调用, 因为内核跟踪每个 tasklet 的"禁止次数"*/ 
void tasklet_schedule(struct tasklet_struct *t); 
/*调度 tasklet 执行,如果tasklet在运行中被调度, 它在完成后会再次运行; 这保证了在其他事件被处理当中发生的事件受到应有的注意. 这个做法也允许一个 tasklet 重新调度它自己*/
void tasklet_hi_schedule(struct tasklet_struct *t); 
/*和tasklet_schedule类似,只是在更高优先级执行。当软中断处理运行时, 它处理高优先级 tasklet 在其他软中断之前,只有具有低响应周期要求的驱动才应使用这个函数, 可避免其他软件中断处理引入的附加周期*/
void tasklet_kill(struct tasklet_struct *t); 
/*确保了 tasklet 不会被再次调度来运行,通常当一个设备正被关闭或者模块卸载时被调用。如果 tasklet 正在运行, 这个函数等待直到它执行完毕。若 tasklet 重新调度它自己,则必须阻止在调用 tasklet_kill 前它重新调度它自己,如同使用 del_timer_sync*/

tasklet 的特点:
(1)一个 tasklet 能够被禁止并且之后被重新使能; 它不会执行,直到它被使能与被禁止相同的的次数;
(2)如同定时器, 一个 tasklet 可以注册它自己;
(3)一个 tasklet 能被调度来执行以正常的优先级或者高优先级;
(4) 如果系统不在重负载下,taslet 可能立刻运行, 但是从不会晚于下一个时钟嘀哒;
(5)一个 tasklet 可能和其他 tasklet 并发, 但是它自己是严格地串行的 ,且tasklet 从不同时运行在不同处理器上,通常在调度它的同一个 CPU 上运行。

       当然,这个机制在实时性要求很高的USB的ISO传输(1ms一次中断)的背景下,会造成图片数据的少许延时,是否应该可以考虑使用void tasklet_hi_schedule(struct tasklet_struct *t),按照上述的描述,可能效果有限,毕竟这个1ms一次的中断是很频繁的。   

阅读(1039) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~