了解操作系统如何存储/检索 IO 设备输入

Understanding how operating systems store/retrieve IO device input

提问人:4Matt 提问时间:5/21/2022 更新时间:5/21/2022 访问量:530

问:

我对键盘等 I/O 设备如何存储其输入以供操作系统或应用程序使用有点困惑。如果我有一台单处理器的电脑(单核CPU),而当前执行过程是游戏,那么游戏如何能够“感知”键盘输入?即使按键强制硬件中断(从而进行上下文切换),然后在操作系统将控制权交还给游戏进程时将密钥值“馈送”给游戏,也不能保证游戏循环甚至会检查玩家的输入,它也可以更新游戏对象位置或渲染游戏世界。

所以我的问题是......

  1. 键盘等 I/O 设备是否将输入存储到某种板载硬件特定的微处理器或板载内存存储缓冲区队列中,这些队列以后可以由外部进程或操作系统本身“读取”和刷新?非常感谢任何见解,谢谢!
输入 IO 操作系统

评论

0赞 Martin James 5/21/2022
是的。按键及其解释通常在硬件和软件中排队/缓冲,直到进程中具有输入焦点的线程请求它们。如果该线程已经请求了此类输入,并且由于没有可用的输入而被阻止,则它已准备就绪/正在运行。通常会对此类线程应用临时优先级提升,以增加在按键时“立即”运行的机会,从而改善交互式用户体验。

答:

3赞 Brendan 5/21/2022 #1

键盘等 I/O 设备是否将输入存储到某种板载硬件特定的微处理器或板载内存存储缓冲区队列中,这些队列以后可以由外部进程或操作系统本身“读取”和刷新?

让我们把它分成 3 个部分。

设备特定部分

对于旧键盘(USB 之前);键盘中的微控制器会定期扫描开关网格,并检测何时按下或释放某个键,将其转换为代码(可能是多个字节),然后一次将字节代码发送到计算机。计算机还有一个小微控制器来接收这些字节。该微控制器有一个 1 字节的缓冲区(甚至不足以容纳多字节代码)。

对于较新的键盘 (USB);键盘的内部结构基本相同(微控制器扫描开关网格等);但 USB 控制器会定期(通常每 8 毫秒)询问键盘“发生什么事吗?”,键盘的微控制器会回复。

无论如何;键盘驱动程序获取来自键盘的代码并对其进行处理;通常将其转换为固定长度的“键码”,将其与其他数据合并(如果 shift 或 capslock 或......当时很活跃;如果有对密钥有意义的 Unicode 代码点,等等),并将所有这些捆绑到一个数据结构中。

操作系统特定部分

该数据结构(由键盘驱动程序创建)通常由操作系统标准化为“用户输入事件”(因此,键盘、鼠标、触摸屏、操纵杆等的“事件”数据结构相同)。

该“用户输入事件”是通过驱动程序发送的。某种形式的进程间通信(管道、消息等)到其他东西(例如 GUI)。这种进程间通信有 2 种常见行为 - 如果接收程序在等待接收事件时被阻塞,则调度器将其解除阻塞(取消等待)并调度它以再次获取 CPU 时间;如果接收程序没有等待,则该事件通常会放在待处理事件的队列中(在内存中)。

当然,通常涉及许多进程,“用户输入事件”可能会从一个进程(例如输入法编辑器)转发到另一个进程(例如GUI)到另一个进程(例如,无论哪个窗口具有键盘焦点)。此外(对于旧的遗留命令行内容),它可能最终会进入一个转换层(例如终端仿真器),该层将事件转换为字符流(),同时破坏大部分信息(例如,当密钥被释放时)。stdin

特定语言部分

若要从高级代码中获取事件,需要了解语言是什么,有时还取决于使用的库。最常见的是某种“getEvent()”,它使程序从其队列(从内存中)获取下一个事件;并且可能会导致程序等待(并且不使用任何 CPU 时间),如果还没有任何事件 get。然而,这通常被进一步埋藏,这样你就注册了一个回调,然后当其他东西调用“getEvent()”时,当它收到一个偶数时,它会调用你注册的回调;所以它可能最终像(例如对于 Java)一样。public boolean handleEvent(Event evt) { switch (evt.id) { case Event.KEY_PRESS: ...

评论

0赞 4Matt 5/21/2022
嗨,布兰登,谢谢你的完美解释。我唯一的问题是,当您说“USB 控制器定期(通常每 8 毫秒)询问键盘”发生任何事情吗?“并且键盘的微控制器回复”......,这是通过操作系统调度程序每 8 毫秒创建一个完整的上下文切换,还是这种“轮询”在 USB 控制器本身上单独发生,并且在实际输入事件发生之前不会中断任何当前执行过程?
0赞 Brendan 5/21/2022
@4Matt:通常,USB 控制器的驱动程序会设置“何时传输什么”列表,并将它们提供给 USB 控制器;然后 USB 控制器使用列表来计算每 1 毫秒帧要做什么 - 例如,在一个 1 毫秒的帧中;USB 控制器可能会轮询 4 个不同的设备,然后将数据传输到/从另外 4 个设备传输数据;然后,在帧结束时,USB 控制器可能/将 (如果任何传输请求) 生成 IRQ,以便 USB 控制器驱动程序可以检查数据 (并将信息转发给其他驱动程序) 。“仅中断”或“全任务切换”的程度取决于操作系统。
1赞 user123 5/21/2022 #2

如今的键盘大多是 USB。在大多数计算机(包括 ARM 计算机)上,您都有一个 USB 控制器,该控制器实现了几家主要科技公司开发的 xHCI 规范。如果你在谷歌上搜索“xhci intel spec”或类似的东西,第一个链接左右应该是指向完整规范的链接。

xHCI 规范要求实现采用 PCI 设备的形式。PCI是由PCI-Seg小组开发的另一个规范。该规范指定了硬件要求的所有内容。它不是像 xHCI 那样的免费规范。它实际上非常昂贵(大约 3k$)。

OS 使用 ACPI 或类似规范检测 PCI 设备,这些规范有时可能特定于板(尤其是 ARM,因为所有基于 x86 的计算机都实现 ACPI)。ACPI 表位于 RAM 的常规位置,其中提到了在何处查找每个 PCI 设备的内存映射配置空间的基址。

操作系统使用内存映射在 RAM 中的寄存器与 PCI 设备交互。OS 在 ACPI 表和配置空间本身指定的位置读取/写入,以收集有关特定设备的信息,并使设备代表其执行操作。PCI 设备的配置空间具有常规部分(每个设备相同)和更具体的部分(取决于设备)。在一般部分,有BAR寄存器,其中包含配置空间中与设备相关的部分的地址。约定的每个实现者都可以对设备特定部分执行任何他们想要的操作。对于每个设备,常规部分必须有些相似,以便操作系统可以正确检测和初始化设备。

如今,每种类型的设备都必须遵守一定的约定才能与当前计算机配合使用。例如,硬盘将实现 SATA,主板将具有 AHCI(PCI SATA 控制器)。同样,键盘将实现 USB,并且该板具有 xHCI。

The xHCI itself have complex interaction mechanisms. A summary for keyboards, is that the OS will "activate" the interrupt IN endpoint of the keyboard. The OS will then place transfer requests (TRBs) on a circular ring in RAM. For interrupt endpoints, the xHCI will read one transfer request per time interval specified by the OS in a specific xHCI register. When the xHCI executes a TRB (when it does the transfer), it will post an event to another circular ring in RAM called the Event Ring. When a new event is posted, the xHCI triggers an interrupt. In the interrupt handler, the OS will read the Event Ring to determine what happened. For a keyboard, the OS will probably see that a transfer was done and read the data. Most often, keyboards will return 8 bytes. Interpretation of each byte is the keys that were pressed at the moment of the transfer. The bytes contain conventional scancodes. So they are not directly in UTF-8 or ASCII format. There is one scancode per keyboard key. It is up to the OS to determine what to do depending on the keyboard key. For example, if the data says that the 'A' key is pressed, then the OS can look if the 'SHIFT' key is pressed to determine if the 'A' should be uppercase or lowercase. If the next report says that the 'A' key is not pressed than the OS should consider this as a release of the key (the user released the key). In other words, the keyboard is polled by the OS at certain intervals.

The interrupt handler will probably pass the key to other portions of the kernel and save the key to a process specific structure. The process will probably poll a lock protected buffer that will contain events. It could also be a system wide buffer that simply contains all events.

The higher level implementation probably varies between OS. If you understand the lower level inner workings than you can probably imagine how an OS will work. It is certain that the whole things is very complex because CPUs nowadays have several cores and caches and other complex mechanisms. The OS must make sure to work seamlessly with all these mechanisms so it is quite complex but achievable. To understand the whole thing, you'd probably need to understand the whole OS. It has lots of ramifications in other OS concepts.