aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/debug.go
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2025-05-28 16:01:33 -0400
committerMichael Pratt <mpratt@google.com>2025-05-29 10:55:39 -0700
commite481a08e0ecb823f368318b142d3dec7340fe51e (patch)
tree3a6463be44bee26437074c9d8ad2fc525dacd126 /src/runtime/debug.go
parentdd678172e378e62cc85d075676e040354f4628da (diff)
downloadgo-e481a08e0ecb823f368318b142d3dec7340fe51e.tar.xz
runtime: guarantee no GOMAXPROCS update syscalls after GOMAXPROCS call
We already guarantee that no automatic updates to GOMAXPROCS occur after a GOMAXPROCS call returns. This is easily achieved by having the update goroutine double-check that updates are still allowed during STW before committing the new value. However, it is possible for sysmon to concurrently run defaultGOMAXPROCS to compute a new GOMAXPROCS value after GOMAXPROCS returns. This new value will be discarded later, but we'll still perform the system calls necessary to compute the new value. Normally this distinction doesn't matter, but if you want to sandbox a Go program, then you may want to disable GOMAXPROCS updates to reduce the system call footprint. A call to GOMAXPROCS will disable updates, but without a guarantee on when sysmon will observe the change it is somewhat fragile. Add explicit synchronization between GOMAXPROCS and sysmon to guarantee that sysmon won't run defaultGOMAXPROCS after GOMAXPROCS returns. The synchronization is a bit complex because we can't hold a mutex across STW, nor take a semaphore from sysmon, but the result isn't too bad. One oddity is that sched.customGOMAXPROCS and gomaxprocs are no longer updated in lockstep (even though both are protected by sched.lock), but I don't believe anything should depend on that. For #73193. Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-staticlockranking Change-Id: I6a6a636cff243a9b69ac1b5d2f98925648e60236 Reviewed-on: https://go-review.googlesource.com/c/go/+/677037 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
Diffstat (limited to 'src/runtime/debug.go')
-rw-r--r--src/runtime/debug.go15
1 files changed, 12 insertions, 3 deletions
diff --git a/src/runtime/debug.go b/src/runtime/debug.go
index 94d1dab34d..bdaaa7196d 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -39,10 +39,18 @@ func GOMAXPROCS(n int) int {
lock(&sched.lock)
ret := int(gomaxprocs)
- unlock(&sched.lock)
if n <= 0 || n == ret {
+ unlock(&sched.lock)
return ret
}
+ // Set early so we can wait for sysmon befor STW. See comment on
+ // computeMaxProcsLock.
+ sched.customGOMAXPROCS = true
+ unlock(&sched.lock)
+
+ // Wait for sysmon to complete running defaultGOMAXPROCS.
+ lock(&computeMaxProcsLock)
+ unlock(&computeMaxProcsLock)
stw := stopTheWorldGC(stwGOMAXPROCS)
@@ -51,7 +59,6 @@ func GOMAXPROCS(n int) int {
// TODO(prattmic): this could use a nicer API. Perhaps add it to the
// stw parameter?
newprocs = int32(n)
- newprocsCustom = true
startTheWorldGC(stw)
return ret
@@ -91,7 +98,9 @@ func SetDefaultGOMAXPROCS() {
// TODO(prattmic): this could use a nicer API. Perhaps add it to the
// stw parameter?
newprocs = procs
- newprocsCustom = false
+ lock(&sched.lock)
+ sched.customGOMAXPROCS = false
+ unlock(&sched.lock)
startTheWorldGC(stw)
}