Information Technology Reference
In-Depth Information
Then, we push an instruction pointer. Notice that—perhaps surprisingly—the
instruction pointer we push is not the address of the current instruction. In-
stead, we save the address of the instruction at LABEL, near the end of the
threadyield() procedure. We need to do this to avoid an endless loop. In
particular, if we instead stored a pointer to the current instruction, then later,
when this thread is restored, it would continue where it left off (e.g., it would
finish saving its state to the stack, copy its saved state to its TCB, and run
another thread.)
Finally, we save the remaining registers to the stack using the x86 pushad
instruction.
Once the calling thread saves its state to its stack, it copies its saved state to
its TCB, chooses another thread to run, and runs it by restoring its state in
three steps: (1) change the stack pointer to point to the other thread's saved
registers; (2) pop the other thread's general purpose registers; and (3) pop the
other thread's instruction pointer and execution flags. After step (3), the current
thread is no longer executing, and the assert(0) in the pseudo-code is never
reached.
When the original thread is eventually restored, its stack, stack pointer, and all
registers except the instruction pointer are the same as they were when the
pushad call saved the registers. The instruction pointer is now LABEL , and the
first thing the thread does upon being resumed is to execute the return . In
essence, threadyield() appears to the caller as an empty procedure that
does nothing but immediately return.
Of course, behind the scenes a lot is
happening.
Processor's point of view. From the processor's point of view, one instruc-
tion follows the next, but now the instructions from different threads are inter-
leaved (as they must be if we are to support multiplexing!)
This interleaving can seem a bit unusual| threadyield() deliberately vio-
lates the procedure call conventions compilers normally follow by manipulating
the stack and program counter to switch between threads. For example, Fig-
ure 4.13 shows the interleaving when two threads each execute a simple endless
loop:
while(1){
thread_yield();
}
One way to view Figure 4.13 is that from the processor's point of view|because
of the way a context switch manipulates the registers| threadyield() is called
by one thread but returns in a different thread.
But, once the operating system has the needed mechanisms to switch be-
tween threads, the threads, themselves, get to ignore this complexity. From
their point of view, they each just run this loop on their own (variable-speed)
virtual processor.
 
Search WWH ::




Custom Search