Declare_waitqueue Adding a process to the waiting queue

Source: Internet
Author: User
Tags goto readable semaphore sleep
#define   declare_waitqueue (name,   tsk)       / 
wait_queue_t   name     =__waitqueue_initializer (name ,   tsk) 
#define   __waitqueue_initializer (Name,tsk)   {task:  tsk,  task_list:  {  Null,null},  __waitqueue_debug_ini (name)} 


Reference: http://blog.csdn.net/hzn407487204/article/details/5489507

Http://www.360doc.com/content/10/1009/17/1317564_59632874.shtml
It is explained by:
The wait queue item is initialized to the corresponding task structure through the Declare_waitqueue macro, and the related pointers for the connection are set to null. Debugging-related code was added.


The process adds itself to a wait queue by performing the following steps:
1) Call Declare_waitqueue () to create an item waiting for the queue;
2) call Add_wait_queue () to add itself to the wait queue. The queue wakes the process as it waits for the condition to be met. Write the relevant code elsewhere, and when the event occurs, the peer queue performs the WAKE_UP () operation.
3) Change the process state to: task_interruptible or task_uninterruptible.
4) If the status is set to Task_interruptible, the signal wakes the process. This is a pseudo-wakeup (wakeup is not caused by an event), so the signal is checked and processed.
5) Check whether the condition is true, it is not necessary to hibernate, if not true, then call scheduled ().
6) When the process is awakened, it checks to see if the condition is true again. Really quit the loop, otherwise call scheduled () again and repeat this step.
7) After the condition is satisfied, the process sets itself to task_running and exits through Remove_wait_queue ().

Join Waiting Queue | Add_wait_queue () | add_wait_queue_exclusive ()

Kernel: 2.6.24
Add_wait_queue () is used to add a process to the wait queue, which, after acquiring the necessary spin lock, uses the __add_wait_queue () function to complete the queue add work.

__add_wait_queue () is defined as:

static inline void __add_wait_queue (wait_queue_head_t *head, wait_queue_t *new)
{
    List_add (&new->task _list, &head->task_list);//list_add () is the standard set up queue bidirectional list function.

}

There is also a add_wait_queue_exclusive () function that works like Add_wait_queue () but inserts the process into the tail of the queue and also sets the Wq_exclusive flag.
Add_wait_queue_exclusive () is defined as:

void Fastcall add_wait_queue_exclusive (wait_queue_head_t *q, wait_queue_t *wait)
{
    unsigned long flags;


    Wait->flags |= wq_flag_exclusive;
    Spin_lock_irqsave (&q->lock, flags);
    __add_wait_queue_tail (q, wait);
    Spin_unlock_irqrestore (&q->lock, flags);
}

The __add_wait_queue_tail () function is defined as:

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);
}


List_add_tail () is defined as:


/**
 * List_add_tail-add A new entry
 * @new: New entry to be added
 * @head: List hea D to add it before
 *
 * Insert A new entry before the specified head.
 * This was useful for implementing queues.
 *
/static inline void List_add_tail (struct list_head *new, struct list_head *head)
{
    __list_add (new, Head->prev, head);
}


Thus, adding to the end of the queue is also called the __list_add () function, except that the 2nd parameter and the 3rd parameter are changed sequentially with the original parameter added to the queue header.

Wait_event_interruptible (). The function modifies the state of the task to task_interruptible, which means that the process will not continue to run until it wakes up and is added to the wait queue Wq.

In Wait_event_interruptible () first determine whether condition is satisfied, if it is directly return 0, otherwise call __wait_event_interruptible (), and use __ret to store the return value

---------------------------------------------------------------

#definewait_event_interruptible(Wq, condition)/

({                                                       /

int __ret = 0; /

if (! ( condition))/

__wait_event_interruptible(Wq, condition, __ret);

__ret; /

})

Wait_event_interruptible ()-__wait_event_interruptible ()

__wait_event_interruptible () first defines and initializes a wait_queue_t variable __wait, where the data is current and the __wait is enqueued.


In an infinite loop, __wait_event_interruptible () resets the process to an interruptible suspend state, repeatedly checking if the condition is set up, if
Then exits, if not established, continues to hibernate; After the condition is satisfied, the running state of the process is set to run, and the __wait is purged from the waiting queue, so that the process can be scheduled to run. If the process currently has
Asynchronous signal (POSIX), the-erestartsys is returned.



Next is a case:

Oneself in See Globalfifo drive time to see not very understand, some places did not understand, today was fortunate to see a post on the forum, I did not understand all understand, excerpt down for reference.

============================= I'm a split line ==============================

Lz:

/*GLOBALFIFO Read function */
Static ssize_t Globalfifo_read (Structfile*filp,char __user *buf,size_tcount,
loff_t *ppos)
{
int ret;
struct globalfifo_dev*dev= filp->private_data;//Get the device struct body pointer

Declare_waitqueue (wait, current);//define Wait queue


Down (&DEV->SEM);//This function contains the action to go to sleep.

Add_wait_queue (&dev->r_wait,&wait);//Why enter the Read wait queue header after acquiring the semaphore.


/* Wait for FIFO non-empty */
while (dev->current_len== 0)
{
if (filp->f_flags&o_nonblock)//?

{
RET =-eagain;//?

Goto out;
}
__set_current_state (task_interruptible);//change process status to sleep

Up (&dev->sem);

Schedule ();//dispatch other Process execution

if (signal_pending (current))//?

If it's because the signal wakes up,

{
RET =-Erestartsys;
Goto Out2;
}

Down (&DEV->SEM);
}

/* Copy to User space */
if (count> Dev->current_len)
Count= dev->current_len;

if (Copy_to_user (buf, Dev->mem,count))
{
RET =-efault;
Goto out;
}
Else
{
memcpy (Dev->mem, Dev->mem +count, dev->current_len-count);//fifo Data move forward

dev->current_len-=count;//Effective data length reduction

PRINTK (kern_info "read%d bytes (s), current_len:%d\n", Count, Dev->current_len);

Wake_up_interruptible (&dev->w_wait);//wake-up Write wait queue


RET =count;
}
Out:up (&dev->sem);//Release signal volume

Out2:remove_wait_queue (&dev->w_wait,&wait);//Remove from the secondary wait queue header

Set_current_state (task_running);
return ret;
}

I do not understand the blocking operation can be combined with this practical example.
I can only understand: from going to sleep wait_event () to Sleep Wake Wake_up ()
But there is no wait_event () correlation function, why.
What's more, the sleep, wait queue, and semaphore are all related. Read all the dizzy.

=================================== I'm a split line ====================================

Reply 1:

First of all, we should grasp the idea of the program in general, the signal volume here involves two functions: here you give the reading function, there is a write function you did not give (Globalfifo_write). The GLOBALFIFO_DEV structure represents the underlying driven hardware (which may simply represent a ring FIFO for software simulations), which clearly defines two process sleep queues: r_wait,
W_wait, a process sleep queue that reads data, and a sleep queue for a write data process. Because the read and write process is the same area, so this area becomes what we usually call "critical area", the read and write process can not access the area at the same time, otherwise it is likely to cause inconsistent system state, which I think should be easy to understand, then the purpose of Dev->sem semaphore is to create this " Critical section ", regardless of whether the read-write process enters the shared area for operation (read or write), you must obtain exclusive access permissions, which is the purpose of the following statement:
Down (&DEV->SEM); This function contains the action of going to sleep.
As you ask, this down function puts the current process to sleep, and when a write process is working on the shared area, the read process (under the down call) is suspended (that is, going to sleep).

The wake of the process is the responsibility of the write process, as in the following statement after you give the Globalfifo_read function:
Wake_up_interruptible (&dev->w_wait);
If you look at the corresponding Globalfifo_write function, the following statement will be present in the Globalfifo_write function:
Wake_up_interruptible (&dev->r_wait);(personal Understanding here should be by up (&dev->sem) wake process, wake_up should be wake-up sleep_on caused by process sleep, welcome to shoot Bricks)
That is, when a write process finishes writing the data, its wake may wait for the read process, at which point the Globalfifo_read function
will continue to execute from the following statement.
Add_wait_queue (&dev->r_wait, &wait); Why go to the Read wait queue header after acquiring the semaphore.
As you asked, why would you want to suspend the current process in advance to the r_wait queue, since we need to explicitly encode
Putting a process into sleep (when countless data is readable) is basically consistent with the kernel putting the current process to sleep when the down function is called, unlike when the kernel puts the process to sleep when the resource is unavailable, and here we
The process is put to sleep based on active encoding with or without data, because when there is no data read, and the user does not set the NON_BLOCK flag bit, we can not continue to consume the CPU, we need to give up the CPU, so that the write process may write to the shared area, so on the one hand you can see when actively let the process put into sleep , you must also call the UP function to release the semaphore, allowing the write process to enter the critical section to write the data, and on the other hand execute the following code to explicitly place the process on sleep:
__set_current_state (task_interruptible); Change the status of the process to be interrupted sleep
Up (&dev->sem);

Schedule (); Scheduling other Process Execution

The schedule function dispatches the execution of other processes, noting that the current process is set to the task_interruptible state to interrupt sleep, and that the process of this state is excluded from the process scheduling qualification until it is awakened (that is, into the task_running state), as previously proposed, This wakeup will be performed by a process that is awakened by the Globalfifo_write function (or some interrupt function).
In addition to being woken up by the globalfifo_write function, there is another possibility that the process is receiving an external interrupt,
The following code checks the situation, such as the user can't wait to use CTRL + C to interrupt the read process operation, then the capture of CTRL + C is done here:

if (signal_pending (current))//Is awakened by another interrupt, such as CTRL + C, it jumps directly
{
ret =-Erestartsys;
Goto Out2;
}
======== above these sentences have not understood, has been standing in the application layer of the angle to think ============

Blogger Supplementary information:

Signal_pending (current)--------"check if there is signal processing for this process, and return not 0 indicates a signal needs to be processed.
The-erestartsys represents a system call before the signal function is re-executed after it has been processed.
That is, if a system call occurs before the signal function, the kernel checks the return value of the system call before dispatching the user signal function to see if the system call is interrupted because of this signal. If the return value is-erestartsys and the current dispatch signal has the-erestartsys attribute, The system call is then executed after the user signal function returns.

=========================================================================

Note that the function ends with the following statement:
Remove_wait _queue (&dev->w_wait, &wait); Incorrect text
Remove_wait_queue (&dev->r_wait, &wait);   //that's the right thing to do.

before the function exits, move the current process from r_ The wait queue is removed, which is symmetric as in the preceding statement:
Add_wait_queue (&dev->r_wait, &wait);

Other should be understandable, the above code has two process sleep:
1> to enter the "critical section" may go to sleep when the semaphore (called the Down function), where the sleep action is the kernel (that is, the lower function of the underlying implementation). The
2> the read-process sleep itself when no readable data is available. The following code is typical in many drivers:

Declare_waitqueue (wait, current);
Down (&DEV->SEM);
Add_wait_queue (&dev->r_wait,&wait);

while (Conditionnot meet)
{

__set_current_state (task_interruptible);//change process status to sleep

Up (&dev->sem);

Schedule ();//dispatch other Process execution

if (signal_pending (current)) {
RET =-Erestartsys;
Goto Out2;
}

Down (&DEV->SEM);
}

============================ I'm a split line ==============================

LZ again asked:

It turns out there are two kinds of sleep: one is to hibernate when the race is generated, and the other is to hibernate when the FIFO is empty.

Sorry, I'll ask you a few more questions:
1. Wake up from where.
Sleep in the down function, after waking, whether the process continues from the down function.
__set_current_state (task_interruptible) sleep after waking, where the process starts.

2.while (Dev->current_len = = 0)
{
if (Filp->f_flags &o_nonblock)
{
ret =-Eagain;
Goto out;
}
__set_current_state (task_interruptible);
Up (&dev->sem);

Schedule ();
if (signal_pending (current))
{
ret =-Erestartsys;
Goto Out2;
}

Down (&DEV->SEM); Why there is a down function here. Its role ....
}

3.else
{
memcpy (Dev->mem, Dev->mem + count, dev->current_len-count); FIFO Data move forward
Dev->current_len-= count; Effective data length reduction
PRINTK (kern_info "read%d bytes (s), current_len:%d\n", Count, Dev->current_len);

Wake_up_interruptible (&dev->w_wait); Wake-Up Write wait queue

ret = count;
}
Why there is no up function here. There's a down function in front of me.

=========================, I'm a split line.

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.