aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/select.go
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2024-06-11 11:02:18 -0700
committerDamien Neil <dneil@google.com>2024-11-19 19:40:40 +0000
commitd90ce588eac7b9105c0ca556a7c6e975fd5c1eca (patch)
tree4692a7f87738058c89bba874fe6d53b82786c44a /src/runtime/select.go
parent944df9a7516021f0405cd8adb1e6894ae9872cb5 (diff)
downloadgo-d90ce588eac7b9105c0ca556a7c6e975fd5c1eca.tar.xz
internal/synctest: new package for testing concurrent code
Add an internal (for now) implementation of testing/synctest. The synctest.Run function executes a tree of goroutines in an isolated environment using a fake clock. The synctest.Wait function allows a test to wait for all other goroutines within the test to reach a blocking point. For #67434 For #69687 Change-Id: Icb39e54c54cece96517e58ef9cfb18bf68506cfc Reviewed-on: https://go-review.googlesource.com/c/go/+/591997 Reviewed-by: Michael Pratt <mpratt@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Diffstat (limited to 'src/runtime/select.go')
-rw-r--r--src/runtime/select.go21
1 files changed, 18 insertions, 3 deletions
diff --git a/src/runtime/select.go b/src/runtime/select.go
index 2e86c85493..0b1d144951 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -120,6 +120,7 @@ func block() {
// Also, if the chosen scase was a receive operation, it reports whether
// a value was received.
func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, block bool) (int, bool) {
+ gp := getg()
if debugSelect {
print("select: cas0=", cas0, "\n")
}
@@ -165,6 +166,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
// generate permuted order
norder := 0
+ allSynctest := true
for i := range scases {
cas := &scases[i]
@@ -174,6 +176,14 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
continue
}
+ if cas.c.synctest {
+ if getg().syncGroup == nil {
+ panic(plainError("select on synctest channel from outside bubble"))
+ }
+ } else {
+ allSynctest = false
+ }
+
if cas.c.timer != nil {
cas.c.timer.maybeRunChan()
}
@@ -186,6 +196,13 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
pollorder = pollorder[:norder]
lockorder = lockorder[:norder]
+ waitReason := waitReasonSelect
+ if gp.syncGroup != nil && allSynctest {
+ // Every channel selected on is in a synctest bubble,
+ // so this goroutine will count as idle while selecting.
+ waitReason = waitReasonSynctestSelect
+ }
+
// sort the cases by Hchan address to get the locking order.
// simple heap sort, to guarantee n log n time and constant stack footprint.
for i := range lockorder {
@@ -235,7 +252,6 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
sellock(scases, lockorder)
var (
- gp *g
sg *sudog
c *hchan
k *scase
@@ -291,7 +307,6 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
}
// pass 2 - enqueue on all chans
- gp = getg()
if gp.waiting != nil {
throw("gp.waiting != nil")
}
@@ -333,7 +348,7 @@ func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, blo
// changes and when we set gp.activeStackChans is not safe for
// stack shrinking.
gp.parkingOnChan.Store(true)
- gopark(selparkcommit, nil, waitReasonSelect, traceBlockSelect, 1)
+ gopark(selparkcommit, nil, waitReason, traceBlockSelect, 1)
gp.activeStackChans = false
sellock(scases, lockorder)