Programs are static executable code that resides in storage. It’s a passive entity. Processes are program code in execution. It’s an active entity and requires much more resources than the static program, in the form of CPU time, memory and access to I/O devices and the file system. Each process is represented in the OS by a Process Control Block (PCB), which resides in the kernel space of memory. The PCB serves as the repository for any information that may change from process to process, such as process state, program counter, register values, memory limits and a list of open files. Each process is also given a unique number, called a Process ID (pid) by the OS.
The process memory block contains the stack, the heap, and the text and data sections:
- The text section contains all the executable code, and current activity (program counter and register values).
- The data section contains all the global variables.
- The stack contains all the temporary data, such as function parameters, return addresses and local variables.
- The heap is dynamically allocated memory.
There are also the base and limit registers, which limit the memory addresses that a certain process can access. For example, if the base register is 1000, and the limit is 100, then that process can legally access all memory addresses from 1000 to 1099.
When a user selects a program to be run, the OS allocates a PCB to it. Once the PCB has been created, and the process is ready to be executed, the PCB is moved into the ‘ready queue’ (This is not the case in all OSes, look below). The process is then said to be in the ‘ready’ state.
Operating System Queues
Job Queue: Similar to the concept of a ‘job pool’ in Multiprogrammed system. Since memory is limited, not all processes can be loaded into memory (and the ‘ready queue’) at the same time. Therefore some are stored in disk, on a job queue, from which a ‘long-term scheduler’ (or ‘job scheduler’) picks processes to load into the ready queue. Systems like UNIX and Windows eliminate the job queue and load all processes directly into the ready queue.
Ready Queue: This is (typically) a linked list of PCBs, of processes that are ready and in need of getting CPU time. A ‘short-term scheduler’ (or ‘CPU scheduler’) selects from the queue and allocates CPU time to them (the process is ‘dispatched’). The process is now in the ‘running’ state. CPU time slices are limited to 100 milliseconds (at most), so that a single process does not get to hold the CPU for too long. But usually, processes do not run for that long, since one of these things will occur:
- Process issues an I/O request and is sent to an I/O device queue.
- Process creates a child process and waits for it to terminate.
- A CPU interrupt occurs, and the process is put back into the ready queue.
Device Queues: Each I/O device has a device queue. Processes that are waiting for I/O access (which are now in the ‘waiting’ state) are kept on these queues.
The Job Scheduler (or long-term scheduler) runs from time to time, and loads processes from the job pool into the ready queue. It maintains the ‘degree of Multiprogramming’ (number of processes in memory), as well as a good ‘process mix’. This is the ratio of CPU-bound processes (ones which do most of their time using the CPU) to I/O-bound processes (ones which spend most of the time using I/O devices). If this mix is bad, either the CPU or I/O devices will be underutilized, and the system will not perform optimally.
Some Operating Systems, such as UNIX and Windows, do not employ a long-term scheduler, and instead loads all runnable processes into the ready queue. They might employ a ‘medium-term scheduler’ to swap processes in and out of memory to either free up space or improve the process mix.
The CPU Scheduler (or short-term scheduler) runs every 100 milliseconds or so, and allots the CPU to one of the processes in the ready queue. It needs to be very fast, since time spent selecting and switching to a new process is CPU time being wasted.
More about Process Management in our next post…