先看个使用实例

init_completion(&tx_done_complete);
wait_for_completion_timeout(&tx_done_complete,msecs_to_jiffies(100));
complete(&tx_done_complete);

分析围绕这三个函数进行

init_completion

struct completion {
	unsigned int done;
	wait_queue_head_t wait;
};
void init_completion(struct completion *x)
{
	x->done = 0;
	init_waitqueue_head(&x->wait);
}

wait_for_completion_timeout(&tx_done_complete,msecs_to_jiffies(100));

unsigned long __sched wait_for_completion_timeout(struct completion *x, unsigned long timeout)
{
	return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
}

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);

		__add_wait_queue_entry_tail_exclusive(&x->wait, &wait);
		do {
			if (signal_pending_state(state, current)) {
				timeout = -ERESTARTSYS;
				break;
			}
			__set_current_state(TASK_UNINTERRUPTIBLE);
			timeout = schedule_timeout(timeout);
		} while (!x->done && timeout);
		__remove_wait_queue(&x->wait, &wait);
		if (!x->done)
			return timeout;
	}
	if (x->done != UINT_MAX)
		x->done--;
	return timeout ?: 1;
}
#define __WAITQUEUE_INITIALIZER(name, tsk) {					\
	.private	= tsk,							\
	.func		= default_wake_function,				\
	.entry		= { NULL, NULL } }

#define DECLARE_WAITQUEUE(name, tsk)						\
	struct wait_queue_entry name = __WAITQUEUE_INITIALIZER(name, tsk)
static inline void
__add_wait_queue_entry_tail_exclusive(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
{
	wq_entry->flags |= WQ_FLAG_EXCLUSIVE;
	__add_wait_queue_entry_tail(wq_head, wq_entry);
}

static inline void __add_wait_queue_entry_tail(struct wait_queue_head *wq_head, struct wait_queue_entry *wq_entry)
{
	list_add_tail(&wq_entry->entry, &wq_head->head);
}

设置该线程不可打断,然后主动schedule,让该线程睡眠 

complete

void complete(struct completion *x)
{
	x->done++;
	__wake_up_locked(&x->wait, TASK_NORMAL, 1);
}

void __wake_up_locked(struct wait_queue_head *wq_head, unsigned int mode, int nr)
{
	__wake_up_common(wq_head, mode, nr, 0, NULL, NULL);
}

static int __wake_up_common(struct wait_queue_head *wq_head, unsigned int mode,
			int nr_exclusive, int wake_flags, void *key,
			wait_queue_entry_t *bookmark)
{
	wait_queue_entry_t *curr, *next;
	curr = list_first_entry(&wq_head->head, wait_queue_entry_t, entry);

	list_for_each_entry_safe_from(curr, next, &wq_head->head, entry) {
		ret = curr->func(curr, mode, wake_flags, key);
	}
}

由上面知道curr->func为default_wake_function

int default_wake_function(wait_queue_entry_t *curr, unsigned mode, int wake_flags,void *key)
{
	return try_to_wake_up(curr->private, mode, wake_flags, 1);
}

curr->private=current,然后通过try_to_wake_up设置该进程为运行状态,在下一次的cpu调度中,该进程才有机会运行起来。

 

说到wait_for_completion函数,内核类似的接口有wait_event/poll_wait/wait_event_interruptible等,实现也是通过等待队列,顺便分析下

使用实例

wait_queue_head_t test_queue;flag=0
init_waitqueue_head(&test_queue);
wait_event_interruptible(test_queue, flag);
flag=1&&wake_up_interruptible(&dev->test_queue);

wait_event_interruptible实现 

#define wait_event_interruptible(wq_head, condition)				\
({										\
	int __ret = 0;								\
	might_sleep();								\
	if (!(condition))							\
		__ret = __wait_event_interruptible(wq_head, condition);		\
	__ret;									\
})

#define __wait_event_interruptible(wq_head, condition)				\
	___wait_event(wq_head, condition, TASK_INTERRUPTIBLE, 0, 0,		\
		      schedule())


#define ___wait_event(wq_head, condition, state, exclusive, ret, cmd)		\
({										\
	__label__ __out;							\
	struct wait_queue_entry __wq_entry;					\
	long __ret = ret;	/* explicit shadow */				\
										\
	init_wait_entry(&__wq_entry, exclusive ? WQ_FLAG_EXCLUSIVE : 0);	\
	for (;;) {								\
		long __int = prepare_to_wait_event(&wq_head, &__wq_entry, state);\
										\
		if (condition)							\
			break;							\
										\
		if (___wait_is_interruptible(state) && __int) {			\
			__ret = __int;						\
			goto __out;						\
		}								\
										\
		cmd;								\
	}									\
	finish_wait(&wq_head, &__wq_entry);					\
__out:	__ret;									\
})

wake_up_interruptible实现 

#define wake_up_interruptible(x)	__wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)

void __wake_up(struct wait_queue_head *wq_head, unsigned int mode,
			int nr_exclusive, void *key)
{
	__wake_up_common_lock(wq_head, mode, nr_exclusive, 0, key);
}

static void __wake_up_common_lock(struct wait_queue_head *wq_head, unsigned int mode,int nr_exclusive, int wake_flags, void *key)
{
...
	nr_exclusive = __wake_up_common(wq_head, mode, nr_exclusive, wake_flags, key, &bookmark);
..
}

总结:先让该进程休眠,然后时机成熟后,重新进入运行状态

好吧,看完后发现套路都一样的。

Logo

更多推荐