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

Io 内核如何跟踪哪些进程从中断接收数据?,io,operating-system,kernel,Io,Operating System,Kernel,在抢占式内核(比如Linux)中,假设进程a在stdin上调用getc,因此它在等待字符时被阻塞。我觉得我对内核如何知道在此时唤醒进程a并在收到数据后交付数据有一个基本的误解 我的理解是,当调度程序安排其他进程/线程运行时,该进程可以被置于挂起状态,或者被抢占。当按键发生时,通过轮询/中断(取决于实现),操作系统运行一个设备驱动程序,对按下的按键进行解码。但是,我的进程A当前可能没有运行。此时,我对我在等待I/O时被阻塞的进程现在如何排队再次运行感到困惑,尤其是它如何知道哪个进程在等待什么。设备

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

我的理解是,当调度程序安排其他进程/线程运行时,该进程可以被置于挂起状态,或者被抢占。当按键发生时,通过轮询/中断(取决于实现),操作系统运行一个设备驱动程序,对按下的按键进行解码。但是,我的进程A当前可能没有运行。此时,我对我在等待I/O时被阻塞的进程现在如何排队再次运行感到困惑,尤其是它如何知道哪个进程在等待什么。设备驱动程序似乎持有某种形式的等待队列

类似地,我不确定这是否与上述内容完全相关,但如果我的浏览器窗口处于焦点位置,它似乎会收到按键,而不是其他窗口。是否每个窗口/进程都有能力“监听”键盘事件,即使它们不在焦点上,但只是为了用户体验而没有

因此,我很好奇内核(或某些内核)如何跟踪哪些进程正在等待哪些事件,以及当这些事件发生时,内核如何确定要调度运行哪些进程

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

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

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

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

所有这些机制的共同点是,调用方选择挂起自己,等待io完成;并通过将其挂起与它期望从中输入的对象的实例关联来实现

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


因此,操作系统不会显式地将字符从设备路由到应用程序;一系列隐含和间接的步骤都可以。

谢谢!这很有帮助。那么,这是否意味着只有一个进程可以使用给定的字符,或者这种互斥依赖于实现(即,驱动程序可以将相同的字符传递给等待的多个进程?)为此,有许多策略,同样是通过各种操作系统中的抽象层实现的。UNIX衍生操作系统中会话和作业控制的高潮回答了这一问题,它只需要几个月的时间就能理解:)简言之,驱动程序将其发送到队列。队列管理器决定哪个“会话”应该获得它,属于该会话的进程将获得它。因此,还有另一个抽象层。如果您使用的进程将其stdin设置为原始模式fork()s,那么父级和子级都从0读取(2)和printf(“%d:get%c\n”,getpid(),c);你可以直接看到它是如何工作的。