CSAPP英語學習系列:Chapter 8: Exceptional Control Flow

xing393939發表於2021-03-01
8.1 Exceptions
8.2 Processes
8.2.1 Logical Control Flow
8.2.2 Concurrent Flows
8.2.3 Private Address Space
8.2.4 User and Kernel Modes

8.2.5 Context Switches

A context switch can occur while the kernel is executing a system call on behalf
of the user. If the system call blocks because it is waiting for some event to occur,
then the kernel can put the current process to sleep and switch to another process.
For example, if a read system call requires a disk access, the kernel can opt to
perform a context switch and run another process instead of waiting for the data
to arrive from the disk. Another example is the sleep system call, which is an
explicit request to put the calling process to sleep. In general, even if a system
call does not block, the kernel can decide to perform a context switch rather than
return control to the calling process.

explicit
美[ɪkˈsplɪsɪt]
adj. 明確的;直言的
8.3 System Call Error Handling

We will use error-handling wrappers throughout the remainder of this book.
They allow us to keep our code examples concise without giving you the mistaken
impression that it is permissible to ignore error checking. Note that when we
discuss system-level functions in the text, we will always refer to them by their
lowercase base names, rather than by their uppercase wrapper names.

throughout
美[θruːˈaʊt]
prep. 自始至終

remainder
美[rɪˈmeɪndər]
n. 廉價出售(書)

concise
美[kənˈsaɪs]
adj. 簡明的
8.4.1 Obtaining Process IDs

Unix provides a number of system calls for manipulating processes from C pro-
grams. This section describes the important functions and gives examples of how
they are used.
Each process has a unique positive (nonzero) process ID (PID). The getpid
function returns the PID of the calling process. The getppid function returns the
PID of its parent (i.e., the process that created the calling process).

obtain
美[əbˈteɪn]
v. 得到

manipulate
美[məˈnɪpjuleɪt]
vt. 操作,處理

positive
美[ˈpɑːzətɪv]
adj. 積極樂觀的
8.4.2 Creating and Terminating Processes

Running. The process is either executing on the CPU or waiting to be executed
and will eventually be scheduled by the kernel.
Stopped. The execution of the process is suspended and will not be scheduled.
A process stops as a result of receiving a SIGSTOP, SIGTSTP, SIGTTIN,
or SIGTTOU signal, and it remains stopped until it receives a SIGCONT
signal, at which point it becomes running again. (A signal is a form of
software interrupt that we will describe in detail in Section 8.5.)
Terminated. The process is stopped permanently. A process becomes termi-
nated for one of three reasons: (1) receiving a signal whose default action
is to terminate the process, (2) returning from the main routine, or (3)
calling the exit function.

eventually
美[ɪˈventʃuəli]
adv. 最後

interrupt
美[ˌɪntəˈrʌpt]
v. 打斷

routine
美[ruːˈtiːn]
n. 常規;例程
8.4.3 Reaping Child Processes

pid_t waitpid(pid_t pid, int *statusp, int options); //Returns: PID of child if OK, 0 (if WNOHANG), or −1 on error

If pid > 0, then the wait set is the singleton child process whose process ID is equal to pid. 
If pid = -1, then the wait set consists of all of the parent’s child processes.
If options = 0, Suspend execution of the calling process until a child process in its wait
set terminates.
If options = WNOHANG. Return immediately (with a return value of 0) if none of the child processes 
in the wait set has terminated yet.
If options = WUNTRACED. Suspend execution of the calling process until a process in the wait
set becomes either terminated or stopped
If options = WCONTINUED. Also return if a stopped child has been resumed by delivery of SIGCONT.

reaping
美['ripɪŋ]
v. 收割
8.4.4 Putting Processes to Sleep

Sleep returns zero if the requested amount of time has elapsed, and the number of
seconds still left to sleep otherwise. The latter case is possible if the sleep function
returns prematurely because it was interrupted by a signal. We will discuss signals
in detail in Section 8.5.

elapse
美[ɪˈlæps]
v. (時間)流逝

latter
美[ˈlætər]
adj. 後者的

prematurely
美[ˌpriməˈtjʊrlɪ]
adv. 過早地,貿然地
8.4.5 Loading and Running Programs

execve() returns −1 on error. It does not return on success, and the text, initialized data, uninitialized data (bss), and stack of the calling process are overwritten according to the contents of the newly loaded program.
8.4.6 Using fork and execve to Run Programs

Programs such as Unix shells and Web servers make heavy use of the fork and
execve functions. A shell is an interactive application-level program that runs
other programs on behalf of the user. The original shell was the sh program,
which was followed by variants such as csh, tcsh, ksh, and bash. A shell performs
a sequence of read/evaluate steps and then terminates. The read step reads a
command line from the user. The evaluate step parses the command line and runs
programs on behalf of the user.

heavy
美[ˈhevi]
adj. 重的;超出一般的;大量的

interactive
美[ˌɪntərˈæktɪv]
adj. 互相作用的

variant
美[ˈveriənt]
n. 變體

evaluate
美[ɪˈvæljueɪt]
v. 估計
8.5 Signals

Each signal type corresponds to some kind of system event. Low-level hard-
ware exceptions are processed by the kernel’s exception handlers and would not
normally be visible to user processes. Signals provide a mechanism for exposing
the occurrence of such exceptions to user processes. For example, if a process at-
tempts to divide by zero, then the kernel sends it a SIGFPE signal (number 8).
If a process executes an illegal instruction, the kernel sends it a SIGILL signal
(number 4). If a process makes an illegal memory reference, the kernel sends it a
SIGSEGV signal (number 11). Other signals correspond to higher-level software
events in the kernel or in other user processes.

correspond
美[ˌkɔːrəˈspɑːnd]
v. 符合

mechanism
美[ˈmekənɪzəm]
n. 機制,機能

expose
美[ɪkˈspoʊz]
v. 揭發;使暴露

occurrence
美[əˈkɜːrəns]
n. 遭遇,事件

divide
美[dɪˈvaɪd]
v. 除以

illegal
美[ɪˈliːɡl]
adj. 不合法的
8.5.1 Signal Terminology

A signal that has been sent but not yet received is called a pending signal. At
any point in time, there can be at most one pending signal of a particular type.
If a process has a pending signal of type k, then any subsequent signals of type
k sent to that process are not queued; they are simply discarded. A process can
selectively block the receipt of certain signals. When a signal is blocked, it can be
delivered, but the resulting pending signal will not be received until the process
unblocks the signal.

terminology
美[ˌtɜːrmɪˈnɑːlədʒi]
n. 專門名詞;術語

particular
美[pərˈtɪkjələr]
adj. 特定的

subsequent
美[ˈsʌbsɪkwənt]
adj. 後來的;隨後的

deliver
美[dɪˈlɪvər]
v. 遞送;交付
8.5.2 Sending Signals

int kill(pid_t pid, int sig); If pid is equal to zero, then kill sends signal sig to every process
in the process group of the calling process, including the calling process itself. If
pid is less than zero, then kill sends signal sig to every process in process group
|pid| (the absolute value of pid).
The alarm function arranges for the kernel to send a SIGALRM signal to the
calling process in secs seconds. If secs is 0, then no new alarm is scheduled. In
any event, the call to alarm cancels any pending alarms and returns the number
of seconds remaining until any pending alarm was due to be delivered (had not
this call to alarm canceled it), or 0 if there were no pending alarms.

arrange
美[əˈreɪndʒ]
v. 佈置;安排

alarm
美[əˈlɑːrm]
n. 警報(器);鬧鐘
8.5.3 Receiving Signals

Figure 8.26 shows the default actions associated with each type of signal.
For example, the default action for the receipt of a SIGKILL is to terminate
the receiving process. On the other hand, the default action for the receipt of
a SIGCHLD is to ignore the signal. A process can modify the default action
associated with a signal by using the signal function. The only exceptions are
SIGSTOP and SIGKILL, whose default actions cannot be changed.

associate
美[əˈsoʊsieɪt]
v. 聯想,聯絡

receipt
美[rɪˈsiːt]
n. 接收
8.5.4 Blocking and Unblocking Signals

Implicit blocking mechanism. By default, the kernel blocks any pending sig-
nals of the type currently being processed by a handler. For example, in
Figure 8.31, suppose the program has caught signal s and is currently run-
ning handler S. If another signals is sent to the process, then s will become
pending but will not be received until after handler S returns.
Explicit blocking mechanism. Applications can explicitly block and unblock
selected signals using the sigprocmask function and its helpers.

implicit
美[ɪmˈplɪsɪt]
adj. 隱含的

explicit
美[ɪkˈsplɪsɪt]
adj. 明確的;直言的

mechanism
美[ˈmekənɪzəm]
n. []機制,機能
8.5.5 Writing Signal Handlers

R0. Signal handlers are tricky because they can run concurrently with the main program and with each other.
R1. waitpid(-1, NULL, 0) // 如果有子程式且沒有一個被terminated才會阻塞;沒有子程式則立即返回-1;有terminated的子程式則立即返回其中一個的pid。
G0. Keep handlers as simple as possible.
G1. Call only async-signal-safe functions in your handlers. such as printf, sprintf, malloc, and exit, are not async-signal-safe
G2. Save and restore errno.
G3. Protect accesses to shared global data structures by blocking all signals.
G4. Declare global variables with volatile. The volatile qualifier forces the compiler to read the value of g from memory.
G5. Declare flags with sig_atomic_t. It only applies to individual reads and writes. It does not apply to updates such as flag++ or flag = flag + 10.

declare
美[dɪˈkler]
v. 申明

volatile
美[ˈvɑːlətl]
adj. 易變的,不穩定的

qualifier
美[ˈkwɑlɪfaɪə(r)]
n. 修飾語

individual
美[ˌɪndɪˈvɪdʒuəl]
adj. 單獨的
8.5.6 Synchronizing Flows to Avoid Nasty Concurrency Bugs

This is an example of a classic synchronization error known as a race. In this
case, the race is between the call to addjob in the main routine and the call to
deletejob in the handler. If addjob wins the race, then the answer is correct. If
not, the answer is incorrect. Such errors are enormously difficult to debug because
it is often impossible to test every interleaving. You might run the code a billion
times without a problem, but then the next test results in an interleaving that
triggers the race.

synchronizing
美['sɪŋkrənaɪzɪŋ]
adj. 同步的

avoid
美[əˈvɔɪd]
v. 避免

nasty
美[ˈnæsti]
adj. 令人討厭的

concurrency
美[kən'kʌrənsɪ]
n. 併發

enormously
美[ɪˈnɔrməsli]
adv. 巨大地

interleaving
美[ɪntə()'livɪŋ]
n. 交叉,交錯
8.5.7 Explicitly Waiting for Signals

The sigsuspend function is equivalent to an atomic (uninterruptible) version
of this three instructions:
sigprocmask(SIG_BLOCK, &mask, &prev);
pause();
sigprocmask(SIG_SETMASK, &prev, NULL);

explicitly
美[ɪk'splɪsɪtlɪ]
adv. 明確地

equivalent
美[ɪˈkwɪvələnt]
adj. 相等的
8.6 Nonlocal Jumps
//goto語句只能實現函式內部的跳轉,非本地跳轉可以從一個函式內跳轉到另一個函式內。java的try/catch機制就是用的非本地跳轉。
//1. setjmp所在的函式必須還沒有返回(堆疊還在)
//2. longjmp不能指定0為返回值

The only difference between sigsetjmp/siglongjmp and the setjmp/longjmp functions is that sigsetjmp has an additional argument. If savemask is nonzero, then sigsetjmp also saves the current signal mask of the process in env. When siglongjmp is called, if the env argument was saved by a call to sigsetjmp with a nonzero savemask, then siglongjmp restores the saved signal mask.
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章