diff options
author | Austin Clements <austin@google.com> | 2019-09-27 12:27:51 -0400 |
---|---|---|
committer | Austin Clements <austin@google.com> | 2019-10-25 23:25:28 +0000 |
commit | 3f834114ab617eb7b414cb12e7ca8085b5fe3a5c (patch) | |
tree | 1eaf7f59fe268f9936fbb192c297397d6145ddb1 /src/runtime/mgcmark.go | |
parent | 46e0d724b3f14fd0d350123bbf101e815b493791 (diff) | |
download | go-3f834114ab617eb7b414cb12e7ca8085b5fe3a5c.tar.gz go-3f834114ab617eb7b414cb12e7ca8085b5fe3a5c.zip |
runtime: add general suspendG/resumeG
Currently, the process of suspending a goroutine is tied to stack
scanning. In preparation for non-cooperative preemption, this CL
abstracts this into general purpose suspendG/resumeG functions.
suspendG and resumeG closely follow the existing scang and restartg
functions with one exception: the addition of a _Gpreempted status.
Currently, preemption tasks (stack scanning) are carried out by the
target goroutine if it's in _Grunning. In this new approach, the task
is always carried out by the goroutine that called suspendG. Thus, we
need a reliable way to drive the target goroutine out of _Grunning
until the requesting goroutine is ready to resume it. The new
_Gpreempted state provides the handshake: when a runnable goroutine
responds to a preemption request, it now parks itself and enters
_Gpreempted. The requesting goroutine races to put it in _Gwaiting,
which gives it ownership, but also the responsibility to start it
again.
This CL adds several TODOs about improving the synchronization on the
G status. The existing code already has these problems; we're just
taking note of them.
The next CL will remove the now-dead scang and preemptscan.
For #10958, #24543.
Change-Id: I16dbf87bea9d50399cc86719c156f48e67198f16
Reviewed-on: https://go-review.googlesource.com/c/go/+/201137
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/mgcmark.go')
-rw-r--r-- | src/runtime/mgcmark.go | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go index 645083db07..adfdaced18 100644 --- a/src/runtime/mgcmark.go +++ b/src/runtime/mgcmark.go @@ -211,14 +211,24 @@ func markroot(gcw *gcWork, i uint32) { userG.waitreason = waitReasonGarbageCollectionScan } - // TODO: scang blocks until gp's stack has - // been scanned, which may take a while for + // TODO: suspendG blocks (and spins) until gp + // stops, which may take a while for // running goroutines. Consider doing this in // two phases where the first is non-blocking: // we scan the stacks we can and ask running // goroutines to scan themselves; and the // second blocks. - scang(gp, gcw) + stopped := suspendG(gp) + if stopped.dead { + gp.gcscandone = true + return + } + if gp.gcscandone { + throw("g already scanned") + } + scanstack(gp, gcw) + gp.gcscandone = true + resumeG(stopped) if selfScan { casgstatus(userG, _Gwaiting, _Grunning) |