diff options
| author | Damien Neil <dneil@google.com> | 2024-06-11 11:02:18 -0700 |
|---|---|---|
| committer | Damien Neil <dneil@google.com> | 2024-11-19 19:40:40 +0000 |
| commit | d90ce588eac7b9105c0ca556a7c6e975fd5c1eca (patch) | |
| tree | 4692a7f87738058c89bba874fe6d53b82786c44a /src/runtime/select.go | |
| parent | 944df9a7516021f0405cd8adb1e6894ae9872cb5 (diff) | |
| download | go-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.go | 21 |
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) |
