Multiprogramming
CSE451
Andrew Whitaker
Overview
Multiprogramming: Running multiple programs
“at the same time”
Requires multiplexing (sharing) the CPU
Firefox Word javac Firefox Word
time
Transfer of control is called a context switch
The Process
The process is an OS
kernel space
abstraction for a running
program stack
(dynamic allocated mem)
SP
Process is associated
with an address space
heap
(dynamic allocated mem)
Preview: Thread is a static data
running program without (data segment)
its own address space code PC
(text segment)
How Do Processes Share the CPU?
The OS maintains a per-process Process
Control Block (PCB)
Which stores state for non-running processes
On a context switch
Save state of the old process
Restore state of the new process
Old PCB
CPU
New PCB
What’s in the PCB?
The PCB is a data structure with many fields:
process ID (PID)
execution state (Ready, Running, Blocked)
program counter, stack pointer, registers
memory management info
UNIX username of owner
scheduling priority
accounting info
In linux:
defined in task_struct (include/linux/sched.h)
over 95 fields!!!
States of a process
running
dispatch interrupt
(unschedule)
ready blocking I/O
interrupt
(I/O complete)
blocked
State queues
The OS maintains a set of queues that
represent the state of processes in the
system
e.g., ready queue: all runnable processes
e.g., wait queue: processes blocked on some
condition
As a process changes state, its PCB is
unlinked from one queue, and linked onto
another
State queues
Ready queue header
head ptr netscape pcb emacs pcb ls pcb
tail ptr
Wait queue header
head ptr cat pcb netscape pcb
tail ptr
There may be many wait queues, one for each
type of wait (particular device, timer, message,
…)
Walking Through a Context Switch
Process A enters the kernel
Due to a system call, interrupt, or exception
The kernel scheduler is invoked:
Is it time to context switch?
If so, which is the next process to run?
Assembly routine exchanges hardware state
Save process A’s state to its PCB
Load process B’s state from its PCB
(Process B now running)
OS returns control to user mode
The Guts of Context Switching (x86)
1. define switch_to(prev,next,last) do {
2. unsigned long esi,edi;
3. asm volatile("pushl %%ebp\n\t"
4. "movl %%esp,%0\n\t /* save stackptr */
5. "movl %5,%%esp\n\t /* restore stackptr */
6. "movl $1f,%1\n\t" /* save instr_ptr */
7. "pushl %6\n\t" /* restore instr_ptr */
8. "jmp __switch_to\n” /* Return to C */
9. "1:\t" /* 1: is $1f*/
10. "popl %%ebp\n\t"
11. :"=m" (prev->thread.esp), /* %0 */
12. "=m" (prev->thread.eip), /* %1 */
13. "=a" (last), /* %2 */
14. "=S" (esi),"=D" (edi)
15. :"m" (next->thread.esp), /* %5 */
16. "m" (next->thread.eip), /* %6 */
17. "2" (prev), "d" (next));
18. } while (0)
UNIX Process API
How do user programs interact with
processes?
Fork: create a new process
Exec: run a program
Kill: destroy a process
Wait: wait for a process to exit
UNIX process creation
Via the fork() system call
Fork essentially clones the parent process
Child receives identical (but separate) address space
Child inherits open files from its parent
The fork() system call “returns twice”
Returns the child’s PID to the parent
Returns 0 to the child
Fork example
int value = 5;
int main () {
pid_t pid ; What value is printed to
the screen?
value = 7;
pid = fork();
if (pid == 0) { /* Child */
value += 15;
}
else { /* Parent */
wait (NULL); /* Wait for child to terminate */
printf("PARENT: value = %d\n",value );
}
}
Exec vs. fork
So how do we start a new program, instead of
just forking the old program?
the exec() system call!
int exec(char *prog, char ** argv)
exec()
stops the current process
loads program ‘prog’ into the address space
initializes hardware context, args for new program
places PCB onto ready queue
note: does not create a new process!
UNIX shells
int main(int argc, char **argv)
{
while (1) {
char *cmd = get_next_command();
int child_pid = fork();
if (child_pid == 0) {
exec(cmd);
panic(“exec failed!”);
} else {
waitpid(child_pid);
}
}
}