项目需要,在驱动模块里用内核计时器timer_list实现了一个状态机。
郁闷的是,运行时总报错“Scheduling while atomic”,网上搜了一下:
"Scheduling while atomic" indicates that you've tried to sleep somewhere that you shouldn't - like within a spinlock-protected critical section or an interrupt handler.
改进程序,在计时器里使用了workqueue,搞定问题。顺便把workqueue的实现代码总结了一下
一、workqueue简介
workqueue与tasklet类似,都是允许内核代码请求某个函数在将来的时间被调用(抄《ldd3》上的)
每个workqueue就是一个内核进程。
workqueue与tasklet的区别:
1.tasklet是通过软中断实现的,在软中断上下文中运行,tasklet代码必须是原子的
workqueue是通过内核进程实现的,就没有上述限制的,最爽的是,工作队列函数可以休眠
PS: 我的驱动模块就是印在计时器中调用了可休眠函数,所以出现了cheduling while atomic告警
内核计时器也是通过软中断实现的
2.tasklet始终运行在被初始提交的同一处理器上,workqueue不一定
3.tasklet不能确定延时时间(即使很短),workqueue可以设定延迟时间
二、workqueue的API
workqueue的API自2.6.20后发生了变化
#include <linux/workqueue.h>
struct workqueue_struct;
struct work_struct;
struct workqueue_struct *create_workqueue(const char *name);
void destroy_workqueue(struct workqueue_struct *queue);
INIT_WORK(_work, _func);
INIT_DELAYED_WORK(_work, _func);
int queue_work(struct workqueue_struct *wq, struct work_struct *work);
int queue_delayed_work(struct workqueue_struct *wq,struct delayed_work *dwork, unsigned long delay);
int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
struct delayed_work *dwork, unsigned long delay);
int cancel_work_sync(struct work_struct *work);
int cancel_delayed_work_sync(struct delayed_work *dwork);
void flush_workqueue(struct workqueue_struct *wq);
Workqueue 编程接口
序号
接口函数
说明
1
create_workqueue
用于创建一个workqueue队列,为系统中的每个CPU都创建一个内核线程。输入参数:
@name:workqueue的名称
2
create_singlethread_workqueue
用于创建workqueue,只创建一个内核线程。输入参数:
@name:workqueue名称
3
destroy_workqueue
释放workqueue队列。输入参数:
@ workqueue_struct:需要释放的workqueue队