Linux内核:在prepare_to_wait_event之后发生抢占时,wait_event_interruptible会永远休眠吗?

问题描述

wait_event_interruptible 上阅读内核源代码时,我有点困惑,因为考虑到抢占,它看起来并不安全。

下面是源码的主要逻辑:

1: #define ___wait_event(wq_head,condition,state,exclusive,ret,cmd)        \
2: ({                                       \
3:  __label__ __out;                            \
4:  struct wait_queue_entry __wq_entry;                 \
5:  long __ret = ret;   /* explicit shadow */               \
6:                                      \
7:  init_wait_entry(&__wq_entry,exclusive ? WQ_FLAG_EXCLUSIVE : 0);    \
8:  for (;;) {                              \
9:      long __int = prepare_to_wait_event(&wq_head,&__wq_entry,state);\
10:                                     \
11:     if (condition)                          \
12:         break;                          \
13:                                     \
14:     if (___wait_is_interruptible(state) && __int) {         \
15:         __ret = __int;                      \
16:         goto __out;                     \
17:     }                               \
18:                                     \
19:     cmd;                                \
20: }                                   \
21: finish_wait(&wq_head,&__wq_entry);                 \
22: __out:  __ret;                                  \
23: })

这个宏没有包含在抢占禁用块中,所以我认为相应的进程可能会在line 10中被关闭。所以在以下场景下:

  1. 此睡眠仅在唤醒时可用。
  2. 当此代码line 8 中时,上述唤醒发生在另一个 cpu 中。
  3. 一个中断在 line 10 处启动,结果此进程被关闭

因此,此过程将永远停留在 TASK_INTERRUPTIBLE 中。

我想知道是这种情况还是我错过了什么?

我正在查看的 linux 代码https://elixir.bootlin.com/linux/v5.13.4/source/include/linux/wait.h#L274

解决方法

当然,它会保持挂起,但下次当进程获得计划并恢复时,它会检查条件并发现条件为真并且会中断。

假设条件变坏,因为其他进程修改了值,然后它会挂起,直到有人向它触发信号,这个进程会检查信号并跳出 for 循环。