Skip to content

Commit 812beeb

Browse files
committed
feat: use fast path when channel has been closed and empty
1 parent 9777cec commit 812beeb

File tree

1 file changed

+16
-12
lines changed

1 file changed

+16
-12
lines changed

src/runtime/chan.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -545,8 +545,9 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
545545
c.timer.maybeRunChan(c)
546546
}
547547

548-
// Fast path: check for failed non-blocking operation without acquiring the lock.
549-
if !block && empty(c) {
548+
// Fast path: check for failed non-blocking operation and receiving on closed chan without
549+
// acquiring the lock.
550+
if empty(c) {
550551
// After observing that the channel is not ready for receiving, we observe whether the
551552
// channel is closed.
552553
//
@@ -557,16 +558,18 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
557558
// separate critical sections under the same lock. This assumption fails when closing
558559
// an unbuffered channel with a blocked send, but that is an error condition anyway.
559560
if atomic.Load(&c.closed) == 0 {
560-
// Because a channel cannot be reopened, the later observation of the channel
561-
// being not closed implies that it was also not closed at the moment of the
562-
// first observation. We behave as if we observed the channel at that moment
563-
// and report that the receive cannot proceed.
564-
return
565-
}
566-
// The channel is irreversibly closed. Re-check whether the channel has any pending data
567-
// to receive, which could have arrived between the empty and closed checks above.
568-
// Sequential consistency is also required here, when racing with such a send.
569-
if empty(c) {
561+
if !block {
562+
// Because a channel cannot be reopened, the later observation of the channel
563+
// being not closed implies that it was also not closed at the moment of the
564+
// first observation. We behave as if we observed the channel at that moment
565+
// and report that the receive cannot proceed.
566+
return
567+
}
568+
} else if empty(c) {
569+
// The channel is irreversibly closed. Re-check whether the channel has any pending data
570+
// to receive, which could have arrived between the empty and closed checks above.
571+
// Sequential consistency is also required here, when racing with such a send.
572+
570573
// The channel is irreversibly closed and empty.
571574
if raceenabled {
572575
raceacquire(c.raceaddr())
@@ -576,6 +579,7 @@ func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
576579
}
577580
return true, false
578581
}
582+
// Fast path failed: this is not a closed chan or data in it. Lets get lock
579583
}
580584

581585
var t0 int64

0 commit comments

Comments
 (0)