内核版本: 4.15
调度一个 work,首先需要定义一个 workqueue,然后将这个 work 放入到这个 workqueue 中。
当我们希望调度一个 work 时,可以有两种方法:
- 内核会为每一个 cpu 创建一个默认的 workqueue,可以用 schedule_work 函数将 work 加入到默认的 workqueue 中;
- 当默认的 workqueue 任务太重时,为了加快响应,我们可以自定义一个 workqueue,然后使用 queue_work 函数将 work 加入到自定义的 workqueue 中。
使用自定义的 workqueue
1
2
3
4
5
6
7
8
9
10
| struct work_struct {
/* atomic_long_t data; */
unsigned long data;
struct list_head entry;
work_func_t func;
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
|
使用前进行必要的初始化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| struct lt9611 {
struct workqueue_struct *wq;
struct work_struct some_work;
...
};
static void lt9611_some_work(struct work_struct *work)
{
struct lt9611 *pdata = container_of(work, struct lt9611, some_work) ;
...
}
static int lt9611_probe (struct i2c_client *client,
const struct i2c_device_id *id)
{
struct lt9611 *pdata;
...
pdata->wq = create_singlethread_workqueue ("lt9611_wq") ;
if (!pdata->wq) {
pr_err ("lt9611: fail to create workqueue") ;
goto err;
}
INIT_WORK(&pdata->some_work, lt9611_some_work) ;
...
}
|
使用 queue_work 调用需要的 work:
1
2
3
4
| static void foo_func (struct lt9611 *pdata)
{
queue_work(pdata->wq, &pdata->some_work) ;
}
|
使用 delayed workqueue
有时候,我们需要一个 work 在一段时间后才执行,这时候便可以使用 delayed work 。delayed workqueue 与普通的 workqueue 在使用上差别并不大,
从 delayed workqueue 的结构体定义就可以看出。
1
2
3
4
5
6
7
8
| struct delayed_work {
struct work_struct work;
struct timer_list timer;
/* target workqueue and CPU ->timer uses to queue ->work */
struct workqueue_struct *wq;
int cpu;
};
|
使用前进行必要的初始化:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
| struct lt9611 {
struct workqueue_struct *wq;
struct work_struct some_delayed_work;
...
};
static void lt9611_some_work ( struct work_struct *work )
{
/* 注意这里的to_delayed_work(work) */
struct lt9611 *pdata = container_of(to_delayed_work(work),
struct lt9611, some_delayed_work ) ;
...
}
static int lt9611_probe ( struct i2c_client *client,
const struct i2c_device_id *id )
{
struct lt9611 *pdata;
...
pdata->wq = create_singlethread_workqueue ( "lt9611_wq" ) ;
if ( !pdata->wq ) {
pr_err ( "lt9611: fail to create workqueue" ) ;
goto err;
}
INIT_DELAYED_WORK(&pdata->some_delayed_work, lt9611_some_delayed_work) ;
...
}
|
使用 queue_delayed_work 调用需要的 delayed_work :
1
2
3
4
5
6
| static void bar_func (struct lt9611 *pdata)
{
queue_delayed_work(pdata->wq, &pdata->some_delayed_work,
msecs_to_jiffies(300)) ;
...
}
|
和普通的 work 相比,除了初始化和调用的方式不同外,有一点需要格外注意:
work 和 delayed_work 对应的回调函数都是: void (*func)(struct work_struct *),delayed_work 回调函数的入参并不是 struct delayed_work *。
因此,在其回调函数中,需要两次调用 container_of 来获得包含 delayed_work 的结构体的地址。
参考
https://blog.csdn.net/heanyu/article/details/6899679