内核如何跟踪哪些进程从中断接收数据?

How does the kernel track which processes receive data from an interrupt?

在抢占式内核中(比如 Linux),假设进程 A 在 stdin 上调用了 getc,因此它被阻塞等待一个字符。我觉得我对内核如何知道此时唤醒进程 A 并在收到数据后传递数据有一个根本性的误解。

我的理解是,当调度程序将其他 processes/threads 调度到 运行 时,此进程可以置于挂起状态,否则它会被抢占。当按键发生时,通过 polling/interrupts 取决于实现,OS 运行 是一个设备驱动程序,它解码被按下的键。但是,我的进程 A 目前可能(而且很可能)未 运行ning。此时,我对在 I/O 上被阻塞等待的进程现在如何再次排队到 运行 感到困惑,尤其是它如何知道哪个进程在等待什么。设备驱动程序似乎持有某种形式的等待队列。

同样,我不确定这是否与上述完全相关,但是如果我的浏览器 window 处于焦点状态,它似乎可以接收按键而不是其他 windows。是否每个 window/process 都能够 "listen" 处理键盘事件,即使它们不在焦点上,但只是为了用户体验而不这样做?

所以我很好奇内核(或某些内核)如何跟踪哪些进程正在等待哪些事件,以及这些事件何时进入,它如何确定将哪些进程调度到 运行?

进程等待的事件是抽象的软件事件,例如特定队列不为空,而不是具体的硬件事件,比如中断4635发生。

某些配置(可能由设备树等硬件描述引导)将中断 4635 标识为来自具有给定地址的给定串行设备的信号。串行设备驱动程序自行配置,以便它可以访问此串行端口的设备寄存器,并将其中断处理程序附加到给定的中断标识符 (4635)。

配置后,当从串行设备发出中断时,内核的最低级别调用此串行设备的中断处理程序。反过来,当处理程序看到新字符到达时,它会将其放入该设备的输入队列中。当它对字符进行排队时,它可能会注意到某些进程正在等待该队列非空,并导致它们为 运行.

这大致描述了使用条件变量作为中断和进程之间的信号机制的情况,正如 44 年前在 UNIX-y 内核中建立的那样。其他方法包括在队列中的每个字符上释放一个信号量;或回复每个角色的消息。可以使用多种形式的同步。

所有此类机制的共同点是,调用者选择挂起自身以等待 io 完成;并通过将其暂停与它期望输入的对象的实例相关联来实现。

接下来会发生什么?通常,等待进程(现在为 运行ning)会重新尝试从输入队列中删除一个字符。有可能其他进程先到达它,在这种情况下,它只是返回等待队列变为非空。

因此,OS 没有明确地将字符从设备路由到应用程序;一系列隐式和间接步骤。