Download presentation
Presentation is loading. Please wait.
1
Low-Level Thread Dispatching on the x86
Dispatching and Exception Handling RECAP: Exception Handling in the x86 How to use Exception Handling mechanisms for Dispatching RECAP: The Thread Control Block (TCB) in class Thread Dispatching in 4 Steps: Start, Store, Locate, Load Creating a Thread The Execution Lifecycle of a Thread
2
Low-Level Thread Dispatching
Low-level Dispatch Thread::dispatch_to(Thread * _thread); Store state of current thread execution and load state of target thread onto CPU. Dispatching in 3 steps: Save state of current thread Load state of new thread Continue execution of new thread
3
Low-Level Thread Dispatching
Dispatching in 3 steps: Save state of current thread Load state of new thread Continue execution of new thread Problems: How do we save the state of the current thread? How do we load the state of the new thread? How do we continue execution of new thread?!
4
Low-Level Thread Dispatching
Problems: How do we save the state of the current thread? How do we load the state of the new state? How do we continue execution of new thread?! Q: Where else do we have the same problem? A: When we handle exceptions. Solution: Handle Thread Dispatching (somewhat) in the same manner!
5
RECAP: Exception Handling
; 0: Divide By Zero Exception _isr0: push byte 0 ; push dummy push byte 0 ; push interrupt no jmp isr_common_stub extern _dispatch_exception ; The common ISR stub. isr_common_stub: pusha push ds push es push fs push gs mov eax, esp push eax mov eax, _dispatch_exc call eax pop eax pop gs pop fs pop es pop ds popa add esp, 8 ; pop code and int no iret global _isr0 global _isr1 global _isr2 ... global _isr8 … global _isr30 global _isr31 ; 8: Double Fault Exception (Error Code!) _isr8: ; don’t push dummy! push byte 8 ; push interrupt no jmp isr_common_stub /* This defines what the stack looks like when the exception/interrupt reaches the exception dispatcher. */ typedef struct regs { unsigned int gs, fs, es, ds, /* pushed in common stub */ unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax; /* pushed by pusha */ unsigned int int_no, err_code; /* pushed in _isrXX */ unsigned int eip, cs, eflags; /* pushed by processor */ } REGS;
6
RECAP: Saving and Loading State
; 0: Divide By Zero Exception _isr0: push byte 0 ; push dummy push byte 0 ; push interrupt no jmp isr_common_stub extern _dispatch_exception ; The common ISR stub. isr_common_stub: pusha push ds push es push fs push gs mov eax, esp push eax mov eax, _dispatch_exc call eax ; call exc dispatcher pop eax pop gs pop fs pop es pop ds popa add esp, 8 ; pop code and int no iret global _isr0 global _isr1 global _isr2 ... global _isr8 … global _isr30 global _isr31 Here we save the state Here we load the state
7
Saving and Restoring the State
thread exception dispatcher exception handler exception function call thread “suspended”, waiting for exception handler to return iret return from function call return from interrupt
8
Saving and Restoring the State
thread iret
9
Saving and Restoring the State
thread Load another thread’s state! iret return from function call
10
Dispatching, Example Thread A Thread B Thread B “suspended”
call function Thread::dispatch_to(B) Thread B “suspended” iret returns from previous call to Thread::dispatch_to(...) Thread A “suspended” call function Thread::dispatch_to(A) returns from previous call to Thread::dispatch_to(B) iret
11
RECAP: Structure of a Thread
class Thread { private: char * stack_ptr; /* The current stack pointer for the thread. Keep it at offset 0, since the thread dispatcher relies on this location! */ int thread_id; /* thread identifier. Assigned upon creation. */ char * stack; /* pointer to the stack of the thread.*/ unsigned int stack_size; /* size of the stack (in byte) */ int priority; /* Maybe the scheduler wants to use priorities. */ etc... Thread Control Block TCB: thread id stack stackptr priority bookkeeping etc… stack top of stack
12
Dispatching Step-by-Step: 0. Start
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } return_addr _thread
13
Dispatching Step-by-Step: 1. Fix Stack
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack push eax ; save eax mov eax, [esp+4] ; get return address mov [esp-4], eax ; move return addr ; down 8 bytes from orig loc add esp, ; move stack ptr up pushfd ; put eflags where return address was mov eax, [esp-4] ; restore saved value of eax push dword KERNEL_CS ; push cs selector sub esp, ; point stack ptr ; at return address ; STEP 2: ... ... return_addr KERNEL_CS return_addr eflags _thread _thread
14
Dispatching Step-by-Step: 2. Save State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 int_no err_no return_addr KERNEL_CS eflags _thread
15
Dispatching Step-by-Step: 2. Save State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 ; Save general purpose registers. pushad edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread
16
Dispatching Step-by-Step: 2. Save State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 ; Save general purpose registers. pushad push ds push es push fs push gs ds edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread
17
Dispatching Step-by-Step: 2. Save State
class Thread { private: char * stack_ptr; /* The current stack pointer for the thread. Keep it at offset 0, since the thread dispatcher relies on this location! */ int thread_id; /* thread identifier. Assigned upon creation. */ char * stack; /* pointer to the stack of the thread.*/ unsigned int stack_size; /* size of the stack (in byte) */ int priority; /* Maybe the scheduler wants to use priorities. */ etc... gs void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; Push fake error code and interrupt number push dword 0 ; Save general purpose registers. pushad push ds push es push fs push gs ; Save stack pointer in the thread control block ; (at offset 0). mov eax, [_current_thread] mov [eax+0], esp ds edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread
18
Dispatching Step-by-Step: 3. Locate State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread mov eax, dword [esp+INTERRUPT_STATE_SIZE] ds edi esi ebp esp INTERRUPT_STATE_SIZE (68 Bytes) ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _thread
19
Dispatching Step-by-Step: 3. Locate State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } fs fs es es _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread mov eax, dword [esp+INTERRUPT_STATE_SIZE] ; Make the new thread current, and switch to its stack. mov [_current_thread], eax mov esp, [eax+0] ds ds edi edi esi esi ebp ebp esp esp ebx ebx edx edx ecx ecx eax eax class Thread { private: char * stack_ptr; /* The current stack pointer for the thread. Keep it at offset 0, since the thread dispatcher relies on this location! */ etc... new thread int_no int_no err_no err_no return_addr return_addr KERNEL_CS KERNEL_CS eflags eflags _somethread _thread
20
Dispatching Step-by-Step: 4. Load State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds edi esi ebp esp ebx edx ecx eax int_no err_no return_addr KERNEL_CS eflags _somethread
21
Dispatching Step-by-Step: 4. Load State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds popad int_no err_no return_addr KERNEL_CS eflags _somethread
22
Dispatching Step-by-Step: 4. Load State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds popad add esp, 8 ; skip int num and error code return_addr KERNEL_CS eflags _somethread
23
Dispatching Step-by-Step: 4. Load State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _threads_low_switch_to: ; STEP 1: fix stack ... ; STEP 2: save state ; STEP 3: locate state of new thread ; STEP 4: load state of new thread pop gs pop fs pop es pop ds popad add esp, 8 ; skip int num and error code ; We'll return to the place where the thread was ; executing last. iret void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } return_addr KERNEL_CS eflags _somethread
24
Dispatching Step-by-Step: 4. Load State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } return_addr KERNEL_CS eflags _somethread
25
Dispatching Step-by-Step: 4. Load State
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } _somethread
26
Dispatching Step-by-Step: 4. Load State
_somethread
27
Dispatching Step-by-Step: 4. Load State
28
Creating a Thread push tshutdown ret_addr
void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); } inline void Thread::push(unsigned long _val) { stack_ptr -= 4; *((unsigned long *) stack_ptr) = _val; } push tshutdown ret_addr
29
Creating a Thread push _tfunction ret_addr push tshutdown ret_addr
void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); } push _tfunction ret_addr push tshutdown ret_addr
30
Creating a Thread push thread_start eip push KERNEL_CS es push 0
void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); } push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr
31
Creating a Thread push 0 int_no push 0 err_code push thread_start eip
void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); /* Fake error code and interrupt number. */ push(0); push(0); } push 0 int_no push 0 err_code push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr
32
Creating a Thread push 0 edi push 0 esi push 0 ebp push 0 esp push 0
void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); /* Fake error code and interrupt number. */ push(0); push(0); /* Initial values for general-purpose registers. */ push(0); ...; push(0); /* eax ... edi */ } push 0 edi push 0 esi push 0 ebp push 0 esp push 0 ebx push 0 edx push 0 ecx push 0 eax push 0 int_no push 0 err_code push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr
33
Creating a Thread push 0 gs push 0 fs push KERNEL_CS es push KERNEL_CS
void Thread::setup_context(Thread_Function _tfunction){ /* Address of thread shutdown function */ push((unsigned long) &tshutdown); /* Push the address of the thread function. */ push((unsigned long) _tfunction); /* EFLAGS and instruction pointer */ push(0); push(Machine::KERNEL_CS); push((unsigned long) &thread_start); /* Fake error code and interrupt number. */ push(0); push(0); /* Initial values for general-purpose registers. */ push(0); ...; push(0); /* eax ... edi */ /* Segment registers */ push(Machine::KERNEL_DS); /* ds */ push(Machine::KERNEL_DS); /* es */ push(0); push(0); /* fs; gs */ } push 0 gs push 0 fs push KERNEL_CS es push KERNEL_CS ds push 0 edi push 0 esi push 0 ebp push 0 esp push 0 ebx push 0 edx push 0 ecx push 0 eax push 0 int_no push 0 err_code push thread_start eip push KERNEL_CS es push 0 eflags push _tfunction ret_addr push tshutdown ret_addr
34
Execution Lifecycle of a Thread
gs fs es ds edi esi ebp esp ebx edx ecx eax int_no err_code push 0 push KERNEL_CS void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } push thread_start eip push KERNEL_CS es push 0 eflags push t_fun_1 ret_addr push tshutdown ret_addr
35
Execution Lifecycle of a Thread
void Thread::dispatch_to(Thread * _thread) { threads_low_switch_to(_thread); } push thread_start eip push KERNEL_CS es push 0 eflags push t_fun_1 ret_addr push tshutdown ret_addr
36
Execution Lifecycle of a Thread
static void thread_start() { /* This function is used to release the thread for execution in the ready queue. */ /* We need to add code, but it is probably nothing more than enabling interrupts. */ } push t_fun_1 ret_addr push tshutdown ret_addr
37
Execution Lifecycle of a Thread
void t_fun_1() { /* do_something_in_this_thread */ } push tshutdown ret_addr
38
Execution Lifecycle of a Thread
static void tshutdown() { /* terminates thread after thread func returns*/ }
39
Execution Lifecycle of a Thread
40
Low-Level Dispatching on the x86 : Summary
We learned: Dispatching can be implemented similarly to exception handlers. (Side Note: This approach is very general and portable.) Implementation of the Thread Control Block in C++ class Thread Dispatching in 4 Steps: Start, Store, Locate, Load Thread Creation The Execution Lifecycle of a Thread
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.