Expand description
Preemptive scheduling support for worker threads.
This module provides platform-specific mechanisms to interrupt worker threads without terminating them, allowing generator context switching.
§Architecture
§The “Trampoline” Approach
To safely preempt a thread (on both Unix and Windows), we cannot simply run code inside a signal handler or a suspended thread context, because:
- Unix: Signal handlers run with signals blocked and are extremely restricted (async-signal-safety). Accessing Thread-Local Storage (TLS) or acquiring locks can deadlock or panic.
- Windows:
SuspendThreadcan stop a thread holding a lock (e.g., heap lock), leading to deadlocks if we try to allocate or use locks. Register corruption is also a major risk.
Solution: We “inject” a function call into the target thread’s stream of execution.
- Interrupt: We stop the thread (Signal on Unix, SuspendThread on Windows).
- Inject: We modify the thread’s stack and instruction pointer (RIP/PC) to simulate a call
to a
trampolinefunction, saving the original RIP/PC on the stack. - Resume: The thread resumes execution at the
trampoline(outside signal/suspend context). - Trampoline:
- Saves all volatile registers (preserving application state).
- Calls
rust_preemption_helper()(safe Rust code, can touch TLS/Locks). - Restores registers.
- Returns to the original code (via the saved RIP/PC).
This ensures full safety: the actual preemption logic (checking flags, yielding) runs as normal thread code, not in an interrupt context.
Structs§
Enums§
- Generator
Yield Reason - Reasons the worker generator yields control back to the scheduler/trampoline.
- Preemption
Error
Functions§
- rust_
preemption_ helper - This function is called by the assembly trampoline. It runs on the worker thread’s stack in a normal execution context. It is safe to access TLS and yield here.