- Learn
- Computer Science & IT
- Computer Science
- Operating Systems
- Processes and System Calls
Processes and System Calls
IntermediateLesson 1 of 9 in Operating Systems Course
What you will learn
- Describe the operating system's main jobs and the history and design ideas that explain why it shares and protects the machine the way it does.
- Describe the main jobs of an operating systemExplain how the operating system turns raw hardware into easier, shared and protected resources for programs.
- Explain how multiprogramming and time sharing shaped the OSFollow the steps from batch processing to multiprogramming and time sharing, see why each step needed new protections, and compare the main ways a kernel can be organized.
- Describe the main jobs of an operating system
- Explain what a process is, what the operating system records about each one, and how processes move between running, ready and blocked.
- Explain what a process is and what the OS keeps about itDistinguish a program from a process, describe a process's machine state and address space, and explain how the OS creates a process and keeps track of it.
- Trace a process through its statesUse the running, ready and blocked states and their transitions to trace how processes share one CPU, and recognize the extra states real systems report.
- Explain what a process is and what the OS keeps about it
- Use the Unix process API in C to create child processes, run new programs in them, collect their results, end them and combine these calls into a simple shell.
- Create a child process with forkCall fork, tell parent and child apart by its return value, and predict what each process sees and prints.
- Run a different program with execReplace the program in a process with exec, pass arguments correctly, and explain why Unix separates creating a process from loading a program.
- Wait for children, read exit status and end processesEnd processes with exit and signals, collect a child's result with wait and waitpid, decode its status, and prevent zombies and orphans from causing trouble.
- Build a simple shell with fork, exec, wait and redirectionCombine the process calls into a shell loop that runs commands, redirects input and output, connects commands with pipes and runs jobs in the background.
- Create a child process with fork
- Explain how the hardware separates privileged kernel code from user programs, and how programs cross that boundary in a controlled way through system calls, exceptions and interrupts.
- Distinguish user mode from kernel modeExplain what each CPU mode allows, which operations are privileged, and what happens when a program oversteps its mode.
- Explain how a system call works, step by stepTrace a system call from the library wrapper through the trap into the kernel and back, and interpret its return value and errors.
- Tell traps, exceptions and interrupts apartClassify the events that move the CPU into the kernel, explain how the kernel's handler table works, and predict what happens after each kind of event.
- Distinguish user mode from kernel mode
- Explain how the operating system runs programs directly on the CPU at full speed while keeping control, and how it switches the CPU from one process to another.
- Explain limited direct executionExplain the two problems of running programs directly on the CPU and how user mode, traps and the timer interrupt solve them, step by step from boot to process exit.
- Trace a context switch and estimate its costFollow each step of switching the CPU from one process to another, tell a context switch from a mode switch, and estimate how much CPU time switching costs.
- Explain limited direct execution
Processes and System Calls study guide
1Explain what an operating system does
The OS gives ordinary programs useful ways to compute, store data, and use devices while sharing the machine safely. Its responsibilities explain why a desktop application does not need its own disk driver and why one faulty program should not stop everything. Follow the move from one-job computers to interactive systems, then compare how different kernel designs divide privileged work.
1.1 Describe the main jobs of an operating system
A browser, a compiler, and a music player can all make progress on one computer. Each needs CPU time, memory, and access to devices. The operating system (OS) provides those resources through services that programs can use without controlling the whole machine.
Give programs useful resources
Virtualization turns a physical resource into a convenient virtual resource. CPU virtualization lets many processes behave as though each has its own processor. The OS runs each for a while and preserves its state between turns. Memory virtualization gives each process its own address space: the addresses its instructions can use.
An abstraction hides details behind a useful interface. A file is an abstraction for stored bytes. A program can call write without knowing whether those bytes go to an SSD or a network drive. A system call provides a controlled way to request a kernel service. Device-specific work stays behind the interface.
Share resources and protect programs
As a resource manager, the OS decides who gets CPU time, memory, and device service. It tries to keep hardware useful while giving programs reasonable access. Sharing also needs protection: one program must not overwrite another's private memory or disable the timer to keep the CPU.
The hardware helps enforce this boundary. Application instructions run in user mode with limited permissions. Kernel code runs with the privilege needed to manage the machine. A timer can interrupt a program even if that program never asks the OS for anything.
For a laptop downloading a file while compiling code, follow three separate jobs:
- The network device reports arriving data. The kernel makes it available to the downloading process.
- The OS shares CPU time between the browser, compiler, and other ready processes.
- The compiler requests file operations to store its output. Its code does not drive the storage controller directly.
Separate the kernel from the interface
The kernel is the privileged core. The shell, desktop, and most system libraries run as ordinary programs, even when they are distributed with the OS. Closing a desktop window does not remove the kernel. A server without a graphical interface still needs process management, memory protection, and device services.
On one logical CPU, user code and kernel code take turns. While the compiler executes ordinary user instructions, the kernel is not also executing on that CPU. System calls, exceptions, and hardware interrupts give it control again.
Choose how, then choose who
A mechanism supplies an operation; a policy chooses how to use it. Saving one process's registers and restoring another's is a mechanism. Choosing which ready process gets the next turn is policy. Keeping these separate lets the OS change its scheduling choices without replacing the switching machinery.
OS design balances useful abstractions, performance, protection, reliability, security, and energy use. The extra CPU time and memory spent on management are overhead. Across the subject, three recurring themes are virtualization, concurrency—activities in progress together—and persistence, which keeps stored data beyond a program's lifetime or loss of power.
Key Takeaways
- Virtualization gives programs convenient views of shared hardware.
- Abstractions such as files hide device details behind useful operations.
- The kernel is privileged; the shell and desktop are ordinary programs.
- Mechanism provides an operation; policy chooses when or for whom it is used.
- Protection and low overhead are both goals of OS design.
1.2 Explain how multiprogramming and time sharing shaped the OS
Operating systems grew as computers moved from running isolated jobs to serving many activities at once. Each change solved a practical problem: idle hardware, slow interaction, or failures spreading between programs.
From batches to overlapping work
In batch processing, submitted jobs run one after another without interaction with the person who submitted them. Early support software mainly helped load jobs and perform common I/O operations. If the current job had to wait for a device, the CPU could sit idle.
Multiprogramming keeps several jobs in memory. When one blocks for I/O, another can compute. Suppose a job repeatedly computes for 20 ms and waits for disk I/O for 80 ms. Alone, its CPU utilization is 20 / 100 = 20%. With two such jobs and suitable overlap, useful computation can occupy 40% of the elapsed time. The device's delay has not become shorter; otherwise idle CPU time has been filled.
The gain depends on having work ready. Adding jobs cannot push CPU utilization above 100%, and jobs waiting for the same device can still face a bottleneck. Several jobs in memory also need protection: one must not overwrite another or damage the OS's own data.
Make interaction responsive
Time sharing gives processes short turns on the CPU. A terminal or desktop can respond while other programs continue working. Waiting for a batch job to finish before serving another user's keystroke would feel very different.
| Sharing method | What is divided | Example |
|---|---|---|
| Time sharing | Use of a resource across successive intervals | CPU turns |
| Space sharing | Capacity held by different users at once | Memory regions or disk space |
Concurrency means several activities are in progress during the same period. Their instructions can be interleaved on one logical CPU. Parallelism means instructions actually execute simultaneously on different processing resources. Multiprogramming does not require parallel hardware.
Put services inside or outside the kernel
| Design | Where most services run | Main trade-off |
|---|---|---|
| Monolithic kernel | File systems, drivers, and networking run in kernel mode | Direct calls are efficient; a driver bug can damage the kernel |
| Microkernel | A small privileged core supports user-mode service processes | Service isolation helps contain failures; communication adds work |
| Hybrid kernel | Combines elements of both approaches | The exact service boundary depends on the design |
Linux is monolithic and can load kernel modules. MINIX 3, QNX, and seL4 illustrate microkernel designs. Windows NT and Apple's XNU are commonly described as hybrid designs. A user-mode driver can often be restarted after a crash, while a privileged driver has access that can make its failure system-wide.
Early personal-computer systems such as MS-DOS and classic Mac OS lacked the process memory protection expected today. Modern systems combine OS rules with hardware enforcement. Short CPU turns alone would not stop a program from changing another program's memory; sharing and protection solve different parts of the problem.
Key Takeaways
- Multiprogramming fills I/O waits with another job's computation.
- Time sharing supports interactive use with short CPU turns.
- Concurrent work can be interleaved on one CPU; parallel work executes simultaneously.
- Time sharing divides turns; space sharing divides capacity.
- Kernel organization trades direct service calls against stronger service isolation.
- Multiple resident jobs require memory and privilege protection.
2Describe processes and the states they move through
A program file is only the starting point. To run it, the OS builds and tracks an active process with memory, registers, open descriptors, and a place in the process list. Learn to read that state, then follow a pair of processes as CPU work overlaps with device waits. The difference between waiting for a CPU and waiting for an event explains which process the scheduler can choose.
2.1 Explain what a process is and what the OS keeps about it
An executable on disk can be launched repeatedly. Each launch needs its own changing state so that one instance can pause, resume, or fail independently. That active instance is a process.
Identify the running instance
A program is stored instructions and static data. A process combines a program with its current memory, CPU registers, and I/O state. Three shells can run the same executable while keeping different variables, current directories, and histories.
The program counter (PC) identifies the next instruction. The stack pointer locates the active stack. General registers hold intermediate values. When a process stops running, enough state must be preserved for it to continue at the right instruction with the right values.
Read the address-space picture
A process's address space is the memory its instructions can address. A common teaching layout places code and static data toward lower addresses, a heap above them, and a stack toward higher addresses. The heap supports dynamically allocated objects; the stack supports function calls and local state. In this layout, the heap grows toward higher addresses and the stack toward lower addresses. Actual layouts depend on the system, and malloc implementations can obtain memory in more than one way.
Two processes can print the same virtual address for a variable and still hold different values there. Virtual addresses belong to a process's view of memory. Matching address numbers do not establish shared writable storage.
Start a program
To start a new program image, the OS establishes these pieces:
- Its executable code and data, with parts loaded when needed on modern systems.
- An initial user stack and startup information, including the argument strings and argument vector used by the runtime to call
main. - Memory for dynamic allocation and the initial register state.
- An I/O environment, including inherited file descriptors.
- An entry point where program startup code begins.
On Unix, file descriptors are small integers naming open I/O resources. By shell convention, 0 is standard input, 1 standard output, and 2 standard error. They are often connected to a terminal. A process can inherit additional descriptors; the three familiar numbers are not a limit or a promise that every process always has them open.
Inspect the kernel's record
The process control block (PCB) records information the kernel needs to manage one process: PID, state, saved execution context, memory information, open descriptors, parent, owner, current directory, and accounting information. Linux uses task_struct; xv6 uses struct proc. A process table or process list organizes these records.
While a process runs, its live registers are in the CPU. On kernel entry, its user registers are saved on its kernel stack; a context switch also preserves the kernel execution context. The PCB is not a continuously updated mirror of every user register.
For example, a Linux ps listing might contain 8240 8200 S bash and 8291 8240 R ps. The second process has PID 8291 and parent PID 8240, so it is the shell's child. R covers both running and ready processes. A PID identifies a live process within its PID namespace, but after cleanup that number can be reused.
Key Takeaways
- A process is a program instance with memory, register, and I/O state.
- Identical virtual addresses in different processes can name different data.
- The PCB holds the kernel's management record, not continuously live CPU registers.
- File descriptors are inherited; 0, 1, and 2 have conventional roles.
- PIDs can be reused after a process has ended and been cleaned up.
2.2 Trace a process through its states
A process can exist without executing an instruction right now. Its state tells the OS whether it can use a CPU or must first wait for something else. This distinction explains why a busy computer can have many processes but only a few executing at an instant.
Decide what the process needs
| State | Meaning | Example |
|---|---|---|
| Running | Executing on a CPU | A compiler generating instructions |
| Ready | Able to execute, waiting for CPU time | A computation whose turn just ended |
| Blocked | Waiting for an event before it can continue | A terminal read waiting for input |
A blocked process consumes no CPU time while blocked. Its device or event can still make progress. A ready process already has what it needs except a CPU.
The basic transitions are ready → running when selected, running → ready when descheduled, running → blocked when it must wait, and blocked → ready when its event occurs. Event completion makes a process eligible; it does not grant it the CPU immediately. Choosing among eligible processes is the scheduler's job.
Trace overlapping work
Use one logical CPU and ignore switching overhead. Process A computes for 2 ms, waits for disk I/O for 3 ms, and then computes for 1 ms. Process B needs 4 ms of CPU time. A starts first.
| Interval | CPU | A's state | B's state |
|---|---|---|---|
| 0–2 ms | A | Running | Ready |
| 2–5 ms | B | Blocked | Running |
| 5–6 ms | B | Ready | Running |
| 6–7 ms | A | Running | Finished |
At 2 ms, A starts I/O and blocks. B computes while the disk works. At 5 ms, A's I/O finishes, but the OS lets B finish its fourth CPU millisecond before running A. This is a policy choice, not an extra state transition straight from blocked to running.
The total CPU work is 2 + 1 + 4 = 7 ms, and both finish after 7 ms. If A ran to completion before B began, elapsed time would be 2 + 3 + 1 + 4 = 10 ms. CPU utilization would be 7 / 10 = 70%, because no other work filled the I/O wait.
Read states on a real system
Linux ps combines running and ready as R. It shows interruptible sleep as S, uninterruptible sleep, often for I/O, as D, a stopped process as T, and a terminated but unreaped process as Z. A stopped process is not simply waiting for an ordinary I/O completion. A zombie has finished executing and retains only the record needed to report its result.
A new process also passes through creation before it is ready. On a system with four logical CPUs, at most four single-threaded processes can execute simultaneously. Ready queues organize eligible work; blocked lists track the events processes need. A context switch preserves one process's execution state and restores another's when the OS changes which process runs.
Key Takeaways
- Ready means waiting for a CPU; blocked means waiting for an event.
- An I/O completion moves a blocked process to ready.
- Overlapping device waits with useful CPU work can shorten total elapsed time.
- Linux reports ready and running with the same code,
R. - A zombie is terminated but has not yet been reaped.
- The number of logical CPUs limits simultaneous execution of single-threaded processes.
3Create and control processes with fork, exec and wait
The Unix process interface separates creating a child, replacing its program, and collecting its result. Trace what each call changes and what it preserves, including private variables and shared open-file state. Then assemble the calls into shell behavior: foreground commands, redirection, pipelines, and background jobs. Each step depends on knowing which process is executing it.
3.1 Create a child process with fork
fork() creates a child process from the calling parent. Both continue immediately after the call, so one source-code path becomes two executions. Its return value tells each process which role it has.
Branch on all three results
pid_t rc = fork();
if (rc < 0) {
perror("fork");
exit(1);
} else if (rc == 0) {
printf("child %ld\n", (long) getpid());
} else {
printf("parent of %ld\n", (long) rc);
}
Use <unistd.h> for fork and getpid, <stdio.h> for printing, and <stdlib.h> for exit. On success, the parent receives the child's positive PID; the child receives 0. On failure, the caller receives -1, errno explains the error, and no child exists.
If the parent is PID 5000 and the child is 5001, the parent prints "parent of 5001" and the child prints "child 5001". Neither role is guaranteed to run first. getpid() returns the caller's own PID; getppid() returns its parent's PID. The child does not restart main or repeat instructions before the fork.
Follow private memory and shared I/O
Parent and child begin with matching ordinary memory contents in separate address spaces. If x is 10 before the call and the child sets its copy to 20, the parent's copy remains 10. Even the printed address of x can match: those equal virtual addresses belong to different process address spaces.
Copy-on-write avoids eagerly copying every memory page. Parent and child initially share physical pages with writes protected. When one writes a private page, the kernel arranges a private copy before allowing the write. This preserves the behavior of separate memory while reducing the cost of a child that soon calls exec.
File descriptors behave differently. Their copied entries refer to the same underlying open file description, which includes the current file offset. Sequential reads through an inherited descriptor advance that shared offset. The descriptor table is copied, but the kernel's underlying open-file state can remain shared.
Count only forks that a process reaches
With every call successful, fork(); fork(); leaves four processes: both processes produced by the first call execute the second. A three-iteration loop reached by all processes leaves processes, including the original. A fork inside a parent-only branch is reached by fewer processes, so repeated doubling no longer describes the whole program.
Flush buffered text deliberately
printf can leave text in a user-space buffer. fork copies that buffer with the rest of memory. If output is redirected to a fully buffered stream, text printed before the fork can be flushed by both processes at normal exit.
For printf("start\n"); fork();, the usual line-buffered terminal flushes the newline before the fork. A redirected file may retain it and receive two copies. fflush(stdout) before fork() sends the pending text once. The duplicate comes from copied buffered data, not from executing the earlier printf twice.
Key Takeaways
fork()returns a child PID in the parent, 0 in the child, or -1 on failure.- Both successful paths continue just after
fork(). - Ordinary private memory changes in the child do not change the parent's values.
- Inherited descriptors can share one open file description and offset.
- Process counts depend on which processes reach each fork.
- Flush pending output before a fork when duplicate flushing would be unwanted.
3.2 Run a different program with exec
A process can keep its identity while changing the program it runs. The exec family performs that replacement. Combining it with fork lets a parent continue its work while a child becomes a different program.
Replace the image, keep the process
Successful exec replaces the old code, static data, heap, and stack. The kernel prepares the new program's arguments and entry state, then begins its startup code. The old call site no longer exists, so successful exec never returns to it.
The PID, parent relationship, and current directory survive. Open descriptors survive except those marked close-on-exec. Caught signal dispositions reset to default; ignored dispositions generally stay ignored. Credentials usually remain the same, but an executable's set-user-ID or set-group-ID permissions can change effective credentials when permitted by the system.
| Operation | New process? | Main effect |
|---|---|---|
fork() | Yes | Creates a child with copied execution state |
| Successful exec | No | Replaces the calling process's program image |
Build a valid argument vector
To run wc -l notes.txt, the child can use:
char *args[] = {"wc", "-l", "notes.txt", NULL};
execvp(args[0], args);
perror("execvp");
_exit(127);
The strings are separate arguments, not one combined command line. By convention, args[0] names the program. The final NULL is a pointer marking the end of the array; it is not the string "NULL". Without a valid terminator, the call can read beyond the array.
The lines after execvp handle failure. If the program cannot be found, exec returns -1 and sets errno, for example ENOENT. _exit then ends the child without flushing inherited C output buffers. Returning into the shell loop after failure would accidentally create another shell path.
Read the variant name
The v in execv means arguments arrive as a vector; l variants receive a list. A p variant searches PATH for a program name. An e variant supplies an explicit environment. Linux's underlying system call is execve; the library provides the convenient variants.
execvp("wc", args) searches PATH. execv("wc", args) treats "wc" as a relative pathname in the current directory. An absolute pathname such as /usr/bin/wc can be used where that executable is installed. Exec does not parse shell syntax: a > string in args is just an argument unless a program interprets it itself.
Use the interval before replacement
In the example with parent PID 6000 and child PID 6001, the child becomes wc but remains PID 6001. Its parent can wait for that PID. Before exec, the child can redirect descriptors, connect a pipe, or change directory; the replacement program inherits the prepared environment.
This separation is central to the Unix shell. Windows CreateProcess combines creation and program loading, using parameters to configure the new process. POSIX also offers posix_spawn for a combined operation.
Key Takeaways
- Exec replaces a program image without creating a process or changing its PID.
- On success exec never returns; following statements handle failure.
- Terminate argument vectors with a
NULLpointer. pvariants searchPATH; a pathname-only variant does not.- Descriptor setup before exec lets an unchanged program participate in redirection and pipes.
3.3 Wait for children, read exit status and end processes
A parent needs to learn whether a child finished and how it ended. Process termination and result collection are separate steps: the child exits, then its parent reaps the kernel's remaining record.
End a process
Returning from main or calling exit(status) ends normal execution. exit flushes C output buffers and runs registered exit handlers. _exit(status) ends without that library cleanup, which is useful after a failed exec in a forked child. By convention, 0 means success and nonzero means failure.
A signal can also end a process. SIGTERM requests termination and can be handled; SIGKILL cannot be caught or ignored. SIGSTOP stops execution and also cannot be caught or ignored; SIGCONT resumes a stopped process. A terminal normally sends SIGINT for Ctrl-C and SIGTSTP for Ctrl-Z to the foreground job. A signal is a software notification to a process, not a hardware interrupt.
Wait for one result
wait(&status) waits for one child and returns its PID. waitpid(pid, &status, 0) selects a particular positive child PID. A finished, unreaped child can be collected immediately. Otherwise, an ordinary blocking wait suspends the parent until a matching result is available.
With WNOHANG, waitpid returns 0 when matching children exist but none has a result ready. A positive result identifies the collected child. A result of -1 is an error: ECHILD means no matching child remains; EINTR means a signal handler interrupted the wait.
Decode the status before using it
int status;
pid_t r;
do {
r = waitpid(child, &status, 0);
} while (r == -1 && errno == EINTR);
if (r == -1) {
perror("waitpid");
} else if (WIFEXITED(status)) {
printf("exit %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("signal %d\n", WTERMSIG(status));
}
This uses <sys/wait.h>, <errno.h>, and <stdio.h>. The stored status encodes the manner of termination as well as a result. WEXITSTATUS is meaningful after WIFEXITED succeeds; WTERMSIG follows WIFSIGNALED.
Only the low eight bits of a normal exit value are available. exit(300) therefore yields 44, while exit(-1) yields 255. On Linux, exit(3) commonly produces raw wait status 768; printing that raw integer is not decoding the exit code.
Reap zombies and recognize orphans
A zombie has terminated but retains its PID and result until a wait collects them. It executes no code, so sending SIGKILL cannot remove it. A long-running parent must reap each child. To collect all children, keep waiting after each positive PID, retry on EINTR, and stop on ECHILD; report other errors.
An orphan has lost its parent and can still run. Linux reparents it to an appropriate subreaper or the namespace's init process, which can collect its result later. Ordinary signal permissions depend on user identities and privileges. Running as root grants permissions, not kernel-mode execution.
Key Takeaways
- Each successful wait collects one child's result.
- Decode normal exit and signal termination with their matching status macros.
WNOHANGreturns 0 when a matching child exists but has no result ready.- Retry an interrupted wait on
EINTR;ECHILDmeans no matching child remains. - A zombie has ended; an orphan has lost its parent and may still be running.
SIGKILLandSIGSTOPcannot be caught or ignored.exitflushes C buffers;_exitdoes not.
3.4 Build a simple shell with fork, exec, wait and redirection
A shell turns command text into process creation, descriptor setup, and result collection. It is an ordinary user program using the same protected OS services available to other programs.
Launch an external command
For wc -l notes.txt, the shell builds the argument vector and launches the command. The parsed words form a null-terminated argument vector, args:
pid_t child = fork();
if (child == -1) {
perror("fork");
} else if (child == 0) {
execvp(args[0], args);
perror("execvp");
_exit(127);
} else {
int status;
pid_t result;
do {
result = waitpid(child, &status, 0);
} while (result == -1 && errno == EINTR);
if (result == -1) perror("waitpid");
else if (WIFEXITED(status)) {
printf("exit %d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("signal %d\n", WTERMSIG(status));
}
}
This uses <unistd.h>, <sys/wait.h>, <errno.h>, and <stdio.h>. The surrounding shell reads and parses each command, runs this launch path, then displays its next prompt.
Only the child replaces its program; the shell can collect a command crash as a termination result. Built-ins such as cd must change the shell's own state: changing a child's directory would leave the parent shell where it was.
Redirect a descriptor before exec
For ls -l > out.txt, the child opens the destination for writing, creating or truncating it. Then it makes standard output refer to that file:
int fd = open("out.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644);
if (fd == -1) { perror("open"); _exit(1); }
if (dup2(fd, STDOUT_FILENO) == -1) {
perror("dup2"); _exit(1);
}
if (fd != STDOUT_FILENO && close(fd) == -1) {
perror("close"); _exit(1);
}
open needs <fcntl.h>; descriptor calls and _exit use <unistd.h>. The creation mode is filtered by the process's file-creation mask. The fd != STDOUT_FILENO check keeps descriptor 1 open even if open itself returned 1. After successful setup, exec preserves descriptor 1 and ls writes normally without knowing about redirection.
An older approach closes descriptor 1 before opening the file: open returns the lowest unused descriptor. dup2 expresses the destination explicitly. Input redirection similarly connects a readable file to descriptor 0.
Connect two commands
For ls | wc -l, pipe(fds) creates a read end fds[0] and write end fds[1]. The producer child connects the write end to descriptor 1. The consumer child connects the read end to descriptor 0. After duplication, each closes the original pipe descriptors it does not need. The parent closes its copies and waits for both children.
Create both children before waiting for either. A producer can fill the pipe and block; the reader must exist to drain it. The reader reaches end-of-file only when all write descriptors are closed and buffered pipe data has been consumed. An unused write end held by the parent can keep wc waiting forever.
Keep the prompt available
For sleep 60 &, the shell launches the child and presents the next prompt without waiting immediately. It later uses nonblocking waits or responds to SIGCHLD to reap finished children.
Exit status also controls command combinations. make && ./app starts the second command only after success; make || echo failed starts the second only after failure. These decisions use the decoded result, not the raw encoded wait status.
Key Takeaways
- An external command runs in a child; a state-changing built-in runs in the shell.
- Redirection changes descriptors in the child before exec.
- A pipe connects a producer's standard output to a consumer's standard input.
- Launch both sides before waiting, and close unused pipe ends.
- End-of-file requires every pipe write end to be closed after buffered data is consumed.
- Background execution postpones waiting; the shell must still reap the child later.
4Explain user mode, kernel mode and system calls
User programs need OS services without gaining control of the machine. Hardware privilege modes create that boundary, and controlled entry paths let the kernel act on requests and events. Trace a system call through its library wrapper and kernel handler, then distinguish deliberate traps, instruction faults, and device interrupts by their causes and possible outcomes.
4.1 Distinguish user mode from kernel mode
The kernel must let programs compute quickly while stopping operations that could take over the machine. The CPU's privilege mode is the hardware boundary that makes both possible.
Separate computation from privileged control
In user mode, instructions can access permitted process memory and perform ordinary computation. They cannot freely change the hardware configuration that protects other programs. In kernel mode, also called supervisor or privileged mode, the OS can perform the protected operations needed to manage the machine.
Privileged operations include programming the timer, disabling interrupts, installing interrupt handlers, changing memory-translation control registers, directly controlling protected devices, and halting the CPU. If any application could disable the timer, short CPU turns would depend on that application's cooperation.
| Platform | Application mode | Kernel mode |
|---|---|---|
| x86-64 on Linux or Windows | Ring 3 | Ring 0 |
| AArch64 | EL0 | EL1 |
AArch64 also provides EL2 for hypervisors and EL3 for secure firmware. These names identify hardware privilege levels, not different kinds of user accounts.
Enter at a controlled address
User code cannot raise its own privilege and choose any kernel address to execute. Entry happens through a system call, an instruction-caused exception, or a hardware interrupt. The CPU transfers control to an entry point configured by the OS. Kernel return code restores the saved user state and lowers the privilege level to resume application code.
The kernel also protects its data with memory permissions. A process may have kernel addresses in its virtual layout while still lacking user-mode permission to access them. Knowing an address does not grant access to the bytes there.
Consider an x86-64 Linux application executing hlt, an instruction intended to halt a CPU until an event. In user mode the instruction causes an exception. Linux normally sends SIGSEGV, whose default action terminates that process. The application does not halt the whole computer; the protection boundary turns the attempted privileged operation into an event the kernel handles.
Keep identity separate from mode
A root or administrator process is still a user-mode program while its own instructions run. Its user identity gives it broader permission to request services. It still enters the kernel through controlled paths, and the kernel checks the request.
For example, a privileged maintenance utility may be allowed to open a protected file. The utility asks through a system call; it does not become kernel code merely because the request is allowed. Conversely, when kernel code services an ordinary user's read, it executes in kernel mode even though the caller has no administrative identity.
On one logical CPU, this is a sequence: user instructions, kernel entry, kernel work, return to user instructions. It is not simultaneous execution of a program and a second OS task on that same CPU. Separate logical CPUs can execute different modes at the same instant.
Key Takeaways
- User mode permits ordinary computation while restricting machine-control operations.
- Kernel entry uses OS-configured entry points.
- Root is a user identity; kernel mode is a CPU privilege state.
- A forbidden user instruction raises an exception so the kernel can respond.
4.2 Explain how a system call works, step by step
A C program often appears to call an ordinary function when it needs an OS service. Underneath a system-call wrapper, a controlled CPU transition lets kernel code validate and carry out that request.
Distinguish a library call from a kernel request
The C library implements strlen in user space without a system call. printf formats data and may buffer it; a later write transfers bytes through the kernel. A thin read wrapper arranges arguments according to the platform's system-call convention and executes the entry instruction.
POSIX describes interfaces for Unix-like systems. Linux implements many services grouped broadly as process control, file and device operations, information, communication, and protection. A system-call number selects a service from the kernel's dispatch table. Numbers are platform-specific: Linux x86-64 uses 1 for write and 39 for getpid; AArch64 uses 64 for write.
Follow one write request
For write(1, "hi\n", 3) on Linux x86-64, follow the request in order:
- The wrapper places service number 1 in
rax, descriptor 1 inrdi, the buffer address inrsi, and count 3 inrdx. syscallpreserves the return address and flags in registers, enters kernel mode, and jumps to the configured entry point. It does not automatically switch stacks.- Kernel entry code establishes the process's kernel stack and saves the remaining user state.
- Kernel dispatch selects
write; the implementation checks the descriptor, user-buffer access, and the request before passing bytes toward the output resource. - On a complete successful write, the result is 3 bytes. Kernel return code restores user state and resumes the wrapper, which returns to the caller.
Descriptor 1 may name a terminal, file, or pipe. The number alone does not identify the output device. A write can also return a smaller successful byte count; callers that must transfer every byte track the amount actually written.
Check errors at the interface
The kernel treats user pointers and other arguments as untrusted. A request to copy from an inaccessible buffer can fail with EFAULT; controlled copying avoids granting the caller access to kernel memory.
On Linux, a kernel error is a negative error code. The usual C wrapper reports -1 and sets errno. For example, if open("missing.txt", O_RDONLY) fails because the file does not exist, errno is ENOENT. perror("missing.txt") can display "missing.txt: No such file or directory". Inspect errno after a reported failure, not as the primary success test: a successful call need not clear an earlier error.
Account for time spent in the kernel
A call that can finish now may return to the same process. A blocking terminal read can instead put that process into the blocked state and let another run. The input event makes the reader ready; once scheduled, it completes the return path.
Kernel entry adds work beyond a normal function call: saving state, changing privilege, checking arguments, and restoring execution. Library buffering can combine small outputs into fewer writes. On Linux, strace ls runs ls while reporting its system calls, arguments, and results.
Key Takeaways
- A library function can do all its work in user space or invoke system calls.
- A service number selects a kernel operation; the caller does not choose an arbitrary kernel address.
- Kernel code validates descriptors, pointers, and other arguments.
- Use the return value to detect failure, then inspect
errno. - A blocking system call can cause a context switch; kernel entry alone need not.
- System-call numbers and register conventions depend on the OS and architecture.
4.3 Tell traps, exceptions and interrupts apart
Kernel entry can mean a service request, an instruction problem, or a device event. Classifying the cause helps you predict what the OS will do and whether the same instruction should run again.
Ask what caused the event
| Event | Cause | Timing relative to the current instruction |
|---|---|---|
| System-call trap | The program deliberately requests a service | Synchronous |
| Exception or fault | The current instruction needs special handling | Synchronous |
| Hardware interrupt | A timer or device signals the CPU | Asynchronous |
Synchronous means tied to the instruction being executed. It does not mean the same input causes exactly the same faults on every run. A load can fault when its page is absent and succeed later when that page is resident. Asynchronous means the event's cause is independent of the current instruction, such as a disk completing earlier work.
CPU manuals use these terms in different ways. Follow the cause: deliberate service request, instruction-caused event, or hardware notification.
Dispatch to the right handler
At boot, the OS installs protected handler addresses. A trap or interrupt table maps event kinds to kernel routines. On x86-64, the interrupt descriptor table (IDT) serves interrupts and exceptions; syscall uses an entry address in a special processor register. Only privileged code can configure these destinations.
On an interrupt from user mode, x86-64 hardware saves a return frame on a kernel stack. Entry code saves additional registers before doing the work. The syscall path preserves its initial return state in registers and relies on entry code to establish the kernel stack. Treating all entry paths as identical hardware actions hides an important implementation difference.
Choose the outcome
A valid page that is absent from memory can be loaded, after which the faulting instruction is retried. An access to memory the process may not use normally leads Linux to send SIGSEGV. An exception is therefore not always fatal, and it is not always a request to skip the current instruction.
For an actual x86-64 integer idiv instruction with divisor zero, the CPU raises a divide-error exception. Linux normally delivers SIGFPE; its familiar message mentions floating point even for this integer instruction. AArch64 integer divide instead gives zero for a zero divisor. C division by zero has undefined behavior, so portable C code cannot rely on either machine outcome.
When a disk read finishes, the interrupt handler records completion and makes the waiting process ready. That process may run later. A timer interrupt gives the OS a chance to reconsider the current CPU user, but the handler can also return to that same process.
Distinguish a signal from an interrupt
A hardware interrupt notifies the CPU; a signal notifies a process through the OS. An exception can cause the kernel to send a signal, and one process can request a signal for another through kill. Normal device completions are interrupts without implying program errors.
Kernel code must also protect shared data while events occur. It can disable interrupts briefly on a CPU and use locks where needed. Long interrupt-disabled periods delay device handling; disabling local interrupts alone does not prevent another CPU from accessing shared data.
Key Takeaways
- Traps and exceptions arise from the current instruction; hardware interrupts have an external cause.
- A recoverable fault can be repaired and its instruction retried.
- Protected entry tables keep user programs from replacing kernel handlers.
- A signal targets a process; a hardware interrupt targets CPU handling.
- Device completion makes a blocked process ready, and a timer interrupt need not change processes.
5Explain how the OS shares the CPU with limited direct execution
Fast execution and OS control have to work together. Limited direct execution lets ordinary instructions run on the hardware while modes, protected entry points, and a timer keep the kernel in charge. Follow what happens when the OS returns to the same process and when it resumes a different one. The saved state and switching costs explain how short CPU turns can support interactive work.
5.1 Explain limited direct execution
Running each application instruction in a software simulator would make CPU sharing expensive. Letting an application control the machine without limits would make sharing unsafe. Limited direct execution (LDE) uses ordinary hardware execution with a protected path back to the OS.
Solve two different control problems
Direct execution means a process's ordinary instructions execute on the CPU itself. The OS does not examine and approve every arithmetic instruction. Two problems remain: restricting operations that could damage the machine, and regaining control when a program does not voluntarily stop.
User mode solves the restriction problem. System-call traps let a program request services without choosing arbitrary privileged code. A hardware timer solves the control problem: it can interrupt an application that makes no calls at all. Together, these mechanisms support CPU virtualization at low overhead.
Prepare before applications run
At boot, the kernel configures event handlers and initializes the timer. These setup operations are privileged. Later user programs cannot redirect the handlers or disable the timer to avoid losing their turns.
To start a process, the OS creates its management record and memory image, prepares startup arguments and a user stack, and establishes initial register values. It arranges an initial saved context so the normal kernel-to-user return path can start the program. Conceptually, the process begins by returning from a trap it never made.
The detailed saved-frame layout depends on the CPU and OS. The useful design idea is reuse: the same restoration machinery can resume a suspended process or start a newly prepared one.
Return to the kernel voluntarily
During a system call, hardware preserves the initial return state and transfers control. Kernel entry code saves the additional registers on the process's kernel stack. After completing a nonblocking request, the kernel restores the process and returns to user mode. If the request blocks, another ready process can run first.
When main returns, runtime exit processing ultimately asks the kernel to terminate the process. Its memory can be freed while its termination record remains until a parent reaps it.
Return without cooperation
A cooperative system depends on programs making calls, yielding, or causing exceptions. An endless loop that does none of these can monopolize a CPU. Classic Mac OS illustrates this weakness.
A non-cooperative design uses a timer interrupt to force kernel entry. Consider a teaching model with one logical CPU and a periodic timer every 4 ms. The timer produces 1000 / 4 = 250 ticks per second. A user process stuck in while (1) { } is interrupted at the next tick. The kernel can then run a different ready process; the loop need not reach a system call first.
The tick is an opportunity to act, not a requirement to switch processes. The scheduler may let the interrupted process continue. Timer handling and saved-state restoration are mechanisms; the scheduler's choice is policy. Real response time also depends on kernel work and when interrupts can be handled, so a timer period by itself is not an application response-time guarantee.
Key Takeaways
- LDE runs ordinary user instructions directly with hardware-enforced limits.
- User mode restricts operations; system calls provide controlled privileged services.
- A timer lets the OS regain control without cooperation from user code.
- Boot-time setup protects handler addresses and timer configuration.
- A timer tick gives the scheduler a choice; it does not require a process switch.
5.2 Trace a context switch and estimate its cost
Entering kernel mode does not necessarily change the running process. A context switch occurs when the kernel preserves one process's execution state and resumes another's. This requires both user-state preservation and a change in the kernel's own execution context.
Follow A out and B in
For a timer-driven switch on x86-64, trace the layers:
- A executes user instructions. The timer interrupts it.
- Hardware moves to kernel mode and saves A's interrupt return frame on A's kernel stack. Entry code saves A's other user registers there.
- The scheduler chooses B. The switch routine saves A's kernel execution context and restores B's saved kernel context, including its kernel stack pointer.
- The kernel changes to B's address-space context as needed. It is now running on B's behalf using B's kernel stack.
- Kernel exit code restores B's user registers. The return instruction restores B's return state and enters user mode. B resumes where it previously stopped.
The first save preserves A's interrupted user execution. The second preserves the kernel's place while handling A. They are not two identical full copies of the same register set. A PCB or associated context structure and the per-process kernel stack work together to preserve the state.
Identify the event and the decision
A blocking call, process exit, or a timer decision can lead to a switch. A device interrupt can make another process ready, and scheduling may then select it. All switching machinery runs in the kernel; an application does not save its own registers to volunteer for interruption.
| Situation | Mode transition? | Process change? |
|---|---|---|
| Nonblocking service returns to its caller | User → kernel → user | No |
| Timer handled, same process resumes | User → kernel → user | No |
| A blocks and B resumes | Kernel entry, then B's return path | Yes |
A context switch preserves the execution state needed to continue. Time passes and the outside world can change: shared file offsets and external inputs are not frozen while a process is paused.
Account for direct and indirect costs
Direct work includes running the scheduler, saving and restoring registers, and selecting an address space. Translation caches may need adjustment; tagged translations can avoid discarding all old entries. Indirect costs follow when B has to refill CPU caches or cached address translations displaced by A. The cost depends on hardware and workload, so use measured or stated values when calculating overhead.
Suppose a switch, including its relevant effects, costs 5 µs and useful CPU turns last 10 ms. Convert 10 ms to 10,000 µs. The switching share is 5 / (10,000 + 5), about 0.05%. For useful turns of 1 ms it is 5 / 1005, about 0.50%; at 0.1 ms it is 5 / 105, about 4.8%.
The denominator includes useful work plus switching time for one repeated cycle. A smaller turn can improve opportunities for interactive work but spends a larger fraction on repeated switching. The timer and switching code make short turns possible; scheduling policy must weigh that cost against responsiveness.
Key Takeaways
- Kernel entry can return to the same process without a context switch.
- User-state saving on entry and kernel-context saving during a switch serve different purposes.
- Resuming B requires B's kernel stack, saved registers, and address-space context.
- Switching costs include direct bookkeeping and later cache or translation refills.
- Overhead share is switch cost divided by useful turn plus switch cost.
- Shorter turns increase the switching share for a fixed per-switch cost.
Processes and System Calls examples
1See what the OS contributes
12 steps
- 1IntroductionStart with several programs
Imagine a laptop compiling a project while playing music and receiving network data. Each application needs CPU time, memory, and I/O, yet none controls the whole machine.
Follow who supplies those resources, how several jobs make progress, and where the privileged services run. The recurring question is concrete: what work does the application request, and what work must the OS manage?
- 2ExplanationHide the device details
The OS offers abstractions: useful interfaces that hide lower-level machinery. A program opens a file and reads bytes without implementing commands for every storage device.
A system call requests a kernel service through a controlled interface. The kernel checks and performs the protected work. The application still decides which data it wants; it does not gain permission to drive the device directly.
- 3ExampleTrace a compiler output file
A compiler produces bytes for an executable and requests a write. The kernel checks the output resource and handles the storage work behind the file interface.
At the same time, the OS manages the compiler's memory and shares CPU time with the music player. One action—saving a file—therefore sits within several OS responsibilities: abstraction, resource management, and protection of the other programs.
- 4Key InsightGive each process a usable machine
Virtualization presents a physical resource through a useful private view. A process can make progress as though it has a processor of its own, even though its instructions take turns with other processes.
Its memory view is also private: the address it uses need not identify the same physical bytes in another process. CPU and memory virtualization give programs convenient models while the OS manages the actual shared hardware.
- 5ChallengeLocate the privileged part
A computer has no graphical desktop installed, but it runs services, stores files, and shares CPU time. Has it lost the essential OS core? Explain.
---reveal---
No. The kernel still manages processes, memory, and device services. A graphical desktop is a user program on top of those services. Its absence changes the interface a person sees, not the need for the kernel's resource-management work.
- 6ExplanationSeparate the operation from the choice
A mechanism makes an action possible. Saving one process's registers and restoring another's provides the machinery for switching.
A policy chooses how to use it, such as deciding which ready process gets the next CPU turn. The distinction matters when a design changes: a new choice rule can reuse the same reliable switching code. Efficient mechanisms alone do not decide what is fair.
- 7ExplanationFill an otherwise idle wait
A batch system can leave the CPU idle while its current job waits for I/O. Multiprogramming keeps other jobs available and runs one during that wait.
The waiting job does not compute and the device has not become faster. The gain comes from overlapping independent work: one process waits while another uses the CPU. Several resident programs also require protection so one cannot overwrite another's memory.
- 8ExampleCalculate the utilization gain
A job computes for 20 ms, then waits for I/O for 80 ms. Alone, one 100 ms cycle contains only 20 ms of CPU work: utilization is 20%.
With a second such job and suitable overlap, another 20 ms of computation can fill otherwise idle time, giving up to 40% in this illustration. The improvement uses waiting time productively; adding jobs cannot raise CPU utilization beyond 100%.
- 9ConnectionGive interactive work short turns
Time sharing gives processes short CPU turns so interactive work need not wait for a whole batch job. This is concurrency even on one logical CPU: several activities progress through interleaving.
Parallelism needs actual simultaneous execution on separate processing resources. Memory and disk capacity illustrate a different division, space sharing, in which different users hold separate portions at once.
- 10ExplanationChoose a service boundary
A monolithic kernel, such as Linux, runs most services together with privilege. Direct calls are efficient, but a faulty driver can damage kernel state.
A microkernel, such as seL4, leaves more services in separate user processes. Isolation can contain a service failure, at the cost of communication and mode transitions. Windows NT and XNU mix approaches. The boundary determines which failures can spread and which services can be restarted.
- 11ChallengeConnect sharing and protection
A one-CPU system runs several jobs and switches to another whenever one waits for disk I/O. A proposal would let every job overwrite any memory address. Explain the utilization benefit and the flaw in this proposal.
---reveal---
Multiprogramming fills I/O waits with another job's computation. Unrestricted writes would let one job damage another or the OS. Overlapping work improves resource use, but shared use still needs enforced memory and privilege protection.
- 12RecapRead a design in three questions
For an OS design, ask which resource is shared, what interface a program sees, and what boundary protects other work.
These questions connect CPU virtualization to process turns, files to hidden device details, and kernel organization to failure isolation. Mechanisms carry out protected operations; policies decide how to distribute their use. Concurrency can come from interleaving on one CPU.
2Follow a process through CPU and I/O work
13 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionFollow an active instance
- 2ExplanationTurn a file into a process
- 3ExplanationPreserve the next instruction
- 4ExampleRead a process listing
- 5ChallengeInterpret equal addresses
- 6TipRead descriptors as inherited resources
- 7ExplanationAsk what is missing
- 8ExampleStart the timeline
- 9ExampleFinish the timeline
- 10ChallengeChange the ready-process decision
- 11ConnectionRecognize real state names
- 12ChallengeConnect records to CPU capacity
- 13RecapRead state as eligibility
3Build a command from process calls
23 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionGive each call one job
- 2ExplanationSplit one execution into two
- 3ExampleFollow a private value
- 4ExampleCount a branch, not source calls
- 5ChallengeCount the printing paths
- 6TipCheck what was copied
- 7ExplanationReplace the child's program
- 8ExamplePass separate argument strings
- 9ChallengePredict a successful replacement
- 10Key InsightUse the gap before exec
- 11ExplanationCollect one child result
- 12ExampleDecode normal exit
- 13ExplanationLeave no uncollected results
- 14ChallengeHandle interruption correctly
- 15TipChoose a termination request
- 16ExplanationReturn to a foreground prompt
- 17ExampleRedirect output before replacement
- 18ChallengePreserve the output destination
- 19ExampleConnect the two pipe ends
- 20Key InsightLaunch before waiting
- 21ConnectionKeep background work accounted for
- 22ChallengeTrace an empty pipeline
- 23RecapTrack identity, image, and result
4Trace a request across the privilege boundary
15 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionAsk why the kernel was entered
- 2ExplanationLimit what applications can control
- 3ExampleSeparate identity from privilege
- 4ChallengePredict a forbidden instruction
- 5ExplanationFind the actual system call
- 6ExamplePrepare one write
- 7ExampleEnter and validate
- 8ExampleInterpret the return
- 9ChallengeFollow a blocked read
- 10ExplanationClassify by the cause
- 11ExampleRepair or terminate
- 12TipKeep signals at the process layer
- 13ChallengeClassify a device completion
- 14ChallengeSeparate two kinds of entry
- 15RecapTrace cause, checks, and outcome
5Keep control while programs execute directly
15 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionKeep speed and control together
- 2ExplanationSolve two control problems
- 3ExamplePrepare the machine and process
- 4ConnectionSee the cooperative weakness
- 5ExampleInterrupt an endless loop
- 6ChallengeIdentify the missing mechanism
- 7ExplanationSave the interrupted user path
- 8ExampleSave the kernel path too
- 9ExampleReturn through B's saved state
- 10ChallengeSpot a mode-only transition
- 11ExplanationCount the costs after a switch
- 12ExampleBuild the full cycle denominator
- 13ChallengeEstimate a changed turn length
- 14ChallengeConnect a blocked call to resumption
- 15RecapFollow who owns the return path
Processes and System Calls practice questions
Set 1: Resources, processes, and protection10 Practice Questions
Question 1 of 10
Show answerHide answer
Question 2 of 10
Show answerHide answer
Question 3 of 10
Show answerHide answer
Question 4 of 10
Show answerHide answer
Question 5 of 10
Show answerHide answer
Question 6 of 10
Show answerHide answer
Question 7 of 10
Show answerHide answer
Question 8 of 10
Show answerHide answer
Question 9 of 10
Show answerHide answer
Question 10 of 10
Show answerHide answer
Set 2: Create, replace, and collect a process10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
Every fork succeeds. How many processes reach puts("done") in this code?
if (fork() == 0) {
fork();
}
puts("done");
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
/opt/course/bin/checker, and PATH includes /opt/course/bin. There is no file named checker in the current directory. Why does execv("checker", args) fail to locate it?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
exit(515). After a successful wait and a true WIFEXITED test, what does WEXITSTATUS report?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
waitpid(child, &status, WNOHANG) returns 0. What has happened?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
SIGKILL leaves the entry visible. What action releases this child's retained result record?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
producer | consumer. The producer exits, but the consumer waits forever after reading all available bytes. The shell closed its pipe copies; the consumer still holds its inherited original write-end descriptor. What fixes the hang?Show answerHide answer
Save this lesson to see this answer.
Set 3: Follow kernel entry and CPU switching10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
errno is ENOENT. What should the caller conclude?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Set 4: Trace process behavior and resource sharing10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
A single-threaded process has private x equal to 6. Every fork succeeds. All processes reach puts. How many lines contain "9"?
pid_t p = fork();
if (p == 0) x += 3;
fork();
if (x == 9) puts("9");
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
execvp for a program that does not exist. Its next statement prints an error. Why can that statement execute?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
errno EINTR. What should the parent do to keep collecting children?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
chdir only in a forked child to implement cd, waits for that child, then launches another command. Why does the next command begin in the old directory?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Set 5: Diagnose process and kernel interactions10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
A program has private x equal to 2. Every fork succeeds. How many processes print "hit"?
pid_t p = fork();
if (p > 0) {
x = 7;
fork();
}
if (x == 7) puts("hit");
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
WIFSIGNALED after waitpid succeeds. What macro gives the terminating signal number?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
SIGSEGV. What sequence distinguishes the two events?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
dup2(fd, 0), closes fd unconditionally, and execs the command. Why can the command's standard input be closed?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Stuck on your own question? Homework Help
Key Terms
A
Abstraction
Address space
Argument vector
B
Background job
Batch processing
Blocked state
Built-in command
C
Child process
Close-on-exec
Concurrency
Context switch
Cooperative control
Copy-on-write
CPU utilization
E
End-of-file
errno
errno is a C library error indicator set by many interfaces on failure and inspected after the return value reports an error.Exception
Exception level
Exec
Exit status
F
File descriptor
Fork
H
Hardware interrupt
K
Kernel
Kernel context
Kernel mode
Kernel stack
L
Library wrapper
Limited direct execution
M
Mechanism
Microkernel
Mode switch
Monolithic kernel
Multiprogramming
N
Nonblocking wait
O
Open file description
Operating system
Orphan
Output buffer
Overhead
P
Page fault
Parallelism
Parent process
PATH
execvp.Pipe
Policy
Privileged instruction
Process
Process control block
Process ID
Program
Program counter
Protection ring
R
Ready state
Reaping
Redirection
Return from trap
Running state
S
Scheduler
Shell
Signal
Space sharing
Stack pointer
System call
System-call number
T
Time sharing
Time slice
Timer interrupt
Translation lookaside buffer
Trap
Trap table
U
User mode
V
Virtualization
W
Wait status
Z
Zombie
About this lesson
Make your own Study Materials
Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.