I have a question about context switches on timer interrupts (x86_64), which makes me confused.
In the theory I thought as follows:
- On timer interrupt, the os switches the registers (rbx,r12,..,r15,rbp,rsp) from the current thread to the next thread (save & restore)
- after that, the interrupt handler calls iret to return from the routine
- the thread, switched by the os while interrupt handling, will run
Code: Select all
struct ContextStack
{
void *rbx;
void *r12;
void *r13;
void *r14;
void *r15;
void *rbp;
void *rsp;
char fpu[108];
};
class Context
{
public:
ContextStack *stack;
// some more attributes, that doesn't matter
}
Code: Select all
save_and_restore:
mov [rdi+0x0], rbx
mov [rdi+0x8], r12
mov [rdi+0x10], r13
mov [rdi+0x18], r14
mov [rdi+0x20], r15
mov [rdi+0x28], rbp
mov [rdi+0x30], rsp
mov rbx, [rsi+0x0]
mov r12, [rsi+0x8]
mov r13, [rsi+0x10]
mov r14, [rsi+0x18]
mov r15, [rsi+0x20]
mov rbp, [rsi+0x28]
mov rsp, [rsi+0x30]
mov rdi, rdx
ret
Code: Select all
void save_and_restore (struct ContextStack *current_stack, ContextStack *next_stack, void *current_context);
What me confuses: I'm logging some text, after calling the save_and_restore routine within the timer interrupt handler, but that is not executed. It seems like the context is switched but the handler never finishes. Also after the first context switch, I'll never receive any timer interrupts again. Shouldn't the log be executed and the switch done after calling iret?
Here is what my handler looks like:
Code: Select all
void on_timer_interrupt()
{
log("starting timer interrupt handler"); // I see this
// do some work...
Context *current_context = // get the current
Context *next_context = // dequeue the next context to run
enqueue_to_ready_list(current_context);
save_and_restore(current_context->stack, next_context->stack, current_context);
enable_inerrupts();
log("timer interrupt done"); // this is never logged
// call iret
}