µ-kernel Construction (6) Dispatching 1
Dispatching Topics Thread switch To a specific thread To next thread to be scheduled To nil Implicitly, when IPC blocks Priorities Preemption Time slices Wakeups, interruptions Timeouts and wakeups Time 2
Thread A Switch to () Dispatcher Thread Smaller stack per thread Dispatcher is preemptible Clean model Improved interrupt latency if dispatching is time consuming switch to (dispatcher) select next ready thread, assume B switch to (B) Thread B 3
Thread A Switch to () save live registers and IP on stack ; tcb[a].sp := SP ; SP := dispatcher stack bottom ; return to dispatcher. switch to (dispatcher) switch to (B) Dispatcher Thread select next ready thread, assume B Dispatcher thread is special No user mode No own AS, hence no AS switch required No ID required Freedom from TCB layout conventions Almost stateless (see priorities) No need to preserve internal state between invocations External state must be consistent costs (A B) costs (A disp B) costs (select next) costs (A disp A) are low Thread B Why?? if B A then switch from AS(A) to AS(B) fi ; SP := tcb[b].sp ; return to B. 4
Example: Simple Dispatch sp Enter the kernel, save some user state in HW Save remaining user state Optionally do some work Save live registers (required when resuming) and return address Store SP in TCB Switch to dispatcher stack Jump to dispatcher code Select next thread to run TCB(A) sp live regs local state eax ebp x cs flg esp ss Dispatcher stack local state 5
Example: Simple Dispatch (cont d) sp Dispatcher selected next thread to run (B) Switch to B s stack Return to B Pop return address from stack Restore live registers Return to B s user mode Pop return address Switch to B s address space (if current) Load user register contents Drop exception code X iret pops remaining data TCB(B) sp live regs local state eax ebp x cs flg esp ss TCB(A) sp live regs local state eax ebp x cs flg esp ss Dispatcher stack local state 6
Example: Simple Dispatch (cont d) Stack layout depends on cause of prior thread switch Timer vs. device IRQ, IPC send vs. recv, yield(), TCB(E) sp live regs local state x cs flg esp ss TCB(D) sp eax ebp x cs flg esp ss TCB(C) sp live regs local state eax ebp x cs flg esp ss TCB(B) sp live regs local state eax ebp x cs flg esp ss TCB(A) sp live regs local state eax ebp x cs flg esp ss Dispatcher stack local state 7
Example: Dispatch with `Tick Dispatcher interrupted by timer IRQ sp Detect and resume Data structures (ready queues) might have changed! Throw away dispatcher state and restart TCB(B) sp live regs local state eax ebp x cs flg esp ss TCB(A) sp live regs local state eax ebp x cs flg esp ss Dispatcher stack local state eax ebp x cs flg esp ss local state 8
Example: Dispatch with Device IRQ Dispatcher interrupted by device IRQ sp Determine handler thread (B) Switch to B (assuming high priority) Throws away dispatcher state TCB(B) sp live regs local state eax ebp x cs flg esp ss TCB(A) sp live regs local state eax ebp x cs flg esp ss Dispatcher stack local state eax ebp x cs flg esp ss local state 9
Switch to () Dispatcher thread is also idle thread Thread A Dispatcher Thread switch to (dispatcher) select next ready thread, assume B switch to (B) B := A ; do B := next ready (B) ; if B nil then return fi ; idle od. Thread B 10
Priorities 0 (lowest) 255 Hard priorities Dynamically changeable Round robin per priority Ready TCB per priority Current TCB per do p := 255 ; do if current [p] nil then B := current [p] ; return fi ; p -= 1 until p < 0 od ; idle od. disp table Prio 100 Prio 50 11
Priorities Optimizations Remember highest active priority Bitmask do p if := current 255 [highest ; active p] nil then dob := current [highest active p] ; if return current [p] nil then elif highest B := current active [p] p ; > 0 then highest return active p -= 1 else fi ; p idle -= 1 until fi p < 0 od ; od idle. od. disp table Prio 100 Prio 50 12
Optimization: Priorities Bitmap Set bit on insertion Clear when group empty IA-32: BSR BIT SCAN REVERSE 2 cycles 240-255 224-239 208-223 32-47 16-31 0-15 13
Priorities, Preemption highest active p := max (new p, highest active p). do do p := 255; if current do [highest active p] nil then B := current if current [highest [p] nil active p] ; return then B := current [p] ; elif highest active p > 0 then return highest active p -= 1 fi ; else p -= 1 idle until p < 0 od ; fi idle od. od disp table Prio 110 Prio 100 Prio 50 p=110 intr/wakeup 14
Priorities, Preemption What happens when a priority falls empty? do if current [highest active p] nil then round robin if necessary ; B := current [highest active p] ; return elif highest active p > 0 then do highest active p -= 1 if else current [highest active p] nil then idle B := current [highest active p] ; fi return od elif. highest active p > 0 then highest active p -= 1 round elserobin if necessary: if current idle [hi act p].rem ts = 0 then fi current [hi act p].rem ts := new ts ; od. current [hi act p] := current [hi act p].next ; fi. disp table Prio 110 Prio 100 Prio 50? Remaining time slice > 0? 15
Priorities, Preemption What happens when a priority falls empty? do if current [highest active p] nil then round robin if necessary ; B := current [highest active p] ; return elif highest active p > 0 then highest active p -= 1 else fi od. idle round robin if necessary: if current [hi act p].rem ts = 0 then current [hi act p].rem ts := new ts ; current [hi act p] := current [hi act p].next ; fi. disp table Prio 110 Prio 100 Prio 50 Remaining time slice > 0 16
Preemption Preemption, time slice exhausted do if current [highest active p] nil then round robin if necessary ; B := current [highest active p] ; return elif highest active p > 0 then highest active p -= 1 else fi od. idle round robin if necessary: if current [hi act p].rem ts = 0 then current [hi act p].rem ts := new ts ; current [hi act p] := current [hi act p].next ; fi. disp table Prio 100 Prio 50 Remaining time slice = 0 17
Preemption Preemption, time slice exhausted do if current [highest active p] nil then round robin if necessary ; B := current [highest active p] ; return elif highest active p > 0 then highest active p -= 1 else fi od. idle round robin if necessary: if current [hi act p].rem ts = 0 then current [hi act p].rem ts := new ts ; current [hi act p] := current [hi act p].next ; fi. disp table Prio 100 Prio 50 Remaining time slice := new ts 18
Lazy Dispatching Thread state toggles frequently (per IPC) ready waiting Delete/insert ready is expensive Therefore: delete lazily from ready disp table Prio 100 Prio 50 ready ready ready 19
Lazy Dispatching Thread state toggles frequently (per IPC) ready waiting Delete/insert ready is expensive Therefore: delete lazily from ready disp table Prio 100 Prio 50 ready waiting ready 20
Lazy Dispatching Thread state toggles frequently (per IPC) ready waiting Delete/insert ready is expensive Therefore: delete lazily from ready disp table Prio 100 Prio 50 ready waiting ready 21
Lazy Dispatching Thread state toggles frequently (per IPC) ready waiting Delete/insert ready is expensive Therefore: delete lazily from ready disp table Prio 100 Prio 50 ready waiting ready 22
Lazy Dispatching Thread state toggles frequently (per IPC) ready waiting Delete/insert ready is expensive Therefore: delete lazily from ready Whenever reaching a non-ready thread Delete it from Proceed with next disp table Prio 100 ready ready Prio 50 23
Lazy Dispatching do round robin if necessary ; if current [highest active p] nil then Thread state toggles return frequently (per IPC) B := current [highest active p] ; return elif highest active p > 0 then highest active readyp -= 1 waiting else idle fi od. Delete/insert ready is expensive Therefore: delete lazily from ready Whenever reaching a non-ready thread Delete it from round robin if necessary: while current [hi act p] nil do next := current [hi act p].next ; if current [hi act p].state ready then delete from (current [hi act p] ) elif current [hi act p].rem ts = 0 then current [hi act p].rem ts := new ts else return fi ; current [hi act p] := next od. Proceed with next disp table 24 Prio 100 Prio 50 ready ready
Timeouts & Wakeups Operations Insert timeout Raise timeout Find next timeout Delete timeout timeout set completion, no timeout timeout expired t Raised-timeout costs are uncritical (occur only after timeout exp time). Most timeouts are never raised! 25
Timeouts & Wakeups too expensive Idea 1: unsorted Insert timeout costs Prepend entry 20..100 cycles Find next timeout t costs Parse entire n 10..50 cycles Raise timeout costs Delete timeout costs Delete known entry 20..100 cycles 26
Timeouts & Wakeups too expensive Idea 2: sorted Insert timeout costs Search + insert n/2 10..50 + 20..100 cycles Find next timeout t costs Check head 10 cycles Raise timeout costs Delete timeout costs Delete known entry 20..100 cycles 27
Timeouts & Wakeups Idea 3: sorted tree / heap too expensive too complicated Insert timeout costs Search + insert log n 10..50 + 20..100 cycles Find next timeout t costs Find min node / root log n x 10..50 / 10 cycles Raise timeout costs Delete timeout costs Delete known node log n x 10..50 + 20..100 / log n x 20..100 28
Wakeup Classes now insert timeout (now + ) soon late late late now soon t late late late 29
Wakeup Classes now soon late late late now soon t late late late 30
Wakeup Classes now soon late late late soon t late late contains soon entries late correction phase required late late 31
Wakeup Classes now soon late late late soon now t late late late late late contains soon and late entries late late correction phase required Also move late late entries to late Postpone further late late correction phases 32
Wakeup Classes now soon soon late late late now soon s := max #entries (length of soon ) t late s #timeouts to be raised in soon + new soon timeouts late late s is small if soon is short enough 33
Timeouts & Wakeups Idea 4: unsorted wakeup classes Insert timeout costs Select class + prepend 10 + 20..100 cycles Find next timeout t costs still Search soon class s 10..50 cycles Raise timeout costs Delete timeout costs Delete known entry 20..100 cycles too expensive Raised-timeout costs are uncritical (occur only after timeout exp time). Most timeouts are never raised! 34
Lazy Timeouts insert (t 1 ) soon late late late t 1 now soon Late t late late 35
Lazy Timeouts insert (t 1 ) delete timeout soon late late late now soon Late t late late 36
Lazy Timeouts insert (t 1 ) delete timeout insert (t 2 ) soon late late late t 2 now soon Late t late late 37