Summary
Blocked select currently reconstructs the winning case after wakeup by scanning sudog.success. That is too weak for close-wakeup semantics and makes selection outcome ambiguous.
Why
- Channel close wakes blocked receivers and senders with
success = false.
select then has no explicit case winner for wakeups caused by close.
- This risks subtle semantic bugs in one of the most correctness-sensitive parts of the runtime.
Evidence
runtime/select.c: selectgo() finds the selected case by looking for sg->success == true after wakeup.
runtime/chan.c: closechan() wakes both recvq and sendq waiters with sg->success = false.
runtime/select.c: the post-wakeup closed-channel handling still assumes a selected case index exists.
Direction
- Store selected case index explicitly in the blocked goroutine state.
- Add an explicit wake reason such as
send, recv, closed, or cancelled.
- Keep
success for data-path bookkeeping only, not for deciding which case won.
Summary
Blocked
selectcurrently reconstructs the winning case after wakeup by scanningsudog.success. That is too weak for close-wakeup semantics and makes selection outcome ambiguous.Why
success = false.selectthen has no explicit case winner for wakeups caused byclose.Evidence
runtime/select.c:selectgo()finds the selected case by looking forsg->success == trueafter wakeup.runtime/chan.c:closechan()wakes bothrecvqandsendqwaiters withsg->success = false.runtime/select.c: the post-wakeup closed-channel handling still assumes a selected case index exists.Direction
send,recv,closed, orcancelled.successfor data-path bookkeeping only, not for deciding which case won.