0

Context: Consider the following set of operations {A, B, C, D, E}:

  • (A) : On the read() function of my device driver, I add the calling thread to a wait queue wq if a driver's buffer buf is empty.

More specifically, the calling thread is added to the queue via:

wait_event_interruptible(wq, strlen(buf) > 0)
  • (B) : Similarly, on the ioctl() function of the driver, I add the calling thread to the same queue wq if the passed ioctl command is MY_IOCTL_X and if a driver's flag is_free == 0.

Again, the calling thread is added to the waiting queue via:

wait_event_interruptible(wq, is_free != 0)
  • (C) : On the driver's write() function, I pass the user-space content to buff, and call wake_up_interruptible(&wq), so that to wake up the thread put to 'sleep' in read().

  • (D) : On the driver's ioctl() function, if the ioctl command is MY_IOCTL_Y, I set is_free = 1, and call wake_up_interruptible(&wq), in order to wake up the thread put to 'sleep' by ioctl(MY_IOCTL_X).

  • (E) : I've created a print_wait_queue() function to print the PIDs of the threads in the waiting queue. I call it before and after calling wake_up_interruptible() in operations C and D.

The print function is implemented like this:

void print_wait_queue(struct wait_queue_head* wq)
{
  struct list_head *i, *tmp;
  pr_info("waiting queue: [");
  list_for_each_safe(i, tmp, &(wq->head)) 
  {
    struct wait_queue_entry* wq_item = list_entry(i, struct wait_queue_entry, entry);
    struct task_struct* task = (struct task_struct*) wq_item->private;
    pr_info("%d,", task->pid);
  }
  pr_info("]\n");
}

Problem: The actual queueing and de-queueing seems to be working as intended, no issues here.

However, the printing of the wait queue is not.

Let's say I perform the operations described above, in this order: A -> B -> C -> D.

This is what I get in the console (simplified output):

  1. “waiting queue : [pid_1, pid_2]” // before calling wake_up_interruptible() on write()
  2. “waiting queue : []” // after calling wake_up_interruptible() on write() (I was expecting [pid_2])
  3. “waiting queue : [pid_2]” // before calling wake_up_interruptible() on ioctl(MY_IOCTL_Y)
  4. “waiting queue : []” // after calling wake_up_interruptible() on ioctl(MY_IOCTL_Y)

As shown above, at print #2, the PID of the remaining thread - pid_2 - doesn’t show up in the PID list. Instead, I get an empty list.

However, pid_2 shows up in the list before calling wake_up_interruptible() on ioctl(MY_IOCTL_Y) at print #3, as expected, indicating that pid_2 is actually kept in the waiting queue in-between prints #2 and #3.

Questions: Why don’t I get [pid_2] at print #2 above, but then get it at #3?

I’ve tried protecting the wait queue cycle in print_wait_queue() with a lock and it didn’t solve the printing issue.

I've also confirmed that the address that the pointer I pass to print_wait_queue() always points to the same address.

1 Answer 1

0

My observations are expected behaviour.

As mentioned here, in section 6.2.2 :

wake_up() wakes up all processes waiting on the given queue (...). The other form (wake_up_interruptible()) restricts itself to processes performing an interruptible sleep.

As such, at print #2 above, immediately after calling wake_up_interruptible(), the state of both tasks is runnable, and as such, both tasks are removed from the wait queue. However, the ioctl() task is about to go to sleep again, since it's condition isn't verified yet.

I've confirmed this by looking at the task state of pid_2 on gdb before and after each wake_up_interruptible():

  • At print #2, the ioctl() task was in fact in state 0, i.e. runnable [1].
  • At any point after print #2 and before print #3, the task was in state 1, i.e. stopped [1].

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.