Program Context and Switching
CS 321 Lecture,
Dr. Lawlor, 2006/01/30
So periodically the CPU is interrupted. The OS takes
control. Let's say the program that was using the CPU has been
running for a long time, and the OS would like to run some other
program for a while.
We can't just kill the old program--then we'd have to start it up again
from scratch. We just want to gently suspend it, keeping its
information around so we can eventually restore the program, starting
it up again where it left off.
So what kind of stuff do we need to save and restore? In other words, what is a "program"? A "program" can be thought of as including, in order of importance:
Step (1) is just a little bit of assembly code to save and restore
registers. Since you've got to do this inside almost every
subroutine, it should be old hat by now. Check out
my little "minithread" example code for an example
(Directory, Zip, Tar-gzip).
The key routine is just the "mth_swap" subroutine, which saves an old
set of registers and loads up a new one, and the core of this is just:
- The values in the processor registers. If we suspended a
program, and then restored it with a totally different value in eax,
the program wouldn't do the same thing as if we'd just left it
alone. So if we want to swap during an interrupt, we've got to
save and restore all
the processor registers. If we switch programs during a
subroutine call, we've got a lot less to save and restore, since we
don't need to bother saving and restoring scratch registers.
- The values on the stack. The stack stores local variables
and the stuff we're working on right now, so it's important that it get
saved when we switch programs. If we just put the different
program's stacks at different places in memory, then we just need to
save and restore the stack pointer when we switch programs.
- The values everywhere in program memory. All of memory can
actually be switched quite easily efficiently with the virtual memory
hardware, but we won't talk about how that works for a few more
weeks. For now, you can imagine just choosing different places in
memory for each program's values.
- All connections to the outside world, including open files and
network connections. We'll talk about how to save and restore
these things when we talk about I/O. For now, we'll just ignore
open files and network connections.
mov [eax],esp ; Save the old stack pointer
mov esp, [ecx] ; Load up the new stack pointer
Kinds of Program Context
There are quite a few different levels of saving and restoring that you
can design. Existing levels are nesting, and from least-to-most
All these levels actually nest. So a virtual machine might
contain several processes, with the OS switching between them.
Each process might contain several kernel threads, with the OS again
switching between them. Each kernel thread might contain several
user-level threads, which user code explicitly switches between.
- User-level threads,
where you save and restore processor registers yourself, usually via an
explicit "swap" subroutine call. Also called "coroutines" or
"user/userspace threads", or (by Sun Java folks) "green threads".
Typical examples include "minithread" (above), Netscape Threads, or any of a thousand tiny projects mostly relying on setjmp/longjmp or "makecontext/swapcontext".
Each thread has its own stack, usually just allocated with "malloc",
but shares the rest of memory with other user-level threads.
- Kernel-level threads,
or just "threads", are where the OS saves and restores processor
registers to switch threads at interrupt time. Also called
"native threads". The most common example is pthreads.
There's actually a hybrid of kernel and user-level threads where you
save and restore processor registers yourself (not in the OS), but you
do it inside a signal handler during an interrupt.
- Processes, where
the OS swaps out all of memory and all I/O connections in addition to
the registers. This is what you usually think of as a "program".
- Virtual Machines, where the
OS itself and everything in it is swapped out. QEMU is a pretty typical
example. A virtual machine is usually treated as an ordinary
process inside the outer ("host") OS.