Basic operation of the wait queue in the Linux kernel

Source: Internet
Author: User
Tags mutex

The status of processes in the Linux kernel is mainly in several states:

1. Running state: that the process is running on the CPU, it is occupying the CPU at the moment;

2. Ready state: The process, in addition to the CPU, has been able to run all the conditions, in the ready queue waiting for the scheduler (schedule) scheduling;

3. Blocking state: The process in addition to the lack of CPU, but also lack of other conditions, waiting in the queue to wait for the required conditions;


Describes the organizational structure of the wait queue in the Linux kernel and the various operations on the wait queue:

The wait queue consists of two parts: Waiting queue header + waiting queue;

The structure of the wait queue header:

struct __wait_queue_head

{

spinlock_t lock; Optional lock for securing the wait queue, preventing concurrent access

struct List_head task_list;//for building wait queues

}

typedef struct __WAIT_QUEUE_HEAD wait_queue_head_t;


Wait items in the waiting queue:

struct __wait_queue

{

unsigned int flags;

void *private;

wait_queue_func_t func;

struct List_head task_list;

}

Description of each field:

Flags: Used to determine when a wait condition is met, is the wake-up wait queue for all waiting for that condition

Wait for the process, or just wake up one;

The last of the flags, 1, indicates that only one process in the wait queue is awakened at a time;

The last of the flags is 0, which indicates that all processes waiting for the condition are awakened each time;

#define Wq_flag_exclusive 0x01


Private: The address used to store the struct task_struct;

wait_queue_func_t: The way the process in the queue waits to be awakened;

typedef int (*wait_queue_func_t) (wait_queue_t *wait,unsigned mode,

int flags, void *key)


Structure diagram of the queue waiting for:

650) this.width=650; "src=" Http://s3.51cto.com/wyfs02/M01/4C/E6/wKioL1RHIaGTX3IdAAJkN7SRu2U215.jpg "title=" Wait queue in Linux. png "alt=" wkiol1rhiagtx3idaajkn7sru2u215.jpg "/>


Various operations on the wait queue:

1. Wait for static initialization of the queue header:

#define __WAIT_QUEUE_INITIALIZER (name) {\

. Lock = __spin_lock_unlock (Name.lock),//lock = 1; \

. task_list = {& (name). Task_list, & (name). Task_list}}


#define DECLARE wait_queue_head (name) \

wait_queue_head_t name = __wait_queue_initializer (name)


Therefore, it is possible to complete the definition and initialization of a waiting queue header directly through: Declare_wait_queue_head (name);


2. Wait for the dynamic initialization of the queue header:

void __init_waitqueue_head (wait_queue_head_t *p, struct Lock_class_key *key)

{

Spin_lock_init (&p->lock); Initialize spinlock_t lock lock = 1;

Init_list_head (&p->task_list);//initialization of the chain header;

}

#define INIT_WAITQUEUE_HEAD (name) \

do {\

static struct Lock_class_key __key; \

__init_wait_queue_head ((name), &__key);

} while (0)

So if you use Init_waitqueue_head () for the following uses:

wait_queue_head_t name;

Init_waitqueue_head (&name);


The difference between declare_wait_queue_head () and Init_waitqueue_head ():

1.declare_wait_queue_head is fully implemented with macro definitions, so the program completes the definition and initialization of variables at compile time. and Init_waitqueue_head () is essentially a package for __init_waitqueue_head (). Although a macro definition is used, it is still a function that initializes the variable at the time the program is run;


3. Statically define and initialize wait items in the wait queue:

#define __WAITQUEUE_INITIALIZER (name, Task) {\

. private = task, \

. Func = default_wake_function, \

. task_list = {Null,null}}


#define DECLARE_WAITQUEUE (Name,task) \

wait_queue_t name = __waitquque_initializer (name, Task)

quite with:

wait_queue_t entry;

struct TASK_STRUCT task;

Entry = {

. private = &task,

. Func = Default_wake_function,

. Taks_list = {null, null}

}


4. Dynamic initialization of data items in the wait queue:

static inline void Init_waitqueue_entry (wait_queue_t *p, struct task_struct *task)

{

p->flags = 0;

P->private = task;

P->func = default_wake_function;


}

Usage: wait_queue_t wait;

struct TASK_STRUCT task;

Init_waitqueue_entry (&wait, &task);


5. Use a custom function as a process wakeup in the wait queue:

static inline void Init_waitqueue_func_entry (wait_queue_t *wait,

wait_queue_func_t func)

{

p->flags = 0;

P->private = NULL;

P->func = func;

}


6. Determine if a wait queue is available:

static inline int waitqueue_active (wait_queue_head_t *p)

{

Return! List_empty (&p->task_list);

}

Waitqueue_active () essentially determines whether a wait queue is empty.

If empty, the wait queue is not available to return 0;

If not empty, the wait queue is available to return 1;


7. Add a data item to the wait queue:

static inline void __add_wait_queue (wait_queue_head_t *head,

wait_queue_t *new)

{

List_add (&new->task_list, &head->task_list);

}


void Add_wait_queue (wait_queue_head_t *q, wait_queue_t *wait)

{

unsigned int flags;

Wait->flags &= ~wq_flag_exclusive; Define Wq_flag_exclusive 0x01

Spin_lock_irqsave (&q->lock, flags);

__add_wait_queue (q, wait);

Spin_unlock_irqstore (&q->lock, flags);

}


So Add_wait_queue () is a __add_wait_queue () package, and some measures are added to protect the wait queue against concurrent access, so it is safer to use add_wait_queue () when adding elements to the wait queue;



8. Add one to the wait queue to wake up one data item at a time:

static inline void __add_wait_queue_tail (wait_queue_head_t *head,

wait_queue_t *new)

{

List_add_tail (&new->task_list, &head->task_list);

}


void Add_wait_queue_exclusive (wait_queue_head_t *q, wait_queue_t *wait)

{

unsigned int flags;

Wait->flags |= wq_flag_exclusive;

Spin_lock_irqsave (&q->lock, flags);

__add_wait_queue_tail (q,wait);

Spin_unlock_irqstore (&q->lock, flags);

}


Can see Add_wait_queue (wait_queue_head_t *head, wait_queue_t *wait)

Adds a non-mutex wake-up wait item after each header to the waiting queue;

Add_wait_queue_exclusive (wait_queue_head_t *head, wait_queue_t *wait)

Each time a wait queue is added to the tail of a mutually exclusive wake-up waiting item;



9. Remove a wait item from the wait queue:

static inline void __remove_wait_queue (wait_queue_head_t *head,

wait_queue_t *wait)

{

List_del (&wait->task_list);

}

void Remove_wait_queue (wait_queue_head_t *head, wait_queue_t *wait)

{

unsigned int flags;

Spin_lock_irqsave (&head->lock, flags);

__remove_wait_queue (head,wait);

Spin_unlock_irqstore (&head->lock, flags);

}


Small summary: Add_wait_queue (); Export_symbol (Add_wait_queue);

Add_wait_queue_exclusive (); Export_symbol (add_wait_queue_exclusive);

Remove_wait_queue (); Export_symbol (Remove_wait_queue);

These three operations on the wait queue are functions that the kernel has mentioned,



Processes in the wait queue in the kernel need to be awakened under certain conditions and then added to the ready queue. And how the running process joins it into the wait queue.

The kernel also provides functions that allow us to block processes that are running, and then add them to the wait queue. And wake-up blocking processes in the wait queue.


Block a running process and then add it to a function in the wait queue:

1. void prepare_to_wait (wait_queue_head_t *head, wait_queue_t *wait, int state)

State: Indicates the status of the process

Value task_running, task_interruptible, task_uninterruptible


void Prepare_to_wait (wait_queue_head_t *head, wait_queue_t *wait, int state)

{

unsigned int flags;

Wait->flags &= ~wq_flag_exclusive; Non-mutex wakeup process;

Spin_lock_irqsave (&head->lock, flags);

if (List_empty (&wait->task_list))//if empty, stating that it was not waiting on the column before

__add_wait_queue (head, wait); Add wait entry to the wait queue

Set_current_state (state); Use Set_current_state () to change the running state of a process

Spin_unlock_irqstore (&head->lock, flags);

}


Export_symbol (prepare_to_wait);


void Prepare_to_wait_exclusive (wait_queue_head_t *head,

Wait_queue_head *wait, int state)

{

unsigned int flags;

Wait->flags |= wq_flag_exclusive; Mutex wakeup process;

Spin_lock_irqsave (&head->lock, flags);

if (List_empty (&wait->task_list))

__add_wait_queue_tail (head, wait); Add to Tail

Set_current_state (state);

Spin_unlock_irqstore (&head->lock, flags);

}

Export_symbol (prepare_to_wait_exclusive);


Remove a wait process function from the blocking queue:

void Finish_wait (wait_queue_head_t *head, wait_queue_t *wait)

{

unsigned int flags;

__set_current_state (task_running); Change the current process state to run;

if (!list_empty_careful (&wait->task_list))//Determine the process is in the waiting queue

{

Spin_lock_irqsave (&head->lock, flags);

List_del_init (&wait->task_list);

Spin_unlock_irqstore (&head->lock, flags);

}

}


Export_symbol (finish_wait);



Basic operation of the wait queue in the Linux kernel

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.