コンテキスト:次のワークセット{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)
read()
(D):ドライバ
ioctl()
機能でioctl
コマンドがあると、「スリープ」状態にあったスレッドを起きるようにMY_IOCTL_Y
設定is_free = 1
して呼び出します。wake_up_interruptible(&wq)
ioctl(MY_IOCTL_X)
print_wait_queue()
(E):待ち行列にあるスレッドのPIDを印刷する関数を作成しました。以前はそう呼んでいました。〜の後wake_up_interruptible()
タスクCとDを呼び出します。
印刷機能は次のように実装されます。
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の順序で実行するとします。
以下はコンソールから得られた結果です(簡単な出力)。
- "待機キュー:[pid_1、pid_2]" //
wake_up_interruptible()
呼び出し前write()
- "待ち行列:[]" //
wake_up_interruptible()
呼び出しwrite()
([pid_2]を楽しみにしています) - "待ち行列:[pid_2]" //呼び出し
wake_up_interruptible()
前ioctl(MY_IOCTL_Y)
- "待機キュー:[]" //呼び出し
wake_up_interruptible()
後ioctl(MY_IOCTL_Y)
上記のように、印刷#2では、残りのスレッド(pid_2)のPIDはPIDリストに表示されません。代わりに空のリストが表示されます。
wake_up_interruptible()
ただし、予想どおり、pid_2はioctl(MY_IOCTL_Y)
印刷#3が呼び出される前にリストに表示され、これはpid_2
実際には印刷#2と#3の間のキューに残っていることを示します。
質問:上記の印刷#2では[pid_2]が得られませんが、#3では何が得られますか?
ロックで待ち行列を保護しようとしましたが、print_wait_queue()
印刷の問題は解決されませんでした。
また、私が渡したポインタのアドレスはprint_wait_queue()
常に同じアドレスを指していることを確認しました。
答え1
私の観察は予想される動作です。
上記のようにここ、セクション6.2.2から:
wake_up()
目覚める指定されたキューで待機しているすべてのプロセス(...).他の形式(wake_up_interruptible()
)は中断可能なスリープモードを実行するプロセスに制限されています。
したがって、上記の印刷#2では、wake_up_interruptible()
呼び出しの直後に両方のジョブの状態があるrunnable
ため、両方のジョブは待機キューから削除されます。しかし、ioctl()
まだ条件が検証されておらず、任務は再び休眠状態になる予定だ。
gdb
各ジョブの前後のpid_2ジョブの状態を確認してこれを確認しましたwake_up_interruptible()
。