---
title: "dispatching"
type: concept
related: [Stack, Preemption, Process Control Block]
source: https://www.jemoka.com/posts/kbhdispatching/
confidence: high
status: active
---

&ldquo;how does an operating system track threads and processes&rdquo;
see process control block
traps and interrups Bad problem: the operating system can&rsquo;t be running when a user thread is running. We can&rsquo;t do thread bookeeping if a user thread is running.
trap a trap is a scheme to request OS attention explicitly from the user thread, swapping the user process off the CPU.
system calls errors page fault (memory errors) interrupt a interrupt takes place outside the current thread, it forces the OS&rsquo; attention even if the user thread isn&rsquo;t asking for it
character typed at keyboard completion of a disk operations a hardware timer that fires an interrupt interrupts enable preemption to happen, so see also preemption for interrupt handling pattern.
what if a timer goes off during an interrupt interrupts are disabled during interrupt handling, otherwise, this causes an infinite loop.
solution: interrupts are disabled during timer handling.
this causes a problem: if you preempt into a brand new thread
main idea there are race condition we cannot solve with mutexes because we are the OS so, we implement mutexes by enabling/disabling interrupts dispatcher a dispatcher performs a context switch, which
context switch (in asm) push all registers except %rsp into the bottom of the old thread&rsquo;s stack store the stack pointer %rsp into the process control block for that process corresponding to thread read the new thread&rsquo;s stack pointer from the process control block, and load that into %rsp (in asm) pop all registers stored on the bottom of our new stack back onto the registers remember to push and pop the registers in the same order&hellip;. otherwise the registers won&rsquo;t be in the right order.
this makes a context switch a function that calls on one thread and returns on another thread&mdash;&ldquo;we start executing from one stack, and end executing from another&rdquo;.
Example:
context switch
Notice that we only store callee saved registers because its the responsibility of whomever called context switch to save the register of the caller saved registers.
pushq %rbp pushq %rbx pushq %r14 pushq %r15 ;; pushq all of em callee saved ... movq %rsp, [somewhere in PCB, thread 1] ; the process control block movq [somewhere else in PCB, thread 2], %rsp ; the stack is now somewhere else ;; now we pop backwards up from the stack ;; popq all of em calee saved ... popq %r15 popq %r14 popq %rbx popq %rbp ;; this will RETURN to the last call *or* top of context_switch() of the ;; **THREAD 2**, because we moved the stack pointer by movq into ;; %rsp, we will return to the NEW thread&#39;s last executed position ret what if the thread is new? We can&rsquo;t ret to a function that never called context_switch, which is the case for new threads.
To do this, we create a fake freeze frame on the stack for that new thread which looks like you are just about to call the thread function, and calls context_switch normally.
yield yield is a user function that one could implement, which acts like a blocking action, but instead of doing that we just add ourselves directly to the end of the ready queue again. (i.e. give up CPU voluntarily, but don&rsquo;t block0.
