Linux下wait_for_completion函数分析
先看个使用实例init_completion(&tx_done_complete);wait_for_completion_timeout(&tx_done_complete,msecs_to_jiffies(100));complete(&tx_done_complete);分析围绕这三个函数进行init_completionstruct completion {unsi
·
先看个使用实例
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);
..
}
总结:先让该进程休眠,然后时机成熟后,重新进入运行状态
好吧,看完后发现套路都一样的。
更多推荐
已为社区贡献6条内容
所有评论(0)