【发布时间】:2010-08-12 18:02:45
【问题描述】:
当我们在 Unix Shell 的提示符下键入 vi 时, 我们可以使用 Vim 编辑器。
现在 Shell fork 另一个进程。
AFAIk 我在一本书中读到,一个进程无法修改另一个进程。 那么在 Linux 中,Shell 是如何允许我们在终端中打开 Vim 的呢?
我对 shell 是否真的在访问 Vim 的地址空间这一事实感到困惑。
【问题讨论】:
标签: unix operating-system
当我们在 Unix Shell 的提示符下键入 vi 时, 我们可以使用 Vim 编辑器。
现在 Shell fork 另一个进程。
AFAIk 我在一本书中读到,一个进程无法修改另一个进程。 那么在 Linux 中,Shell 是如何允许我们在终端中打开 Vim 的呢?
我对 shell 是否真的在访问 Vim 的地址空间这一事实感到困惑。
【问题讨论】:
标签: unix operating-system
在 Unix 中只有一种方法可以启动用户进程 - fork(2) 系统调用。它创建调用进程的精确副本,不同之处在于调用的返回值 - 父/调用者中新进程的进程 ID (pid),子进程中为零。操作系统通过 父进程 id 属性维护这种父子关系(例如,参见ps -f 的输出)。
幕后发生的事情是操作系统内核复制调用者的整个虚拟内存空间(这里有更多详细信息,google for Copy-On-Write 页面映射和vfork) .除非通过像mmap(2) 这样的共享内存 机制专门设置,否则不能从一个地址空间直接访问另一个地址空间。父进程可以wait(2) 为其子进程终止。
我不会进入process groups、sessions 和控制终端。这需要一张好照片。请查看APUE book 以获得详细解释。
execve(2) 系统调用用文件中的一些可执行文件之一替换当前进程映像。
现在,shell 将其 stdin、stdout 和 stderr 连接到 terminal emulator,继承自控制台上的 login(1) 进程,或由网络守护程序(如 sshd)动态分配,或者窗口管理器 (X)。例如,当您在 shell 中键入 vi 时,它是 forks,然后是 execs /bin/vi 程序,然后是 waits。新进程继承了打开的文件描述符,并且能够通过它们通过ioctl(2) 操作终端伪设备。
真正的乐趣从 管道 开始,当您输入类似 ps -ef|grep bash 的内容时 - 留给读者作为练习 :)
我在这里省略了许多有趣的细节,但希望这可以作为一个简短的介绍有所帮助。
【讨论】:
shell 只是简单地将 Vim 的终端文件描述符连接到它自己的,传递数据。
您可能听说过“标准输入”、“标准输出”等文件描述符。当使用终端仿真器(如 XTerm 或您使用的任何东西)时,它会为在其中运行的 shell 提供接收到的击键流,并解释 shell 发送到终端的数据(颜色等)并显示它们.
当您启动 Vim 时,shell 会启动它的进程并为该进程提供自己的输入和输出流。输入流与 shell 接收的相同,即在终端上键入的所有内容都会被 shell 接收,然后将其发送到 Vim。 Vim 发送到其输出流中的所有内容都会被 shell 接收,然后发送到终端。
基本上,数据的双向流动是这样的:
terminal emulator <====> shell <====> vim
【讨论】:
fork(2) 然后execve(2) 来启动一个进程。 fork(2) 系统调用让子进程inherit 打开文件描述符,execve(2) 让它们为新进程映像打开。