1. wait_queue_head_t
//定义
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
//初始化
//进入可中断睡眠等待,让出cpu
{
wait_queue_head_t wq;
init_waitqueue_head(&wq);
wait_event_interruptible(wq, ei.state == MTD_ERASE_DONE );
}
//唤醒
{
wake_up_interruptible((wait_queue_head_t *)ei->priv);
}
2. wait_queue_t
//定义
typedef struct __wait_queue wait_queue_t;
struct __wait_queue {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
//初始化
{
init_waitqueue_head(&chip->controller->wq);
}
//添加到等待队列中,并 睡眠 当前进程
{
spinlock_t *lock = &chip->controller->lock;
wait_queue_head_t *wq = &chip->controller->wq;
//调用DECLARE_WAITQUEEU创建一个等待队列的项
DECLARE_WAITQUEUE(wait, current);
retry:
spin_lock(lock);
//...
//将进程的状态更为TASK_INTERRUPTIBLE或TASK_UNINTERRUPTIBLE
//如果状态呗置为TASK_INTERRUPTIBLE,则信号唤醒进程。这就是所谓的 伪唤醒(唤醒不是因为时间的发生)
_current_state(TASK_UNINTERRUPTIBLE);
//调用add_wait_queue()把自己加入到队列中。该队列会在进程等待的条件满足时唤醒它。当然我们必须在其他地方撰写相关代码,在事件发生时,对等待队列进行wake_up()操作。
add_wait_queue(wq, &wait);
spin_unlock(lock);
//调用schedule();表示切换任务,此任务进入设置的状态,即休眠态
schedule();
goto retry;
}
//唤醒
{
//唤醒队列
//以下操作会唤醒以queue等待队列头的所有等待队列中所有属于该等待队列头的等待队列对应的进程。
wake_up(&chip->controller->wq);
remove_wait_queue(wq, &wait);
}
3.状态切换图
4.优先级调整
4.1 工作队列
/*
* System-wide workqueues which are always present.
*
* system_wq is the one used by schedule[_delayed]_work[_on]().
* Multi-CPU multi-threaded. There are users which expect relatively
* short queue flush time. Don't queue works which can run for too
* long.
*
*
* system_highpri_wq is similar to system_wq but for work items which
* require WQ_HIGHPRI.
*
* system_long_wq is similar to system_wq but may host long running
* works. Queue flushing might take relatively long.
*
* system_unbound_wq is unbound workqueue. Workers are not bound to
* any specific CPU, not concurrency managed, and all queued works are
* executed immediately as long as max_active limit is not reached and
* resources are available.
*
* system_freezable_wq is equivalent to system_wq except that it's
* freezable.
*
* *_power_efficient_wq are inclined towards saving power and converted
* into WQ_UNBOUND variants if 'wq_power_efficient' is enabled; otherwise,
* they are same as their non-power-efficient counterparts - e.g.
* system_power_efficient_wq is identical to system_wq if
* 'wq_power_efficient' is disabled. See WQ_POWER_EFFICIENT for more info.
*/
//system_wq Don't queue works which can run for too long.
//不要将可能运行太久的工作排队。
extern struct workqueue_struct *system_wq;
//system_highpri_wq for work items which require WQ_HIGHPRI.
extern struct workqueue_struct *system_highpri_wq;
extern struct workqueue_struct *system_long_wq;
extern struct workqueue_struct *system_unbound_wq;
extern struct workqueue_struct *system_freezable_wq;
extern struct workqueue_struct *system_power_efficient_wq;
extern struct workqueue_struct *system_freezable_power_efficient_wq;
#define alloc_ordered_workqueue(fmt, flags, args…)
alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args)
#define create_singlethread_workqueue(name)
alloc_ordered_workqueue("%s", WQ_MEM_RECLAIM, name)
#define create_workqueue(name)
alloc_workqueue("%s", WQ_MEM_RECLAIM, 1, (name))
#define create_freezable_workqueue(name)
alloc_workqueue("%s", WQ_FREEZABLE | WQ_UNBOUND | WQ_MEM_RECLAIM,
system_wq = alloc_workqueue("events", 0, 0);
system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0);
system_long_wq = alloc_workqueue("events_long", 0, 0);
system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, WQ_UNBOUND_MAX_ACTIVE);
system_freezable_wq = alloc_workqueue("events_freezable", WQ_FREEZABLE, 0);
system_power_efficient_wq = alloc_workqueue("events_power_efficient", WQ_POWER_EFFICIENT, 0);
system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient", WQ_FREEZABLE |WQ_POWER_EFFICIENT,0);
WQ_UNBOUND = 1 << 1, /* not bound to any cpu */
WQ_FREEZABLE = 1 << 2, /* freeze during suspend */
WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */
WQ_HIGHPRI = 1 << 4, /* high priority */
WQ_CPU_INTENSIVE = 1 << 5, /* cpu intensive workqueue */
WQ_SYSFS = 1 << 6, /* visible in sysfs, see wq_sysfs_register() */
WQ_POWER_EFFICIENT = 1 << 7,
__WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */
__WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */
WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */
WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */
WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2,
from wowotech:
标有WQ_UNBOUND这个flag的workqueue说明其work的处理不需要绑定在特定的CPU上执行,workqueue需要关联一个系统中的unbound worker thread pool。如果系统中能找到匹配的线程池(根据workqueue的属性(attribute)),那么就选择一个,如果找不到适合的线程池,workqueue就会创建一个worker thread pool来处理work。
WQ_FREEZABLE是一个和电源管理相关的内容。在系统Hibernation或者suspend的时候,有一个步骤就是冻结用户空间的进程以及部分(标注freezable的)内核线程(包括workqueue的worker thread)。标记WQ_FREEZABLE的workqueue需要参与到进程冻结的过程中,worker thread被冻结的时候,会处理完当前所有的work,一旦冻结完成,那么就不会启动新的work的执行,直到进程被解冻。
和WQ_MEM_RECLAIM这个flag相关的概念是rescuer thread。前面我们描述解决并发问题的时候说到:对于A B C D四个work,当正在处理的B work被阻塞后,worker pool会创建一个新的worker thread来处理其他的work,但是,在memory资源比较紧张的时候,创建worker thread未必能够成功,这时候,如果B work是依赖C或者D work的执行结果的时候,系统进入dead lock。这种状态是由于不能创建新的worker thread导致的,如何解决呢?对于每一个标记WQ_MEM_RECLAIM flag的work queue,系统都会创建一个rescuer thread,当发生这种情况的时候,C或者D work会被rescuer thread接手处理,从而解除了dead lock。
WQ_HIGHPRI说明挂入该workqueue的work是属于高优先级的work,需要高优先级(比较低的nice value)的worker thread来处理。
WQ_CPU_INTENSIVE这个flag说明挂入该workqueue的work是属于特别消耗cpu的那一类。为何要提供这样的flag呢?我们还是用老例子来说明。对于A B C D四个work,B是cpu intersive的,当thread正在处理B work的时候,该worker thread一直执行B work,因为它是cpu intensive的,特别吃cpu,这时候,thread pool是不会创建新的worker的,因为当前还有一个worker是running状态,正在处理B work。这时候C Dwork实际上是得不到执行,影响了并发。