Skip to main content

Section 2.1 Processes

Start by reading the Process chapter introduction (before 4.1).

Practice 2.1.1.

The operating system implements mechanisms and processes. What do those refer to?
  • Mechanisms are pure hardware features that implement a needed piece of functionality.
  • Mechanisms are low level protocols that implement a needed piece of functionality.
  • Mechanisms are function calls that implement a needed piece of functionality.
  • Policies are algorithms that the OS employs to make some decision.
  • Policies are structured documents that the OS employs to make some decisions.
  • Implementing CPU virtualization requires both mechanisms and policies.
  • A context switch is a policy.
  • Scheduling a process requires a policy.
Read section 4.1 then answer this question.

Practice 2.1.2.

What parts of the machine state constitute a process?
  • the memory that the process can address
  • the values of the various registers
  • the file location in the disk that holds the process code
  • Process code is generally in memory once the process starts running, and changes to the disk version will not change the running program.
  • the program counter
  • the files that the process has open
  • stack of function calls the process is currently executing
  • the results of function calls the process has completed
  • These would not be maintained anywhere long term.
Read section 4.2 then answer this question.

Practice 2.1.3.

What are the general capabilities expected of a modern process API?
  • creating new processes (by for example running a program from the shell)
  • forcefully stopping a process
  • changings a process’ id
  • waiting for a process to end
  • suspending a process’ execution for a period of time
  • changing a process’ arguments
  • finding out information about the running process, like how long it has been running for
  • allowing a process to access another process’ information
Read section 4.3, about what goes on during process creation.

Practice 2.1.4.

Which of the following are parts of the steps for creating a new process?
  • Reading the program code from disk into memory
  • Removing other processes from memory
  • This would not in general be needed, unless there is limited memory available. The OS can manage having multiple processes in memory at the same time.
  • Allocating memory for the process’ stack
  • Allocating memory for the process’ heap
  • Setting up standard file descriptors
Read section 4.4 on process states.

Practice 2.1.5.

What are the states that a process can be in?
  • Ready
  • Running
  • Suspended
  • A process that is suspended is actually in the ready state.
  • Blocked
  • Terminated
  • While it may be necessary to consider this state temporarily, terminated processes are simply removed from the system and their resources are reclaimed.

Practice 2.1.6.

Read section 4.5 about the data structures used to represent a process. Also take a look at our xv6-riscv code, specifically kernel/proc.h. How do those definitions compare to what you see in the book? How do the process states map to the ones discussed in the book?

Practice 2.1.7.

Looking at the proc_state options in the code, which of those options describes the state of a process after it has been terminated but before it has been fully eliminated from the system?
  • UNUSED
  • USED
  • No this is actually the state when the process structure is being set up.
  • SLEEPING
  • No, this is basically the blocked state.
  • ZOMBIE
  • Unix programmers certainly have a weird sense of humor, right?

Practice 2.1.8.

Looking at the proc_state options in the code, which of those options describes the state of the process when it is in what the book described as the "ready" state?
  • UNUSED
  • USED
  • No this is actually the state when the process structure is being set up.
  • RUNNABLE
  • Very good!
  • SLEEPING
  • No, this is basically the blocked state.
  • RUNNING

Practice 2.1.9.

Practice 2.1.10.

In kernel/proc.c you will find a function that is used to allocate a new "process id" (usually referred to as a pid) for a to-be-created process. Locate this function (you should recognize the acronym name of it when you see it). How does the system determine this pid?
  • It selects a random integer, making sure the integer is not in use already.
  • It uses an ever-increasing integer counter.
  • It uses the index in the proc array where the process will be stored.
  • It uses the smallest positive integer that is not already being used (so if a process terminates, its process id can be used for a later process).
Now we look at the Process API chapter which discusses important system calls that the kernel provides to enable us to manage processes. Start by reading section 5.1 about the fork system call, quite possibly the weirdest function you have seen. Compile and run the code in figure 5.1, which can also be found in the ostep/cpu-api/p1.c code file. (You can build all programs by doing make all from that directory, then delete them when you are done by running make clean.)
Make sure you really understand which lines from that file are executed in the child process, which lines are executed in the parent, and which are executed in both.

Practice 2.1.11.

Practice 2.1.12.

When a fork call happens, where does the child process start execution?
  • In main().
  • Exactly where the fork call happens.
  • At a location we specify as part of the fork call.

Practice 2.1.13.

Practice 2.1.14.

What would happen if the attempt to fork a process fails (for example there is no room in the system for more processes)?
  • The fork call returns a negative number.
  • The system freezes.
  • An exception is thrown.
  • The fork call returns 0.

Practice 2.1.15.

This is a bit more open-ended: Change program 1 so that it creates a specific number of children (stored in some variable N). You need to be careful, as a naive approach by wrapping everything in a for loop will create many more children (e.g. 7 children if you ask it for 3).
Hint.
Each child continues execution exactly where the fork() call occurs, and if in the middle of the loop it means that the loop will also continue in the child process, not just in the parent process. You need to make sure children exit out of the for loop.
Now read through section 5.2, which discusses the wait() call that can be used by a process to wait for one of its children to end. Compile and run the program in Figure 5.2, also found in the file under ostep/cpu-intro/p2.c.

Practice 2.1.16.

What is the return value of the wait call?
  • There is no return value.
  • The time that the child process has been running for.
  • The pid of the terminated child.
  • The number of running children.

Practice 2.1.17.

If a process has multiple children, when does that the wait call return?
  • Immediately.
  • When all the children have terminated.
  • When the child with the smallest pid terminates.
  • When any child terminates.

Practice 2.1.18.

This is a bit more open-ended: Change this program p2 so that it creates a specific number of children (stored in some variable N), then waits for them all to finish and records the pids in the order the children finished. After that, it prints out all the pids in that same order.

Practice 2.1.19.

When we use execvp to run another program, what happens to the original program?
  • The original program continues executing just below the execvp line.
  • The original program doesn’t run any more.
  • Read the documentation for execvp by running man execvp. What happens if the call fails to start the new program? Try to make the example p3 fail by calling a program that doesn’t exist (for example wce instead of wc).
  • The original program will only continue to run if there was an error in execvp executing the new program (for example if the file for the new program could not be found).

Practice 2.1.20.

Modify the provided program so that it instead executes the ls program just as if we had typed: ls -l ... You should see as a result a list of the different directories like cpu-api.
Hint.
You will need to extend the array used to provide arguments to the new program, as the call described above needs three different entries in the command line.
Read through sections 5.4 and 5.5 to get further understanding of how these tools are used, and in particular how the system manages multiple users and what they each can do.