feat(channel): select — ready-index wait over multiple receivers
select(&[&dyn Selectable]) -> usize registers (pid, epoch) in every arm under one wait epoch, parks once, and returns the first ready index in documented priority order (BEAM-style; no fairness promise). A closed arm counts as ready — and stays ready forever, so callers drop it from the set once observed. Losing arms need no cancellation pass: the winning wake consumed the epoch, so their registrations die at their wakers' failed CAS or are overwritten by the receiver's next wait on that channel (the single-receiver debug_asserts relax to 'none or own pid' accordingly). The one genuinely new protocol piece is the no-park exit: returning with an arm ready at registration time leaves earlier arms holding LIVE-epoch registrations, whose wakes could fault a later one-shot park as a pending notification. scheduler::retire_wait closes it — bump the epoch (in-flight wakes die at their CAS), eat a notification that already landed (StateWord::clear_notify), then re-observe the stop flag, in that order. Proved by the new loom theorem retire_eats_late_arm_notification; the integration probes in tests/select.rs fire stale loser-arm wakes and assert a subsequent sleep's one-shot park holds its full duration.
This commit is contained in:
+1
-1
@@ -45,7 +45,7 @@ static ALLOCATOR: preempt::PreemptingAllocator = preempt::PreemptingAllocator;
|
||||
// Public API re-exports
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
pub use channel::{channel, Receiver, RecvError, RecvTimeoutError, Sender};
|
||||
pub use channel::{channel, select, Receiver, RecvError, RecvTimeoutError, Selectable, Sender};
|
||||
pub use gen_server::{CallError, CallTimeoutError, CastError, GenServer, ServerRef};
|
||||
pub use link::{link, trap_exit, unlink, ExitSignal};
|
||||
pub use monitor::{demonitor, monitor, Down, DownReason, Monitor, MonitorId};
|
||||
|
||||
Reference in New Issue
Block a user