Module preemption

Module preemption 

Source
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:

  1. 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.
  2. Windows: SuspendThread can 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.

  1. Interrupt: We stop the thread (Signal on Unix, SuspendThread on Windows).
  2. Inject: We modify the thread’s stack and instruction pointer (RIP/PC) to simulate a call to a trampoline function, saving the original RIP/PC on the stack.
  3. Resume: The thread resumes execution at the trampoline (outside signal/suspend context).
  4. 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§

PreemptionHandle
WorkerThreadHandle

Enums§

GeneratorYieldReason
Reasons the worker generator yields control back to the scheduler/trampoline.
PreemptionError

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.