计算机体系结构:应用程序如何与操作系统通信?

Computer Architecture: How do applications communicate with an operating system?

前言:诚然,这是一个关于计算机体系结构的相当广泛的问题,但我从其他人那里听到并且自己也经常想知道。我也不认为对此有直接或快速的答案。但是,我希望精通系统架构的人可以提供一些见解。

一些背景:我主要是一名全栈开发人员,主要关注网络技术和数据库。我确实有一些 C 语言的背景,并且修补过很多低级的东西,但那是很久以前的事了,而且是非学术的。因此,我从来没有深入了解 OS 体系结构,这是我无法理解的一部分。我知道完成这些任务的各种技术和方法(特别是在更高层次上使用为此目的而设计的技术),但我缺乏关于如何发生这种情况的低层次逻辑的整体 picture/understanding - 特别是在OS级.

一般问题是:"container" 内部的应用程序 运行 如何与该容器的 运行 实例通信? "container" 是指已经加载到内存中的 运行 代码实例(此类代码的示例可以是操作系统、图形绘制界面、应用程序服务器、驱动程序等)。

此外,这个问题只适用于编译后的代码,以及同一台机器上运行系统之间的通信。

例如

假设我构建了一个简单的库,其目的是在屏幕上绘制一个像素。假设这个库只有一种方法,drawPixel(int x, int y)

库本身管理自己的绘图上下文(可以是从原始 SVGA 缓冲区到桌面的任何内容 window)。使用此 API 的应用程序只是针对库动态地 link,并调用 drawPixel 方法,而不知道调用后库的确切操作。

在幕后,这个 drawPixel 方法应该绘制到桌面上的 window,如果它在第一次调用时不存在则创建它。

但是,从技术上讲,如果设置如此简单明了,那么每个调用应用程序都会 "pull & run" drawPixel 中的所有代码及其依赖项,从而有效地导致每个 运行 应用程序拥有自己的整个调用链的 运行 实例(因此,如果它被 5 个不同的应用程序调用,你最终会得到 5 个不同的 windows 而不是共享上下文到一个 window)。 (我希望我解释的对)

所以,我的问题是,这 "sharing" 在现代操作系统中是如何发生的?

drawPixel 的代码真的会被 IPC 代码替换吗?或者它会是常规图形代码,但以某种方式 "loaded" 进入 OS 的方式有一个普遍可访问的 运行 实例,其他应用程序随意调用?

我知道的一些案例

我知道有很多方法可以解决这个问题,并且知道其中的一些。 然而,所有这些似乎都针对特定的利基市场并且存在缺点; none 似乎足以解释现代应用程序生态系统令人难以置信的功能(关于 OS 和应用程序服务的互连性)。

例如:

问题

还有哪些其他方式可以促进这种交流?或者,更具体地说,传统意义上的 "is this done",尤其是 OS APIs?

更具体问题的一些示例:

Note: I think in the case of WIN32 (and possibly GDI+), for example, you get a pointer (handle) to a context, so the concept is effectively "shared memory". But is it as simple as that? It would appear pretty unsafe to just get a raw pointer to a raw resource. Meaning, there are things that protect you from writing arbitrary data to this pointer, so I think it is more complex than that.

注意:我不确定这个问题是否有道理,并且可能承认它是愚蠢的或措辞不当的。但是,我希望我的观点得到理解,并且具有系统背景的人可以在涉及这些场景(如果有这样的事情)时加入标准 "way of doing things"。

编辑:我并不是要 IPC 方法的详尽列表。我试图找出一个特定的概念,但我不熟悉正确的术语,因此无法找到精确定位它的词。这就是为什么这个问题有这么多例子,"eliminate"问题没有针对的部分。

太笼统的问题,但有一些要点(与Linux相关;Windows的原则应该相同,但您可能被禁止全部理解):

初级 system calls (those listed in syscalls(2)...) are invoked by an elementary machine instruction (e.g. SYSENTER or SYSCALL) which switches the processor into kernel mode (with the system call number and arguments passed through defined registers, following the ABI convention). Hence user-space code can be viewed as running in some virtual machine (defined by user-mode instructions + the system call primitives). BTW the Linux kernel can load kernel modules 例如在其中添加额外的代码(例如设备驱动程序),这也是通过系统调用完成的。

inter-process communication facilities are built above these system calls (perhaps used by the standard library in higher level functions, e.g. getaddrinfo(3) might interact indirectly with some DNS service, see nsswitch.conf(5)). Read Advanced Linux Programming for more details. In practice you'll need several server programs (and that idea is pushed to its extreme in microkernel approaches), notably (on recent Linux) systemd. Drivers and kernel modules are loaded by specific system calls and later are part of the kernel so are usable thru other system calls. Play with strace(1) to understand the actual system calls done by some Linux program. Some information is provided by the kernel thru pseudo file systems (see proc(5)...) 可通过系统调用访问。

从用户程序到内核的每一次通信都是由IPC完成的(通过系统调用实现)。有时,内核会向上调用用户代码(在 Linux,signals)。

Linux 帧缓冲区(以及物理键盘和鼠标)通常只能由单个服务器访问,其他桌面应用程序使用常用的 IPC 设施与之通信 -sockets-, that server is the X11 or Wayland 服务器。

还读了一些关于 Operating Systems, e.g. the freely downloadable Operating Systems: Three Easy Pieces

的好书

对于Windows、MacOSX、Android,非常相似。但是,由于Windows(等...)是一个proprietary software, you might not be able to know all the details (and you might not be allowed to reverse-engineer them). In contrast, Linux is free software,所以你可以研究它的源代码。

我的建议是详细了解 Linux 的工作原理(这需要几年时间)并研究一些相关的源代码(这对于免费软件是可能的)。如果您需要深入了解 Windows,您可能需要购买它的一些源代码许可证(可能数百万美元)并签署 NDA。我根本不知道 Windows,但据我所知,它仅由 C 中的一个巨大的 API 定义。谣言说 Windows 内核类似于微内核,但微软有经济利益隐藏难看的实现细节。

另见 osdev