Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 42 additions & 1 deletion src/runtime/chan.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,11 +432,52 @@ func unlockAllStates(states []chanSelectState) {
func chanSelect(recvbuf unsafe.Pointer, states []chanSelectState, ops []channelOp) (uint32, bool) {
mask := interrupt.Disable()

const selectNoIndex = ^uint32(0)

// Fast path for non-blocking single-state selects, for example:
//
// select {
// case ch <- value:
// default:
// }
//
// Such selects can only lock at most one channel, so they don't need the
// global select lock. Also avoid lockAllStates/unlockAllStates here: they use
// channel.selectLocked, which is shared state protected by chanSelectLock.
if len(states) == 1 && len(ops) == 0 {
state := states[0]
selectIndex := selectNoIndex
selectOk := true

if state.ch != nil {
if hasParallelism {
state.ch.lock.Lock()
}

if state.value == nil { // chan receive
if received, ok := state.ch.tryRecv(recvbuf); received {
selectIndex = 0
selectOk = ok
}
} else { // chan send
if state.ch.trySend(state.value) {
selectIndex = 0
}
}

if hasParallelism {
state.ch.lock.Unlock()
}
}

interrupt.Restore(mask)
return selectIndex, selectOk
}

// Lock everything.
chanSelectLock.Lock()
lockAllStates(states)

const selectNoIndex = ^uint32(0)
selectIndex := selectNoIndex
selectOk := true

Expand Down
Loading