Skip to main content

Module select

Module select 

Source
Expand description

selectgo — the runtime heart of select { }.

Ported from runtime/select.go.

§How it works

selectgo receives a slice of [SCase]s and an optional has_default flag and picks the first case that can proceed without blocking.

1. Build pollorder  — a random permutation of case indices (fairness).
2. Build lockorder  — case indices sorted by channel address (deadlock prevention).
3. Acquire all channel locks in lockorder.
4. First pass (pollorder): check each case for immediate readiness.
   – buffer op:    perform it, release all locks, return winner.
   – direct handoff (partner waiting): dequeue partner's sudog, perform op,
     release all locks, call goready(partner), return winner.
   – send on closed: release all locks, panic.
5. If has_default: release all locks, return (CASE_DEFAULT, false).
6. Blocking path:
   a. For every case, allocate a sudog (is_select=true) and enqueue it.
   b. Reset G.selectdone to 0 and G.param to null.
   c. Release all locks.
   d. gopark(Select).
7. On wakeup (winner wrote G.param = winning sudog):
   a. Acquire all locks in lockorder.
   b. Dequeue all *losing* sudogs (dequeue_sudog is a no-op if a racing
      channel op already removed them).
   c. Release all locks.
   d. Release all sudogs back to the free list.
   e. Return (winner_index, ok).

§Type erasure

Channels are generic (Hchan<T>) but selectgo must operate over a heterogeneous set of them. Each [SCase] carries four function pointers that are monomorphised at the call site (by the select! macro):

pointerpurpose
lock_fnacquire the channel’s RawMutex
unlock_fnrelease the channel’s RawMutex
try_fnattempt the channel op while all locks held
enqueue_fnenqueue a sudog on the channel’s wait queue
dequeue_fnremove a specific sudog (O(1) cleanup)

chan_ptr is the type-erased *const Hchan<T> used as the channel identity for deduplication and address-ordered locking.

§Sentinel index

selectgo returns CASE_DEFAULT (usize::MAX) when the default case is taken. Channel cases use their 0-based index within the slice.

Constants§

CASE_DEFAULT
Return value from [selectgo] when the default case is taken.