/* 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;