定义
数据结构如下:
struct completion {
unsigned int done; //指示等待的事件是否完成。初始化时为0。
//如果为0,则表示等待的事件未完成。大于0表示等待的事件已经完成
wait_queue_head_t wait;//存放等待该事件完成的进程队列
};
初始化
1) init_completion(&completion)
init_completion()会将done字段初始化为0,wait字段的自旋锁为未锁,等待队列为空。
这说明调用该完成量的进程必须等待某事件完成(即另外一进程必须先调用completiom()唤醒该完成量)。
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);
}
#define init_waitqueue_head(q) \
do { \
static struct lock_class_key __key; \
\
__init_waitqueue_head((q), #q, &__key); \
} while (0)
void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
spin_lock_init(&q->lock);
lockdep_set_class_and_name(&q->lock, key, name);
INIT_LIST_HEAD(&q->task_list);
}
2) DECLARE_COMPLETION(completion);
直接定义并初始化completion完成量,效果等同于以上定义方式
等待完成量
1) wait_for_completion()函数
void __sched wait_for_completion(struct completion *x)
{
wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
static long __sched
wait_for_common(struct completion *x, long timeout, int state)
{
return __wait_for_common(x, schedule_timeout, timeout, state);
}
static inline long __sched
__wait_for_common(struct completion *x,
long (*action)(long), long timeout, int state)
{
might_sleep();
spin_lock_irq(&x->wait.lock);
timeout = do_wait_for_common(x, action, timeout, state);
spin_unlock_irq(&x->wait.lock);
return timeout;
}
static inline long __sched
do_wait_for_common(struct completion *x,
long (*action)(long), long timeout, int state)
{
if (!x->done) {
/*该函数相当于信号量中的down()操作。不过在操作中对使用其自身的自旋锁。如果done为0,
则说明等待的事件没有完成,则调用DECLARE_WAITQUEUE()定义等待队列wait并将当前进程
添加进等待队列wait。然后将wait添加进该完成量的等待队列的末尾,进入循环。
设置当前进程为不可中断状态(TASK_UNINTERRUPTIBLE),释放自旋锁并让当前进程进入睡眠状态。
一旦进程被调度唤醒据又获得自旋锁并查看等待的事件是否完成。如果完成(大于0),
则从完成量的等待队列中删除等待的进程,并自减*/
DECLARE_WAITQUEUE(wait, current);
__add_wait_queue_tail_exclusive(&x->wait, &wait);
do {
if (signal_pending_state(state, current)) {
timeout = -ERESTARTSYS;
break;
}
__set_current_state(state);
spin_unlock_irq(&x->wait.lock);
timeout = action(timeout);
spin_lock_irq(&x->wait.lock);
} while (!x->done && timeout);
__remove_wait_queue(&x->wait, &wait);
if (!x->done)
return timeout;
}
x->done--;
return timeout ?: 1;
}
2) wait_for_completion_timeout()
也是等待完成量。与wait_for_completion()最大的区别是它等待超时的情况下返回。也就是说如果经过给定的时间该完成量还没有被唤醒,就直接返回。这样最大的好处是经过一定的时间该进程已经不需要等待某事件,那么就可以直接被唤醒继续执行。
3) wait_for_completion_interruptible()
这个函数的等待完成量的方式是可以被信号打断的。如果当前进程收到 如果收到TIF_SIGPENDING信号,则等待该完成量的进程会被从等待队列中删除,并返回ERESTARTSYS
4) wait_for_completion_interruptible_timeout()
可中断的并且可超时返回的等待完成量。
唤醒完成量
completion()函数 : 唤醒所有等待给完成量的进程