1. Data structure
1.1 Waiting Queue Header
1 struct __wait_queue_head {2 Lock ; 3 struct List_head task_list; 4 }; 5 struct __wait_queue_head wait_queue_head_t;
Initialize the wait queue header
1 #define __wait_queue_head_initializer (name) { 2 . Lock = __spin_lock_unlocked (name. Lock), 3 . task_list = {& (name). Task_list, &(name). Task_list} }45#define6 wait_queue_head_t name = __wait_queue_head_ INITIALIZER (name)
1.2 Waiting queue
1typedefstruct__wait_queue wait_queue_t;2typedefint(*wait_queue_func_t) (wait_queue_t *wait, unsigned mode,intSyncvoid*key);3 intDefault_wake_function (wait_queue_t *wait, unsigned mode,intSyncvoid*key);4 5 struct__wait_queue {6Unsignedintflags;7 #defineWq_flag_exclusive 0x018 void*Private;9 wait_queue_func_t func;Ten structList_head task_list; One};
Initializing the wait queue
1 #define __waitqueue_initializer (name, tsk) { 2 . Private = tsk, 3 . Func = default_wake_function, 4 . task_list = {null, NULL}}56#define declare_ Waitqueue (name, tsk) 7 wait_queue_t name = __waitqueue_initializer (name, tsk)
The task_list waiting queue joins the task_list linked list waiting for the queue header. The wait_queue_func_t is typically assigned the following default handler:
1 int int Sync, 2 void *key)3{4 return try_to_wake_up (curr-> Private , mode, sync); 5 }
1.3 Add/Remove wait queues
1 StaticInlinevoid__add_wait_queue (wait_queue_head_t *head, wait_queue_t *New)2 {3List_add (&New->task_list, &head->task_list);4 }5 6 StaticInlinevoid__remove_wait_queue (wait_queue_head_t *Head,7wait_queue_t *Old )8 {9List_del (&old->task_list);Ten}
2 Waiting events
Call the following four macro wait events, waiting for the first parameter as the waiting queue header to wake up, the second parameter condition must be satisfied, otherwise continue to block.
The difference between wait_event () and wait_event_interruptible () is that the latter can be interrupted by a signal, while the former cannot.
The addition of a timeout macro means that the blocking wait time-out, in Jiffy, is returned when timeout arrives, regardless of whether condition is satisfied.
1 #define 2 #define wait_event_timeout (Wq, condition, timeout) 3#define Wait_event_ Interruptible (Wq, condition) 4#define wait_event_interruptible_timeout (Wq, condition, Timeout
The following is an example of wait_event () to analyze the execution process
1 #defineWait_event (Wq, condition)2 Do { 3 if(condition)4 Break; 5 __wait_event (Wq, condition); 6} while(0)7 #define__wait_event (Wq, condition)8 Do { 9 define_wait (__wait); Ten One for (;;) { APrepare_to_wait (&WQ, &__wait, task_uninterruptible); - if(condition) - Break; the schedule (); - } -Finish_wait (&WQ, &__wait); -} while(0)
wait_event (Wq, condition)
wait_event (Wq, condition)-__wait_event (Wq, condition); -define_wait (__wait); -->prepare_to_wait (&WQ, &__wait, task_uninterruptible); -->__add_wait_queue (q, wait);//Add the wait queue to the wait queue header-set_current_state (state); -->schedule ();//switch to another process-be awakened to switch back-->finish_wait (&WQ, &__wait); -__set_current_state (task_running); -->list_del_init (&wait->task_list);//to delete a wake-up wait queue
Note the above define_wait (__WAIT) macro expands as follows
1 #define define_wait (name) 2 wait_queue_t name = { 3 . private = current, 4 . Func = autoremove_wake_function, 5 . Task_list = List_head_init ((name). Task_list), 6 }
1 int autoremove_wake_function (wait _queue_t *wait, unsigned mode, int sync, void *key) 2 { 3 int ret = default_wake_function (wait, mode, sync, key); 4 5 if 6 list_del_init (&wait-& Gt task_list); 7 return RET; 8 }
autoremove_wake_function
3. Wake-up queue
WAKE_UP () can wake up processes in task_uninterruptible and task_interruptible, while wake_up_interruptible can only wake processes that are in task_interruptible.
#define wake_up (x) __wake_up (x, task_uninterruptible | Task_interruptible, 1, NULL)#define wake_up_interruptible (x) __wake_up (x, task_interruptible, 1, NULL)
The following is an example of wake_up (),
1 wake_up (x) 2 1 , NULL) 3 0, key); // Wake up all wait queues in the list of waiting queue headers
The key is the __wake_up_common () function
1 /*2 * The core wakeup function. Non-exclusive wakeups (nr_exclusive = = 0) Just3 * Wake everything up. If it ' s an exclusive wakeup (nr_exclusive = = Small +ve4 * number) Then we wake all the non-exclusive tasks and one exclusive task.5 *6 * There is circumstances in which we can try to wake a task which have already7 * Started to run, but isn't in the state task_running. TRY_TO_WAKE_UP () returns8 * Zero in this (rare) case, and we handle it by continuing to scan the queue.9 */Ten Static void__wake_up_common (wait_queue_head_t *q, unsignedintmode, One intNr_exclusive,intSyncvoid*key) A { - structList_head *tmp, *Next; - theList_for_each_safe (TMP, Next, &q->task_list) { -wait_queue_t *curr =list_entry (TMP, wait_queue_t, task_list); -Unsigned flags = curr->flags; - + if(Curr->func (curr, mode, Sync, key) && -(Flags & wq_flag_exclusive) &&!--nr_exclusive) + Break; A } at}
The curr->func is a pointer to the Autoremove_wake_function () function.
The wake process is performed specifically in the TRY_TO_WAKE_UP (curr->private, mode, sync) function, which is more complex to wake up and has time to analyze later.
It can be simply understood that the wait queue in 2 wait_event () is woken up to continue execution after the function has been executed.
Linux wait queue and wake up