1 数据结构
struct completion {
unsigned int done;
wait_queue_head_t wait;//等待队列头
};
2 初始化
2.1 动态
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_waitqueue_head(&x->wait);//初始化等待列队头
}
done为0 表示completion不可用。
2.2 静态
#define DECLARE_COMPLETION(work) \
struct completion work = COMPLETION_INITIALIZER(work)
#define COMPLETION_INITIALIZER(work) \
{ 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }
2.3 重新启动
#define INIT_COMPLETION(x) ((x).done = 0)
3 获取completion
3.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) {
//不可用,初始化等待队列
DECLARE_WAITQUEUE(wait, current);
//将等待队列添加到等待队列头的list,WQ_FLAG_EXCLUSIVE表示表示等待进程想要被独占地唤醒
__add_wait_queue_tail_exclusive(&x->wait, &wait);
do {
//设置当前进程为TASK_UNINTERRUPTIBLE
if (signal_pending_state(state, current)) {
timeout = -ERESTARTSYS;
break;
}
__set_current_state(state);
spin_unlock_irq(&x->wait.lock);
//执行schedule_timeout()
timeout = action(timeout);
spin_lock_irq(&x->wait.lock);
} while (!x->done && timeout);
//获取到completion,删除等待队列
__remove_wait_queue(&x->wait, &wait);
//已经超时,还没获取到,返回超时
if (!x->done)
return timeout;
}
x->done--;
return timeout ?: 1;
}
timeout = action(timeout);如果超时返回0,否则返回剩余的time。
do_wait_for_common()的返回值取决于done和timeout。如果action(timeout)已经超时,还没获取到completion,return timeout(0)。获取到completion,未超时return timeout,否则return 1。最后返回值:
0:超时,获取失败。
1:超时,获取成功。
timeout(非0值),获取成功。如果刚好timeout == 1,和上一种情况不能区分。
static inline int signal_pending_state(long state, struct task_struct *p)
{
//不可被中断或者未设置TASK_WAKEKILL(可被致命信号kill)
if (!(state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL)))
return 0;
//没有待处理的信号。TIF_SIGPENDING置位,表示该进程有信号需要处理
if (!signal_pending(p))
return 0;
/*设置了TASK_INTERRUPTIBLE,或者设置TASK_WAKEKILL,并且有待处理的信号就走到了这里。TASK_INTERRUPTIBLE表示可以被信号中断,设置了它,这里会返回非0值;只设置了TASK_WAKEKILL,如果检测到SIGKILL信号也会返回非0值。*/
return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p);
}
其他的获取函数类似:
extern void wait_for_completion_io(struct completion *);
schedule用的是io_schedule_timeout()。
extern int wait_for_completion_interruptible(struct completion *x);
state为TASK_INTERRUPTIBLE。
extern int wait_for_completion_killable(struct completion *x);
state为TASK_KILLABLE。
extern unsigned long wait_for_completion_timeout(struct completion *x,
unsigned long timeout);
带有timeout参数的wait,同wait_for_common()。
extern unsigned long wait_for_completion_io_timeout(struct completion *x,
unsigned long timeout);
带有timeout参数的wait io,同wait_for_completion_io()。
extern long wait_for_completion_interruptible_timeout(
struct completion *x, unsigned long timeout);
带有timeout参数的wait,同wait_for_completion_interruptible()。
extern long wait_for_completion_killable_timeout(
struct completion *x, unsigned long timeout);
带有timeout参数的wait,同wait_for_completion_killable()。
3.1 try_wait_for_completion()
尝试获取completion。bool try_wait_for_completion(struct completion *x)
{
unsigned long flags;
int ret = 1;
spin_lock_irqsave(&x->wait.lock, flags);
if (!x->done)
ret = 0;
else
x->done--;
spin_unlock_irqrestore(&x->wait.lock, flags);
return ret;
}
带try的一般都不会休眠。
4 释放completion
4.1 complete()
void complete(struct completion *x)
{
unsigned long flags;
spin_lock_irqsave(&x->wait.lock, flags);
x->done++;
//只wakeup 一个exclusive task
__wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL);
spin_unlock_irqrestore(&x->wait.lock, flags);
}
4.2 completion_done()
test completion是否有waiter,如果有(wait_for_completion() in progress)返回0,如果没有返回1。bool completion_done(struct completion *x)
{
unsigned long flags;
int ret = 1;
spin_lock_irqsave(&x->wait.lock, flags);
if (!x->done)
ret = 0;
spin_unlock_irqrestore(&x->wait.lock, flags);
return ret;
}
4.3 complete_all()
能够唤醒所有等待的进程。void complete_all(struct completion *x)
{
unsigned long flags;
spin_lock_irqsave(&x->wait.lock, flags);
x->done += UINT_MAX/2;
__wake_up_common(&x->wait, TASK_NORMAL, 0, 0, NULL);
spin_unlock_irqrestore(&x->wait.lock, flags);
}
如果使用了该函数,必须调用INIT_COMPLETION(completion)重新初始化;否则,done未知,有不可预测的结果。