tasklet例程
简单实现步骤1.DECLARE_TASKLET() 2. tasklet_schedule(&demo_tasklet);
//设备相关的指针
static struct demo_dev *p = ....;
//延迟操作函数
void demo_delay_action(unsigned long data)
{
// 通过data获得设备相关指针
static struct demo_dev * pdev = (static struct demo_dev *)data;
// 延迟操作
.....
}
//用DECLARE_TASKLET(name, func, data)定义一个tasklet对象demo_tasklet
DECLARE_TASKLET(demo_tasklet, demo_delay_action, (unsigned log)p );
//中断处理例程
irqreturn_t demo_isr(int irq, void * dev_id)
{
.................
通过tasklet_schedule实现延迟操作
tasklet_schedule(&demo_tasklet); //此处提交tasklet对象和SOFTIRQ部分调用处理
}
在任意时刻,同一tasklet只能有一个实例在运行,即使是多处理器系统也如此。tasklet另一个特性是:
那个处理器调用tasklet_schedule提交的tasklet,只能在该处理器上运行。
工作队列work queue
简单实现步骤:1. INIT_WORK(_work, _func); 2. schedule_work();
struct work_struct //工作节点
struct cpu_workqueue_struct //cpu工作队列管理结构
struct workqueue_struct //工作队列管理管理结构
驱动程序可以调用create_singlethread_workaueue和creat_workqueue函数来让内核生成属于自己的工作队列,两者区别
前者只在系统中第一个CPU上创建工作队列和工人线程,后者函数会在系统中每个CPU上创建工作队列和工人线程。在用
queue_work提交工作节点时,如果是singlethread类型,只能提交到这唯一的一个worklist。反之,如果不是singlethread
类型,那么工作节点将会提交到当前运行queue_work的CPU所在的worklist中。
动态初始化:INIT_WORK(_work, _func)
静态初始化:DECLARE_WORK(n,f)
提交工作节点时只需调用schedule_work()函数就可以,对于queue_delayed_work,对于内核创建的工作队列而言,
延迟提交函数变成schedule_delayed_work().
使用内核工作队列好处是驱动无须创建自己的工作队列就可以提交节点来实现延迟操作,坏处是正在与系统
中其它模块共享一个工作队列以及该队列上的work_thread,所以无法预期提交一个节点需多久才调度执行。
内核提供了另一个提交节点的函数queue_delayed_work
int queue_delayed_work(struct workqueue_struct *wq, struct delayed_work *dwork, unsigned long delay);
自己创建工作队列例程:
//定义全局性的struct workqueue_struct指针demo_dev_wq
static struct workqueue_struct * demo_dev_wq;
//设备特定的数据结构,实际使用中大部分struct work_struct结构都内嵌在这个数据结构中
struct demo_device{
....................
struct work_struct work;
...............
}
static struct demo_device * demo_dev;
//定义延迟操作函数
void demo_work_func(ftruct work_struct *work)
{.................}
// 驱动程序模块初始化代码调用create_singlethread_workqueue创建工作队列
static int_init demo_dev_init(void)
{ ..................
demo_dev = kzalloc(sizeof *demo_dev,GFP_KERNEL);
demo_dev_wq = create_singlethread_workqueue("demo_dev_workqueue");
INIT_WORK(&demo_dev->work,demo_work_func);
...................
}
//模块退出函数
static void demo_dev _exit(void)
{.................
flush_wokqueue(demo_dev_wq);
destroy_workqueue(demo_dev_wq);
.........................
}
//中断处理函数
irqreturn_t demo_isr(int irq, void * dev_id)
{...........................
queue_work(demo_dev_wq, &demo_dev->work);
..........................
}