3
votes

I'm reading "Linux kernel development 3rd edition by Robert Love" to get a general idea about how the Linux kernel works..(2.6.2.3)

I'm confused about how wait queues work for example this code:

    /* ‘q’ is the wait queue we wish to sleep on */ 
DEFINE_WAIT(wait);
add_wait_queue(q, &wait); 

while (!condition) { /* condition is the event that we are waiting for */
    prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE); 
    if (signal_pending(current))
        /* handle signal */ 
      schedule();
    }

finish_wait(&q, &wait);
  • I want to know which process is running this code? is it a kernel thread? whose process time is this?

  • And also in the loop, while the condition is still not met we will continue sleeping and call schedule to run another process the question is when do we return to this loop?

  • The book says that when a process sleeps, it's removed from our run queue, else it would be waken and have to enter a busy loop...

  • Also says: "sleeping should always be handled in a loop that ensures that the condition for which the task is waiting has indeed occurred."

I just want to know in what context is this loop running?

Sorry if this is a stupid Question. I'm just having trouble seeing the big pic

2

2 Answers

7
votes

Which process is running the code? The process that called it. I don't mean to make fun of the question but the gist is that kernel code can run in different contexts: Either because a system call led to this place, because it is in a interrupt handler, or because it is a callback function called from another context (such as workqueues or timer functions).

Since this example is sleeping, it must be in a context where sleeping is allowed, meaning it is executed in response to a system call or at least in a kernel thread. So the answer is the process time is taken from the process (or kernel thread) that called into this kernel code that needs to sleep. That is the only place where sleeping is allowed in the first place.

A certain special case are workqueues, these are explicitly for functions that need to sleep. Typical use would be to queue a function that needs to sleep from a context where sleeping is forbidden. In that case, the process context is that of one of the kernel worker threads designated to process workqueue items.

You will return to this loop when the wait_queue is woken up, which either sets one task waiting on the queue to runnable or all of them, depending on the wake_up function called.

The most important thing is, forget about this unless you are interested in the implementation details. Since many people got this wrong and it's basically the same thing everywhere it's needed, there have long been macros encapsulating the whole procedure. Look up wait_event(), that's how your example should really look like:

wait_event(q, condition);
-2
votes

As per your example... I added comments....

NOTE: while creating waiting queue by default it will be in sleep stat.

DEFINE_WAIT(wait); /* first wait ---> it the kernel global wait queue it is pointing */

add_wait_queue(q, &wait); /* first wait ---> it the kernel global wait queue it is pointing using add_wait_queue(q, &wait); ---> you are adding your own waiting queue (like appending linked list) */

while (!condition) { /* condition is the event that we are waiting for */ /*condition --> Let's say you are getting data from user space in write method (using __get_user()) */

prepare_to_wait(&q, &wait, TASK_INTERRUPTIBLE); 

/* This will wait when any wake_up_process() call will be generated having interrupt */ if (signal_pending(current))

/* This is continuously monitoring if any signal is pending on current CPU on which wait queue is running while not pending any signal generally used return -ERESTARTSYS; or "break" the loop if interrupts came exa., SIGINT or SIGKILL and finishes wait queue statement to check again / / handle signal */

  schedule();  // Scheduling of wait queue
               // Remove from global data structure 
}

finish_wait(&q, &wait); //Finishing wait queue