/* Must be called with
the spinlock in the wait_queue_head_t held.*/ static inline void
remove_wait_queue_locked(wait_queue_head_t *q,
wait_queue_t * wait) {
__remove_wait_queue(q, wait); } Locked系列适用于在已经获得锁的情况下调用,通常用于信号
量后者complete系列函数中。
2.3.3
prepare_to_wait和finish_wait /* * Used to distinguish between sync
and async io wait context: * sync i/o typically specifies a NULL
wait queue entry or a wait * queue entry bound to a task (current
task) to wake up. * aio specifies a wait queue entry with an async
notification * callback routine, not associated with any task. */ #define
is_sync_wait(wait) (!(wait) || ((wait)->private)) 同步io等待将唤醒
当前进程,异步io等待和当前进程无关,时间到后执行安装的回调函数
void fastcall prepare_to_wait(wait_queue_head_t
*q, wait_queue_t *wait, int state) { unsigned long flags;
3.3
wait_event_interruptible #define __wait_event_interruptible(wq,
condition, ret) \ do {
\ DEFINE_WAIT(__wait);
\
\ for (;;) {
\
prepare_to_wait(&wq, &__wait, TASK_INTERRUPTIBLE); \
if (condition) \
break;
\ if (!signal_pending(current)) {
\ schedule();
\ continue;
\ }
\ ret = -ERESTARTSYS;
\ break;
\ }
\ finish_wait(&wq,
&__wait); \ } while (0)
/** *
wait_event_interruptible - sleep until a condition gets true * @wq:
the waitqueue to wait on * @condition: a C expression for the event
to wait for * * The process is put to sleep (TASK_INTERRUPTIBLE)
until the * @condition evaluates to true or a signal is received. *
The @condition is checked each time the waitqueue @wq is woken up. * *
wake_up() has to be called after changing any variable that could *
change the result of the wait condition. * * The function will
return -ERESTARTSYS if it was interrupted by a * signal and 0 if
@condition evaluated to true. */ #define
wait_event_interruptible(wq, condition) \ ({
\
int __ret = 0; \
if (!(condition)) \
__wait_event_interruptible(wq, condition, __ret); \
__ret;
\ })
3.4 wait_event_interruptible_timeout #define
__wait_event_interruptible_timeout(wq,condition,ret) \ do {
\ DEFINE_WAIT(__wait);
\ \ for (;;) {
\
prepare_to_wait(&wq,&__wait,TASK_INTERRUPTIBLE); \
if (condition) \
break; \
if(!signal_pending(current)) { \
// 当前进程无信号需要处理 ret = schedule_timeout(ret); \
if(!ret) \
break; //时间片用完唤醒 \
continue; \ . }
\ ret = _ERESTARTSYS; //被信号唤醒
\ break; \
} \
finish_wait(&wq,&__wait); \ } while (0)
\kernel
\sched.c /* * The core wakeup function. Non-exclusive wakeups
(nr_exclusive == 0) just * wake everything up. If it's an exclusive
wakeup (nr_exclusive == small +ve * number) then we wake all the
non-exclusive tasks and one exclusive task. * * There are
circumstances in which we can try to wake a task which has already *
started to run but is not in state TASK_RUNNING. try_to_wake_up()
returns * zero in this (rare) case, and we handle it by continuing to
scan the queue. */ static void __wake_up_common(wait_queue_head_t
*q, unsigned int mode, int nr_exclusive,
int sync, void *key) { struct list_head *tmp, *next;
/** * __wake_up - wake up threads blocked on a
waitqueue. * @q: the waitqueue * @mode: which threads *
@nr_exclusive: how many wake-one or wake-many threads to wake up *
@key: is directly passed to the wakeup function */ void fastcall
__wake_up(wait_queue_head_t *q, unsigned int mode, int nr_exclusive,
void *key) { unsigned long flags;