completion

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未知,有不可预测的结果。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值