Linux-Kernel

在 Linux 核心中列印等待隊列的內容時出現問題

  • February 7, 2022

**上下文:**考慮以下一組操作 {A, B, C, D, E}:

  • (A) :在我的設備驅動程序的功能上,如果驅動程序的緩衝區為空read(),我將呼叫執行緒添加到等待隊列。wq``buf

更具體地說,呼叫執行緒通過以下方式添加到隊列中:

wait_event_interruptible(wq, strlen(buf) > 0)
  • (B) : 同樣,在驅動程序的功能上,如果傳遞的命令是並且如果驅動程序的標誌ioctl(),我將呼叫執行緒添加到同一個隊列中。wq``ioctl``MY_IOCTL_X``is_free == 0

同樣,呼叫執行緒通過以下方式添加到等待隊列:

wait_event_interruptible(wq, is_free != 0)
  • (C) :在驅動程序的write()功能上,我將使用者空間內容傳遞給buff,並呼叫wake_up_interruptible(&wq),以便喚醒 ‘sleep’ 中的執行緒read()
  • (D):在驅動ioctl()函式上,如果ioctl命令是MY_IOCTL_Y,我設置is_free = 1,並呼叫wake_up_interruptible(&wq),以喚醒被 ‘sleep’ 設置的執行緒ioctl(MY_IOCTL_X)
  • (E):我創建了一個print_wait_queue()函式來列印等待隊列中執行緒的 PID。我在呼叫操作 C 和 D之前和之後呼叫它。wake_up_interruptible()

列印功能是這樣實現的:

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

**問題:**實際的排隊和出隊似乎按預期工作,這裡沒有問題。

但是,等待隊列的列印不是。

假設我按照以下順序執行上述操作:A -> B -> C -> D。

這是我在控制台中得到的(簡化輸出):

  1. “等待隊列:$$ pid_1, pid_2 $$” // 在呼叫wake_up_interruptible()之前write()
  2. “等待隊列:$$ $$” // 呼叫後wake_up_interruptible()write()期待$$ pid_2 $$)
  3. “等待隊列:$$ pid_2 $$” // 在呼叫wake_up_interruptible()之前ioctl(MY_IOCTL_Y)
  4. “等待隊列:$$ $$” // 呼叫wake_up_interruptible()ioctl(MY_IOCTL_Y)

如上所示,在列印 #2 處,剩餘執行緒的 PID - pid_2 - 沒有出現在 PID 列表中。相反,我得到一個空列表。

但是,pid_2 在列印 #3 呼叫之前出現在列表中wake_up_interruptible()ioctl(MY_IOCTL_Y)正如預期的那樣,表明它pid_2實際上保留在列印 #2 和 #3 之間的等待隊列中。

**問題:**為什麼我沒有得到

$$ pid_2 $$在上面的列印 #2,然後在 #3 得到它? 我試過print_wait_queue()用鎖保護等待隊列週期,但沒有解決列印問題。

我還確認了我傳遞的指針的地址print_wait_queue()總是指向同一個地址。

我的觀察是預期的行為。

如此處所述,在第 6.2.2 節中:

wake_up()喚醒所有等待給定隊列(…)的程序。另一種形式 ( wake_up_interruptible()) 將自身限制為執行可中斷睡眠的程序。

因此,在上面的列印 #2 處,在呼叫 之後wake_up_interruptible(),兩個任務的狀態都是runnable,因此,兩個任務都從等待隊列中刪除。然而,ioctl()任務即將再次進入休眠狀態,因為它的狀態尚未得到驗證。

我通過查看 pid_2gdb之前和之後的任務狀態確認了這一點wake_up_interruptible()

  • 在列印 #2 處,ioctl()任務實際上處於狀態 0,即runnable $$ 1 $$.
  • 在 print #2 之後和 print #3 之前的任何時候,任務都處於狀態 1,即stopped $$ 1 $$.

引用自:https://unix.stackexchange.com/questions/688539