计算机体系结构:应用程序如何与操作系统通信? [英] Computer Architecture: How do applications communicate with an operating system?

查看:157
本文介绍了计算机体系结构:应用程序如何与操作系统通信?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前奏:诚然,这是一个关于计算机体系结构的相当广泛的问题,但是我从别人那里听到了一个问题,并且经常对自己感到疑惑.我也不认为对此有直接或快速的答案.但是,我希望精通系统架构的人能够提供一些见识.

一些背景:我主要是一个全栈开发人员,主要致力于Web技术和数据库.我确实有一定的C语言背景,并且对大量的低级内容进行了修改,但这是很久以前的事了,并且是非学术性的.因此,我从没有对OS体系结构进行过深入的了解,而这是我无法企及的一环.我知道完成这些任务的各种技术和方法(尤其是在较高级别上具有为此目的而设计的技术),但是我缺乏对这种情况如何发生的低水平后勤工作的全面了解/理解,尤其是在OS级别

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

此外,此问题仅适用于编译后的代码以及同一计算机上运行的系统之间的通信.

例如

比方说,我建立了一个简单的库,其目的是在屏幕上绘制像素.我们还说这个库有一个方法drawPixel(int x, int y).

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

在后台,该drawPixel方法应该绘制到桌面上的窗口,如果在第一次调用时不存在该窗口,则会创建该窗口.

但是,从技术上讲,如果安装过程如此简单明了,将会发生什么情况?很简单,就是每个调用应用程序都会拉出并运行" drawPixel中的所有代码及其依赖项,从而有效地使每个正在运行的应用程序在整个调用链中拥有自己的正在运行的实例(因此,如果被调用,则为通过5个不同的应用程序,您最终将拥有5个不同的窗口,而不是一个窗口的共享上下文. (我希望我能解释这个权利)

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

drawPixel的代码是否会实际替换为IPC代码?还是正常的图形代码,但是以某种方式将其加载"到操作系统中,从而使其具有一个可普遍访问的运行实例,其他应用程序会随意调用它?

我知道的某些情况

我知道有很多解决此问题的方法,并且知道其中一些方法. 但是,所有这些似乎都解决了特定的壁and并存在缺陷;似乎没有一个足够全面的解释现代应用程序生态系统令人难以置信的功能(关于OS和应用程序服务的互连性).

例如:

  • 在过去的(DOS)时代,我相信app <-> OS通讯是通过系统中断来完成的.
  • 在UNIX世界中,这是通过控制台上的stdin/stdout管道以及X Windows中的网络协议来完成的.
  • 在Windows&上有IPC平台,例如COM +/DCOM/DCOP/DBus. Linux,但同样,这些似乎是针对特定目的而设计的(大规模构建和管理组件;当今SOA的前身).

问题

可以促进这种交流的其他方式有哪些?或者,更具体地说,传统意义上的如何完成",尤其是在涉及OS API时?

一些更具体的问题的示例:

  • 内核如何在引导时加载"设备驱动程序,该设备驱动程序运行自己的代码(在隔离的空间中?),但仍与当前正在内存中运行的其上方的内核通信?这种交流是如何发生的?

  • 应用程序如何与窗口子系统(使用套接字的X和Quartz除外)进行通信?我认为WIN32使用了中断(也许仍然可以使用吗?),但是更新的东西如何工作?我很惊讶地发现,即使在今天,诸如WPF或Metro的复杂框架仍然归结为调用中断.我实际上不确定这些系统甚至使用WIN32 API.

  • 诸如GDI +和Linux Framebuffer之类的较低级图形子系统呢?

注意:例如,我认为在WIN32(可能还有GDI +)的情况下,您会获得指向上下文的指针(句柄),因此该概念实际上是共享内存".难道就这么简单吗?仅获得指向原始资源的原始指针似乎非常不安全.意思是,有些事情可以防止您向该指针写入任意数据,所以我认为它要复杂得多.

  • (这可能与上下文有关,因为它特定于JVM)在应用程序服务器内部运行的servlet如何与实际的应用程序服务器通信?意思是,它们如何在当前运行的服务器的内部上下文"中加载自身?

  • 关于IIS的相同问题-管道设置的准确度如何,以便IIS可以控制和回传信息.单独运行一个ASP.NET应用程序的进程?

注意:我不确定这个问题是否有意义,可以肯定是愚蠢的或措辞不佳的.但是,我希望我能理解我的观点,并且具有系统背景的人可以在涉及这些场景时(如果有这样的事情)采用标准的做事方式".

我并没有要求提供IPC方法的详尽清单.我正在尝试找出一个特定的概念,但是我不熟悉正确的术语,因此很难找到准确的用词.这就是为什么这个问题带有这么多示例来消除"该问题不针对的部分的原因.

解决方案

问题过于笼统,但有几点要点(与Linux有关; Windows的原理应相同,但您可能被禁止理解所有内容):

基本系统调用(在模式(系统调用号和参数通过已定义的寄存器传递,并遵循虚拟机(由用户模式定义)中运行指令+系统调用原语).顺便说一句,Linux内核可以将内核模块加载到例如.在其中添加其他代码(例如设备驱动程序),也可以通过系统调用来完成.

进程间通信功能是在这些系统调用之上构建的(也许已使用由标准库在更高级别的功能中提供,例如 getaddrinfo(3)可能与某些 DNS 服务进行间接交互,请参见 nsswitch.conf(5)).阅读 高级Linux编程 以获得更多详细信息.在实践中,您将需要几个服务器程序(并且该想法已推送到它在微内核方法中的极端情况),尤其是(在最近的Linux上) strace(1)了解实际的系统调用由某些Linux程序完成.内核通过伪文件系统(参见信号).

通常仅由单个服务器访问Linux帧缓冲区(以及物理键盘和鼠标),其他台式机应用程序使用常规IPC设施与之通信- X11 Wayland 服务器.

还要阅读有关操作系统的一些好书,例如免费下载的 操作系统:三个简单的组件

对于Windows,MacOSX,Android,它非常相似.但是,由于Windows(等)是专有软件,因此您可能无法了解所有详细信息(并且可能不允许您进行反向工程).相反,Linux是免费软件,因此您可以研究其源代码.

我的建议是详细了解Linux的工作方式(这将花费数年时间),并研究一些相关的源代码(对于免费软件来说是可能的).如果您需要对Windows的深入了解,则可能需要购买Windows的一些源代码许可(可能数百万美元)并签署NDA.我根本不了解Windows,但AFAIK仅由庞大的 API 中定义C.谣言说Windows内核就像微内核一样,但是Microsoft出于经济上的利益隐藏了丑陋的实现细节.

另请参见 osdev .

Prelude: This is admittedly a fairly broad question regarding computer architecture, but one that I hear from others and wonder about quite often myself. I also don't think that there is a direct or quick answer to this. However, I was hoping someone well-versed in systems architecture could provide some insight.

Some background: I am primarily a full-stack developer focusing mostly on web technologies and databases. I do have some background in C and tinkering with a good deal of low-level stuff, but that was a very long time ago and was non-academic. As such, I never got very deep into OS architecture, and this is one piece that eludes me. I am aware of various techniques and methods of accomplishing these tasks (especially on a higher level with technologies geared for this purpose), but am lacking a holistic picture/understanding of the low-level logistics of how this happens - particularly on an OS level.

The general question is: how do applications running inside of a "container" actually talk to the running instance of that container? By "container", I mean an instance of running code which is already loaded into memory (examples of such code could be an operating system, a graphics drawing interface, an application server, a driver, etc).

Also, this question applies only to compiled code, and to communication between systems running on the same machine.

For example

Let's say I build a simple library who's purpose is to draw a pixel on a screen. Let's also say this library has one method, drawPixel(int x, int y).

The library itself manages its own drawing context (which could be anything from a raw SVGA buffer to a desktop window). Applications using this API simply link dynamically against the library, and call the drawPixel method, without any awareness of the library's exact actions after the call.

Under the hood, this drawPixel method is supposed to draw to a window on the desktop, creating it if it doesn't exist on the first call.

However, technically what would happen if the setup was that straightforward & simple, is that each calling application would "pull & run" all of the code in drawPixel and its dependencies, effectively causing each running application to have its own running instance of the entire call chain (and thus, if it was called by 5 different applications, you'd end up with 5 different windows instead of a shared context to one window). (I hope I'm explaining this right)

So, my question is, how does this "sharing" happen in modern operating systems?

Would the code for drawPixel actually be replaced with IPC code? Or would it be regular graphics code, but somehow "loaded" into the OS in a way that there is one universally accessible running instance of it, which other applications call at-will?

Some cases I'm aware of

I know that there are many approaches to this issue, and am aware of a few of them. However, all of these seem to address specific niches and have shortcomings; none appear to be comprehensive enough to explain the incredible capabilities (regarding interconnectedness of OS & app services) of modern application ecosystems.

For example:

  • In the old (DOS) days, I believe app <-> OS communication was accomplished via system interrupts.
  • In the UNIX world, this is done via stdin/stdout pipes on the console, and a network protocol in X Windows.
  • There were IPC platforms like COM+/DCOM/DCOP/DBus on Windows & Linux, but again, these appear to be geared at a specific purpose (building & managing components at scale; predecessors of present-day SOA).

The question

What are some of the other ways that this kind of communication can be facilitated? Or, more specifically, how "is this done" in a traditional sense, especially when it comes to OS APIs?

Some examples of more specific questions:

  • How does a kernel "load" a device driver on boot, which runs its own code (in an isolated space?) but still talks to the kernel above it, which is currently running in memory? How does this communication happen?

  • How are windowing subsystems (with the exception of X and Quartz, which use sockets) talked to by applications? I think WIN32 used interrupts (maybe it still does?), but how does the newer stuff work? I'd be very surprised to find out that even in the present day, sophisticated frameworks like WPF or Metro still boil down to calling interrupts. I'm actually not sure that WIN32 APIs are even used by these systems.

  • What about lower-level graphics subsystems like GDI+ and the Linux Framebuffer?

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.

  • (this might be a bit out of context as its JVM specific) How do servlets running inside an application server talk to the actual application server? Meaning, how do they load themselves "inside the context" of the currently running server?

  • Same question for IIS - How exactly is the plumbing set-up so that IIS can control and communicate back & forth with a separate process running an ASP.NET application?

Note: I am not sure if this question makes much sense and may admittedly be dumb or poorly-worded. However, I was hoping that my point came across and that someone with a systems background could chime in on the standard "way of doing things" when it comes to these scenarios (if there is such a thing).

Edit: I am not asking for an exhaustive list of IPC methods. There is a specific concept that I am trying to find out about, but I am not familiar with the correct terminology and so am having trouble finding the words to pinpoint it. This is why this question comes with so many examples, to "eliminate" the parts that the question does not target.

解决方案

Too broad question, but some points (related to Linux; the principles should be the same for Windows, but you probably are forbidden to understand all of it) :

The elementary 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 to e.g. add additional code (such as device drivers) in it, and that is done also thru system calls.

The 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)...) accessible thru system calls.

Every communication from user program to kernel is done by IPC (implemented by system calls). Sometimes, the kernel is doing an upcall to user code (on Linux, with signals).

The Linux framebuffer (and the physical keyboard & mouse) is generally only accessed by a single server which other desktop applications communicate with using usual IPC facilities -sockets-, that server is the X11 or Wayland server.

Read also some good book on Operating Systems, e.g. the freely downloadable Operating Systems: Three Easy Pieces

For Windows, MacOSX, Android, it is very similar. However, since Windows (etc...) is a 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, so you can study its source code.

My advice would be to understand in details how Linux work (this would take several years) and study some relevant source code (which is possible for free software). If you need an deep understanding of Windows, you might need to buy some source code license of it (probably millions of dollars) and sign an NDA. I don't know Windows at all, but AFAIK it is only defined by a huge API in C. Rumors tell that the Windows kernel is microkernel like, but Microsoft has economical interest to hide ugly implementation details.

See also osdev.

这篇关于计算机体系结构:应用程序如何与操作系统通信?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆