结构体
D:\linux31026\include\linux\completion.hstruct completion {
unsigned int done;
wait_queue_head_t wait;
};
done: 完成计数,0 表示未完成, 大于0表示等待的事件已经完成。
wait: 存放等待该事件完成的进程队列。
定义/初始化
init_completion
动态分配的completionstatic inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);
}
DECLARE_COMPLETION
#define COMPLETION_INITIALIZER(work) \
{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
#define DECLARE_COMPLETION(work) \
struct completion work = COMPLETION_INITIALIZER(work)
INIT_COMPLETION
- reinitialize a completion structure/* This macro should be used to reinitialize a completion structure so it can
* be reused. This is especially important after complete_all() is used.
*/
#define INIT_COMPLETION(x) ((x).done = 0)
D:\linux31026\kernel\sched\core.c
API
/* 不超时,不可中断 */
wait_for_completion
wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
wait_for_completion_interruptible_timeout
/* 会超时,可中断 *//*
返回值
-ERESTARTSYS if interrupted
0 if timed out,
positive (at least 1, or number of jiffies left till timeout) if completed.
*/
wait_for_completion_interruptible_timeout
wait_for_common(x, timeout, TASK_INTERRUPTIBLE);
代码分析
wait_for_common(struct completion *x, long timeout, int state)
__wait_for_common(x, schedule_timeout, timeout, state);
do_wait_for_common(x, action, timeout, state);
static inline long __sched
do_wait_for_common(struct completion *x,
long (*action)(long), long timeout, int state)
{
/* done 初始化为0, 表示未完成 */
if (!x->done) {
/* 初始化一个wait_queue_t wait,
wait_queue_t->private = current
wait_queue_t->func = default_wake_function
wait_queue_t->task_list = { NULL, NULL }
*/
DECLARE_WAITQUEUE(wait, current);
/* 将这个wait加入到完成量的完成量等待队列wait_queue_head_t */
__add_wait_queue_tail_exclusive(&x->wait, &wait);
do {
/* 当前进程被interrupted,也就是收到信号SIGKILL,返回,返回值是-ERESTARTSYS */
if (signal_pending_state(state, current)) {
timeout = -ERESTARTSYS;
break;
}
/* 设置当前进程状态,是否可以被interrupt,等待 */
__set_current_state(state);
/* 释放lock */
spin_unlock_irq(&x->wait.lock);
/* 调度,也就是调用schedule_timeout() --> schedule() */
timeout = action(timeout);
/* timeout超时,或者schedule() 返回,回到当前进程,释放lock*/
spin_lock_irq(&x->wait.lock);
/* 如果done > 0, 或者timeout超时,二者满足其一,则退出循环
如果二者都不满足,重新获得lock,重新调度。
*/
} while (!x->done && timeout);
/* 从完成量等待队列删除 */
__remove_wait_queue(&x->wait, &wait);
if (!x->done)
return timeout;
}
x->done--;
return timeout ?: 1;
}
complete
x->done++;
__wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL);
curr->func(curr, mode, wake_flags, key)
curr->func == default_wake_function, see __WAITQUEUE_INITIALIZER
try_to_wake_up