Implementation and use of Wait_queue

Source: Internet
Author: User
Tags data structures sleep
/*************************************************************/
Data structures introduced: Wait_queue_head and Wait_queue
/*************************************************************/
struct __wait_queue_head {
spinlock_t lock;
struct List_head task_list;
};
typedef struct __WAIT_QUEUE_HEAD wait_queue_head_t;

struct __wait_queue {
unsigned int flags;
void *private;
wait_queue_func_t func;
struct List_head task_list;
};

/*************************************************************/
Wait_queue: What kind of problem is solved?
The current process waits for an event to occur: If a condition is true
Set the current process to: interruptible or uninterruptible
The current process is added to the linked list of the wait_queue_head associated with this time through wait_queue;

When an event occurs, or when the condition is established: Find the process of sleep on the event by Wait_queue_head
and awaken it;
/*************************************************************/
Init_waitqueue_head (&epfile->wait);

Wait_event_interruptible (epfile->wait, (ep = Epfile->ep));

WAKE_UP (&epfile->wait);

static inline int waitqueue_active (wait_queue_head_t *q)
{
Return!list_empty (&q->task_list);
}

/*************************************************************/
Take a specific wait_queue in F_FS.C as an example: look at the interfaces used
The arguments for the action function are: wait_queue_head_t, not Wait_queue
F_FS.C (drivers\usb\gadget\function): ret = wait_event_interruptible (epfile->wait, (ep = Epfile->ep));
F_FS.C (drivers\usb\gadget\function): Init_waitqueue_head (&epfile->wait);
F_FS.C (drivers\usb\gadget\function): Waitqueue_active (&epfile->wait));
F_FS.C (drivers\usb\gadget\function): Wake_up (&epfile->wait);

/*************************************************************/
#define INIT_WAITQUEUE_HEAD (q) \
do {\
static struct Lock_class_key __key; \
\
__init_waitqueue_head ((q), #q, &__key); \
} while (0)


void __init_waitqueue_head (wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
Spin_lock_init (&q->lock);
Lockdep_set_class_and_name (&q->lock, key, name);
Init_list_head (&q->task_list);
}


struct Ffs_epfile {
wait_queue_head_t wait;
}

/*************************************************************/
How to make the current process sleep?
/*************************************************************/
/
Wait_event_interruptible (epfile->wait, (ep = Epfile->ep));
/**
* 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 are woken up.
*
* WAKE_UP () have to is called after changing any variable that could
* Change the result of the wait condition.
*
* The function would return-erestartsys if it is interrupted by a
* Signal and 0 if @condition evaluated to true.
*/
#define WAIT_EVENT_INTERRUPTIBLE (Wq, condition) \
({                                    \
int __ret = 0; \
Might_sleep (); \
if (! ( condition)) \
__ret = __wait_event_interruptible (Wq, condition); \
__ret; \
})

#define __WAIT_EVENT_INTERRUPTIBLE (Wq, condition) \
___wait_event (Wq, condition, task_interruptible, 0, 0, \
Schedule ())


#define ___wait_event (Wq, condition, State, exclusive, ret, cmd) \
({                                    \
__label__ __out; \
wait_queue_t __wait; [This only introduced the wait_queue_t, the user sees only wait_queue_head]\
Long __ret = ret; /* Explicit Shadow */\
\
Init_list_head (&__wait.task_list); \
if (exclusive) \
__wait.flags = wq_flag_exclusive; \
else \
__wait.flags = 0; \
\
for (;;) {                            \
Long __int = Prepare_to_wait_event (&wq, &__wait, state); \
\
if (condition) \
Break \
cmd \
}                                \
Finish_wait (&wq, &__wait); \
__out: __ret; \
})


Long Prepare_to_wait_event (wait_queue_head_t *q, wait_queue_t *wait, int state)
{
unsigned long flags;

if (Signal_pending_state (state, current))
Return-erestartsys;

Wait->private = current;
Wait->func = autoremove_wake_function;

Spin_lock_irqsave (&q->lock, flags);
if (List_empty (&wait->task_list)) {//[says Wait_queue task_list is empty and not said Wait_queue_head]
if (Wait->flags & wq_flag_exclusive)
__add_wait_queue_tail (q, wait);
Else
__add_wait_queue (q, wait);
}
Set_current_state (state);
Spin_unlock_irqrestore (&q->lock, flags);

return 0;
}

F_FS.C (drivers\usb\gadget\function): Wake_up (&epfile->wait);
/*************************************************************/
How to wake up the sleep process?
F_FS.C (drivers\usb\gadget\function): Wake_up (&epfile->wait);
/*************************************************************/
#define WAKE_UP (x) __wake_up (x, Task_normal, 1, NULL)
void __wake_up (wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, void *key)
{
unsigned long flags;

Spin_lock_irqsave (&q->lock, flags);
__wake_up_common (q, Mode, nr_exclusive, 0, key);
Spin_unlock_irqrestore (&q->lock, flags);
}

static void __wake_up_common (wait_queue_head_t *q, unsigned int mode,
int nr_exclusive, int wake_flags, void *key)
{
wait_queue_t *curr, *next;

List_for_each_entry_safe (Curr, Next, &q->task_list, Task_list) {
Unsigned flags = curr->flags;

if (Curr->func (curr, mode, Wake_flags, key) &&
(Flags & wq_flag_exclusive) &&!--nr_exclusive)
Break
}
}

int autoremove_wake_function (wait_queue_t *wait, unsigned mode, int sync, void *key)
{
int ret = default_wake_function (wait, mode, sync, key);

if (ret)
List_del_init (&wait->task_list);
return ret;
}

int default_wake_function (wait_queue_t *curr, unsigned mode, int wake_flags,
void *key)
{
Return try_to_wake_up (curr->private, mode, wake_flags);
}

Try_to_wake_up->ttwu_do_activate->ttwu_do_wakeup:p->state = task_running;
static void Ttwu_queue (struct task_struct *p, int cpu)
{
struct RQ *rq = CPU_RQ (CPU);
Raw_spin_lock (&rq->lock);
Ttwu_do_activate (RQ, p, 0);
Raw_spin_unlock (&rq->lock);
}
static void
Ttwu_do_wakeup (struct RQ *rq, struct task_struct *p, int wake_flags)
{
Check_preempt_curr (RQ, p, wake_flags);
Trace_sched_wakeup (P, true);

P->state = task_running;
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.