> For the complete documentation index, see [llms.txt](https://book.bsdcn.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-er-bu-fen-jin-cheng/4.8.-jin-cheng-tiao-shi.md).

# 4.8 进程调试

与多数 UNIX 系统一样，4.3BSD 提供一个控制与调试进程执行的简单设施。该设施经 `ptrace` 系统调用访问，允许父进程通过操纵子进程的用户态和内核态执行状态来控制它的执行。具体说，用 `ptrace`，父进程可以对子进程做以下操作：

* 读写地址空间和寄存器
* 拦截投递给进程的信号
* 单步执行与继续执行进程
* 终止进程的执行

`ptrace` 调用几乎专供 **adb** 和 **dbx** 等程序调试器使用。

进程被跟踪时，任何投递给它的信号都使它进入 SSTOP 态。父进程收到 SIGCHLD 信号的通知，并可用 `wait` 和 `wait3` 系统调用查询子进程的状态。多数机器上，单步执行时产生的跟踪陷阱（trace trap）和执行断点指令引起的断点故障，都被 UNIX 翻译成 SIGTRAP 信号。由于投递给被跟踪进程的信号都会使它停止并通知父进程，程序的执行很容易控制。

要启动一个待调试的程序，调试器先用 `fork` 系统调用创建子进程。fork 之后，子进程调用 `ptrace`，置起 proc 结构 `p_flag` 字段中的 STRC 位，从而把进程标记为被跟踪。然后子进程置起进程处理器状态字中的跟踪陷阱位，调用 `execve` 装入待调试程序的映像。置起这一位，保证子进程在新映像装入后执行的第一条指令就引发硬件跟踪陷阱，被系统翻译成 SIGTRAP 信号。父进程会得到子进程所有信号的通知，于是能在程序执行一条指令之前拦截信号、取得控制权。

`ptrace` 提供的所有操作都在被跟踪进程的上下文中执行。父进程想执行一个操作时，把操作的参数放进名为 `ipc` 的数据结构，清除子进程 proc 结构中的 SWTED 标志，然后在 `ipc` 的地址上入睡。子进程下次遇到信号时（若它正被信号停止则立即），从 `ipc` 结构取回参数并执行所请求的操作。然后子进程把返回结果放进 `ipc` 结构，以 `ipc` 的地址为等待通道调用 `wakeup()`。

`ptrace` 设施的效率 **非常** 低，原因有三。第一，`ptrace` 用单个全局数据结构在系统中所有父子进程之间来回传递信息。结构只有一个，必须互斥，保证一次只有一对父子进程使用。第二，数据结构大小固定且小，父进程一次只能读写 32 位。最后，父进程的每个请求都必须在子进程的上下文中执行，为此每个请求要做两次上下文切换——一次从父到子发送请求，一次从子到父返回结果。

UNIX 第八版中的 **/proc** 文件系统所含的调试设施 \[Killian, 1984] 解决了所有这些问题。在 **/proc** 系统中，可以用 `read` 和 `write` 系统调用访问另一个进程的地址空间，让调试器以高得多的效率访问被调试进程。一种机制取代了进程间来回传消息的数据结构，既消除了对 `ipc` 结构的争用，也省去了父子进程之间的上下文切换。

## 习题

4.1 user 结构为什么与 proc 结构分开？

4.2 user 结构不映射到内核地址空间的固定虚拟地址上，会有什么影响？

4.3 上下文切换机制的性能为什么对高度多道程序化的系统至关重要？

4.4 增大时间片对系统的交互响应和总吞吐量有什么影响？

4.5 把运行队列数从 32 减到 16，对调度开销和系统总体性能有什么影响？

4.6 给出系统选择新进程运行的三条理由。

4.7 4.3BSD 用什么类型的调度策略？该策略偏向什么类型的作业？为识别这些受优待的作业提出一种算法。

4.8 如今窗口系统已广泛普及，作业控制还是有用的设施吗？为什么？

4.9 进程调度何时以及如何与存储管理设施互动？

4.10 给实时系统下个定义。给出 4.3BSD 不是实时系统的两条理由。

4.11 进程退出之后，可能先进入僵尸状态 SZOMB，然后才彻底从系统消失。SZOMB 状态的目的是什么？什么事件使进程退出 SZOMB？

4.12 假设图 4.2 所示的数据结构不存在。系统要识别一个进程的全部后代，最少需要维护什么信息？就空间与时间代价比较下列操作：

a. 创建新进程

b. 查进程的父进程

c. 查一个进程的全部兄弟

d. 查一个进程的全部后代

e. 销毁一个进程

4.13 `sleep()` 例程在改动进程 proc 结构的内容之前，先把硬件优先级提升到 `splhigh`。为什么？

4.14 以低于 PZERO 的优先级阻塞的进程可能永不被信号唤醒。描述系统运行中磁盘变得不可用时这种情形可能引起的问题。

4.15 对表 4.2 所列的每种状态，列出处于该状态的进程可能出现在哪些系统队列上。

\*4.16 4.3BSD 中，用户键入“挂起字符”时向进程投递 SIGTSTP 信号。进程为什么想在被停止之前捕获这个信号？

\*4.17 在 4.3BSD 信号机制加入之前，捕获 SIGTSTP 信号的信号处理程序这样写：

```c
catchstop()
{
    prepare to stop;
    signal(SIGTSTP, SIG_DFL);
    kill(getpid(), SIGTSTP);
    signal(SIGTSTP, catchstop);
}
```

这段代码在 4.3BSD 中会造成无限循环。为什么？代码该怎么改写？

\*4.18 进程优先级计算和记账统计都基于采样数据。描述能给出更精确统计和优先级计算的硬件支持。

\*4.19 给 4.3BSD 添加固定优先级调度算法有什么影响？

\*4.20 信号为什么是一种糟糕的进程间通信设施？

**4.21** 硬件检测到内核态栈指针的无效值时，产生内核栈无效（kernel-stack-invalid）陷阱。假设该陷阱在内核态下于中断栈上收到。进程在 user 结构内的内核运行时栈上执行时收到这种陷阱，系统该如何优雅地终止它？

**4.22** 描述一种能在紧耦合多处理机硬件环境中工作的同步方案。假设硬件支持测试并设置（test-and-set）指令。

**4.23** 描述测试并设置指令的替代物，使你能为多处理机 UNIX 系统构建同步机制。

**4.24** 轻量级进程（lightweight process）是在普通 UNIX 进程上下文内运作的执行线程。单个 UNIX 进程中可以存在多个轻量级进程并共享内存，但每个都能做阻塞操作（如系统调用）。描述轻量级进程如何完全在用户态实现。

**4.25** 描述实现轻量级进程会有用的新内核设施。现有的 UNIX 进程上下文组织如何使内核支持轻量级进程变得困难？

## 参考文献

AT\&T, 1987. AT\&T, *The System V Interface Definition (SVID)*, Issue 2, American Telephone and Telegraph, Murray Hill, NJ (January 1987).

Bobrow et al., 1972. D. G. Bobrow, J. D. Burchfiel, D. L. Murphy, & R. S. Tomlinson, “TENEX, a Paged Time Sharing System for the PDP-10,” *Comm ACM* **15**(3), pp. 135–143, Association for Computing Machinery (March 1972).

Ferrin & Langridge, 1980. T. E. Ferrin & R. Langridge, “Interactive Computer Graphics with the UNIX Time-Sharing System,” *Computer Graphics* **13**, pp. 320–331 (1980).

Joy, 1986. W. N. Joy, “An Introduction to the C Shell,” pp. 4:1–46 in *UNIX User's Supplementary Documents, 4.3 Berkeley Software Distribution, Virtual VAX-11 Version*, USENIX Association, Berkeley, CA (1986).

Killian, 1984. T. J. Killian, “Processes as Files,” *USENIX Association Conference Proceedings*, pp. 203–207 (June 1984).

Korn, 1983. D. Korn, “KSH—A Shell Programming Language,” *USENIX Association Conference Proceedings*, pp. 191–202 (June 1983).

Korn, 1984. D. Korn, *Introduction to the Korn Shell*, Issue 2, AT\&T Bell Laboratories, Murray Hill, NJ (November 1984).

Ritchie, 1988. D. M. Ritchie, “Multi-Processor UNIX,” private communication (April 25, 1988).

Sanderson et al., 1986. T. Sanderson, S. Ho, N. Heijden, E. Jabs, & J. L. Green, “Near-Realtime Data Transmission During the ICE-Comet Giacobini-Zinner Encounter,” *ESA Bulletin* **45**(21) (1986).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://book.bsdcn.org/4.3-bsd-unix-cao-zuo-xi-tong-she-ji-yu-shi-xian/di-er-bu-fen-jin-cheng/4.8.-jin-cheng-tiao-shi.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
