The Process
Informally, a process is a program in execution or simply an instance of a
computer program that is being executed. It is more than the program code,
which is sometimes called text section. While a program itself is just a
passive collection of instructions, a process is the actual execution of those
instructions. It includes the current activity, as represented by the value of the
program counter and the contents of the processor‘s registers. In addition, a
process generally includes the process stack, which contains temporary data
(such as method parameters, return addresses, and local variables), and a data
section, which contains global variables.
You should note the emphasis that a program by itself is not a process; a
program is a passive entity such as the content of the file stored on disk,
whereas a process is an active entity, with a program counter specifying the
next instruction to execute and a set of associated resources.
Several processes may be associated with the same program - each would
execute independently (multithreading - where each thread represents a
process), either synchronously (sequentially) or asynchronously (in parallel).
Although, two processes may be associated with the same program, they
nevertheless considered two separate execution sequences. For instance,
several users may be running different copies of the mail program, or the same
user may invoke many copies of the editor program. Each of these is a
separate process, and although the text sections are equivalent, the data
sections vary. It is also common to have a process that spawns many processes
as it runs.
Modern computer systems allow multiple programs and processes to be
loaded into memory at the same time and, through time-sharing (or
multitasking), give an appearance that they are being executed at the same
time (concurrently) even if there is just one processor. Similarly, using a
multithreading OS and/or computer architecture, parallel processes of the
same program may actually execute simultaneously (on different CPUs) on a
multiple CPU machine or network.
In general, a computer system process consists of (or is said to 'own') the
following resources:
An image of the executable machine code associated with a program.
Memory (typically some region of virtual memory); which includes the
executable code, process-specific data (input and output), a call stack (to keep
track of active subroutines and/or other events), and a heap to hold intermediate
computation data generated during runtime.
Operating system descriptors of resources that are allocated to the process, such
as file descriptors (Unix terminology) or handles (Windows), and data sources
and sinks.
Security attributes, such as the process owner and the process' set of permissions
(allowable operations).
Processor state (context), such as the content of registers, physical memory
addressing, etc. The state is typically stored in computer registers when the
process is executing, and in memory otherwise.
3.2 Process states
As a process executes, it changes state. The state of a process is defined in part by the
current activity of that process. Each process may be in one of the following states:
New: The process is being created.
Running: Instructions are being executed.
Waiting: The process is waiting for some event to occur (such as I/O completion or
reception of a signal)
Ready: the process is waiting to be assigned to a processor.
Terminated: The processor has finished execution.
New Terminated
Admitted Exit
Interrupt
Ready Running
Scheduler dispatch
I/O or Event completion I/O or Event wait
Waiting
Figure 3.1: Process State
These state names are arbitrary, and they vary across operating systems. The states that
they represent are found on all systems, however. Certain operating systems more finely
delineate process states. Only one process can be running on any processor at any instant,
although many processes may be ready and waiting. The state diagr am corresponding to
these states is presented in Figure 3.1. The various process states, are displayed in the
figure, with arrows indicating possible transitions between states.
3.3 Process Control Block (PCB)
Each process is represented in the operating system by a process control block (PCB) –
also called a task control block. A PCB contains many pieces of information associated
with a specific process as shown in Figure 3.2 below.
Pointer Process State
Process number
Program counter
Registers
Memory limits
List of open files
.
.
.
Figure 3.2: Process Control Block (PCB)
The content of the PCB include:
• Process State: As you have learnt in the previous section, the state may be new,
ready, running, waiting, halted, etc.
• Program counter: The counter indicates the address of the next instruction to be
executed for this process.
• CPU registers: the register vary in number and type, depending on the computer
architecture. They include accumulators, index registers, stack pointers, and
general-purpose registers, plus any condition-code information. Along with the
program counter, this state information must be saved when an interrupt occurs, to
allow the process to be continued correctly afterward. (Figure 3.3)
• CPU-Scheduling information: This information includes a process priority,
pointers to scheduling queues, and any other scheduling parameters.
• Memory-management information: this information may include such
information as the value of the base and limit registers, the page tables, or the
segment tables, depending on the memory system used by the operating system.
• Accounting information: this information includes the amount of CPU and real
time used, time limits, account numbers, job or process numbers, etc.
I/O status information: the information includes the list of I/O devices
allocated to this process, a list of open files, etc.
The PCB simply serves as the repository for any information that may
vary from process to process.
process P0 operating system process P1
interrupt or system call
Executing
save state into PCB0
. Idle
.
.
reload state from PCB1
Executing
Idle interrupt or system call
save state into PCB1
.
. Idle
.
reload state from PCB0
Executing
Figure 3.3: Diagram showing CPU switch from process to process
3.4 Process Scheduling
The objective of multiprogramming is to have some process running at all
times so as to maximize CPU utilization. The objective of time-sharing is to
switch the CPU among processes so frequently that users can interact with
each program while it is running. A uniprocessor system can have only one
running process. If more processes exist, the rest must wait until the CPU is
free and can be rescheduled.
3.4.1 Scheduling Queues
As processes enter the system, they are put into a job queue. This queue
consists of all processes in the system. The processes that are residing in main
memory and are ready and waiting to execute are kept on a list called the
ready queue. This queue is generally stored as a linked list. A ready-queue
header contains pointers to the first and final PCB in the list. We extend each
PCB to include a pointer field that points to the next PCB in the ready queue.
The operating system also has other queues. When a process is allocated the
CPU, it executes for a while and eventually quits, is interrupted, or waits for
the occurrence of a particular event, such as the completion of an I/O request.
In the case of I/O request, such a request may be to a dedicated tape drive, or
to a shared device, such as a disk. Since the system has many processes, the
disk may be busy with the I/O request of some other process. The process
therefore may have to wait for the disk. The list of processes waiting for a
particular I/O device is called a device queue. Each device has its own queue.
A common way of representating process scheduling is by using a queueing
diagram, such as that in Figure 3.4. Each rectangular box represents a queue.
Two types of queues are present: the ready queue and a set of device queues.
The circles represent the resources that serve the queues, and the arrows
indicate the flow of processes in the system.
A new process is initially put in the ready queue. It waits in the ready queue
until it is selected for execution (or dispatched). Once the process is assigned
to the CPU and is executing, one of several events could occur:
The process could issue an I/O request, and then be placed in an I/O queue.
The process could create a new sub process and wait for its termination.
The process could be removed forcibly from the CPU, as result of an interrupt, and
be put back in the ready queue.
In the first two cases, the process eventually switches from the waiting state to the
ready state, and is then put back in the ready queue. A process continues this cycle
until it terminates, at which time it is removed from all queues and has its PCB and
resources deallocated.
3.4.2 Schedulers
A process migrates between the various scheduling queues throughout its lifetime. The
operating system must select, for scheduling purposes, processes for these queues in
some fashion. The selection process is carried out by the appropriate scheduler.
In a batch system, often more processes are submitted than can be executed immediately.
These processes are spooled to a mass-storage device, where they a re kept for later
execution. The long-term scheduler, or job scheduler, selects processes from this pool
and loads them into memory for execution. The short-term scheduler, or CPU scheduler,
selects from among the processes that are ready to execute, and allocates the CPU to one
of them.
ready queue
CPU
I/O queue I/O request
I/O
time slice expired
child executes fork a child
wait for an
interrupt occurs interrupt
Figure 3.4: Queuing-diagram representation of process scheduling
The primary distinction between these two schedulers is the frequency of their execution.
The short-term scheduler must select a new process for the CPU frequently. A process may
execute for only a few milliseconds before waiting for an I/O request. Often, the short-term
scheduler executes at least once every 100 milliseconds. Due to the brief time between
executions, the short-term scheduler must be fast.
The long-term scheduler, on the other hand, executes much less frequently. There may be
minutes between the creation of new processes in the system. The long-term scheduler
controls the degree of multiprogramming - the number of processes in memory. If the
degree of multiprogramming is stable, then the average rate of process creation must be
equal to the average rate of processes leaving the system.. therefore, the long-term
scheduler may need to be invoked only when process leaves the system.
3.4.3 Context Switch
Switching the CPU to another process requires saving the state of the old process and
loading the saved state for the new process. This task is known as context switch. The
context of a process is represented in the PCB of a process; it includes the value of the CPU
registers, the process state (Figure 3.1), and memory-management information. When a
context switch occurs, the kernel saves the context of the old process in its PCB and loads
the saved context of the new process scheduled to run. Context-switch time is pure
overhead, because the system does no useful work while switching. Its speed varies from
machine to machine, depending on the memory speed, the number of registers that must
be copied, and the existence of special instructions. Typical speeds range from 1 to
1000 micro seconds. Also, context-switch times are highly dependent on
h/which support.
3.5 Operations on Processes
The processes in the system can execute concurrently, and they must be
created and deleted dynamically. Therefore, the operating system must
provide a mechanism (or facility) for process creation and termination.
3.5.1 Process Creation
A process may create several new processes, via a create-process system
call, during the course of execution. The creating process is called a parent
process, whereas the new processes are called the children of that process.
Each of these new processes may in turn create other processes, forming a
tree of processes (Figure 3.5).
In general, a process will need certain resources (such as CPU time, memory,
files, I/O devices) to accomplish its task. When a process creates a
subprocess, that subprocess may be able to obtain its resources directly from
the operating system, or it may be constrained to a subset of the resources of
the parent process. The parent may have to partition its resources among its
children, or it may be able to some resources (such as memory or files) among
several of its children. Restricting a child process to a subset of the parent‘s
resources prevents any process from overloading the system by creating too
many subprocesses.
When a process is created it obtains initialization data (or input) that may be
passed along from the parent process to the child process in addition to the
various physical and logical resources. For instance, consider a process whose
function is to display the status of a file, say F1, on the screen of a terminal.
When it is created, it will get, as an input from its parent process, the name of
the file F1, and it will execute using that datum to obtain the desired
information. It may also get the name of the output device. Some operating
systems pass resources to child processes. On such a system, the new process
may get two open files, F1 and the terminal device, and may just need to
transfer the datum between the two.
When a process creates a new process, two possibilities exist in terms of
execution:
1. The parent continues to execute concurrently with its children.
2. The parent waits until some or all of its children have terminated
There are also two possibilities in terms of the address space of the new
process:
1. The child process is a duplicate of the parent process.
2. The child process has a program loaded into it.
In UNIX, every process except process 0 (the swapper) is created when another process
executes the fork system call. The process that invoked fork is the parent process and the
newly-created process is the child process. Every process (except process 0)
has one parent process, but can have many child processes.
In UNIX, a child process is in fact created (using fork) as a copy of the parent.
The child process can then overlay itself with a different program (using
exec) as required.
Each process may create many child processes but will have only one parent
process, except for the very first process which has no parent. The first
process, called init in UNIX, is started by the kernel at booting time and never
terminates.
The kernel identifies each process by its process identifier (PID). Process 0 is
a special process that is created when the system boots; after forking a child
process (process 1), process 0 becomes the swapper process. Process 1,
known as init, is the ancestor of every other process in the system.
When a child process terminates execution, either by calling the exit system
call, causing a fatal execution error, or receiving a terminating signal, an exit
status is returned to the operating system. The parent process is informed of
its child's termination through a SIGCHLD signal. A parent will typically
retrieve its child's exit status by calling the wait system call. However, if a
parent does not do so, the child process becomes a zombie process.
On Unix and Unix-like operating systems, a zombie process or defunct process is a
process that has completed execution but still has an entry in the process table, this entry
being still needed to allow the process that started the zombie process to read its exit status.
3.5.2 Process Termination
A process terminates when it finishes executing its final statement and asks the operating
system to delete it by using exit system call. At that point, the process may return data
(output) to its parent process (via the wait system call). All the resources of the process –
including physical and virtual memory, open files, and I/O buffers – are deallocated by the
operating system.
Termination occurs under additional circumstances. A process can cause the termination of
another process via an appropriate system call e.g. abort. Usually, only the parent of the
process that is to be terminated can invoke such a system call. Otherwise, users could
arbitrarily kill each other‘s jobs. A parent, therefore, need to know the identities of its
children. Thus, when one process creates a new process, the identity of the
newly created process is passed to the parent.
A parent may terminate the execution of one of its children for a variety of
reasons, such as these:
The child has exceeded its usage of some of the resources that it has been allocated. This
requires the parent to have a mechanism to inspect the state of its children.
The task assigned to the child is no longer required.
The parent is exiting, and the operating system does allow a child to continue if its parent
terminate. On such systems, if a process terminates (either normally or abnormally), then all
its children must also be terminated. This phenomenon, referred to as cascading termination,
is normally initiated by the operating system.
To illustrate process execution and termination, consider that in UNIX, we
can terminate a process by using the exit system call; its parent process may
wait for the termination of a child process by using wait system call. The wait
system call returns the process identifier of a terminated child, so that the
parent can tell which of its possibly many children has terminated. If the
parent terminates, however, all its children have assigned as their new parent
the init process. Thus, the children still have a parent to collect their status.