Let’s break down the design of ParkThread and UnparkThread:
-
Overall Structure: Both
ParkThreadandUnparkThreadshare a commonInnerstruct through anArc:pub(crate) struct ParkThread { inner: Arc<Inner>, } pub(crate) struct UnparkThread { inner: Arc<Inner>, } struct Inner { state: AtomicUsize, mutex: Mutex<()>, condvar: Condvar, } -
State Management: The
Innerstruct uses anAtomicUsizeto manage the parking state:const EMPTY: usize = 0; const PARKED: usize = 1; const NOTIFIED: usize = 2; -
ParkThread Functionality:
new(): Creates a newParkThreadwith an initializedInner.unpark(): Creates anUnparkThreadfrom the sameInner.park(): Parks the current thread.park_timeout(): Parks the thread with a timeout.
-
UnparkThread Functionality:
unpark(): Unparks a parked thread.into_waker(): Converts theUnparkThreadinto aWakerfor use with futures.
-
Parking Mechanism: The
park()method inInner:- Uses compare-and-swap operations to manage state transitions.
- Utilizes a mutex and condition variable for actual thread blocking.
- Handles spurious wakeups by rechecking the state.
-
Unparking Mechanism: The
unpark()method inInner:- Uses atomic operations to update the state.
- Notifies the condition variable to wake up a parked thread.
-
Thread-Safety: The use of atomic operations, mutexes, and condition variables ensures thread-safe operation.
-
Waker Integration:
UnparkThreadcan be converted into aWaker, allowing integration with Rust’s async/await system. -
Efficiency:
- Fast path for already-notified threads.
- Atomic operations for quick state checks.
- Mutex only acquired when actually parking.
-
Flexibility: Supports both indefinite parking and timeout-based parking.
This design allows for efficient thread parking and unparking, which is crucial
for Tokio’s runtime performance. The separation of ParkThread and UnparkThread
allows for clear ownership semantics, where the thread that can park itself
holds the ParkThread, while other threads that need to wake it up can hold
UnparkThreads.