diff options
| author | Daniel Morsing <daniel.morsing@gmail.com> | 2025-11-27 14:49:09 +0000 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2026-02-27 12:41:12 -0800 |
| commit | 62a1da372a2bfeb29644246ff0f61dc048bb912c (patch) | |
| tree | 8aa901636e926591fbac77afd575e61b9c1d6dba /src/runtime/proc.go | |
| parent | 6a712954669bc9cdbf748be5b2b6613af41a2675 (diff) | |
| download | go-62a1da372a2bfeb29644246ff0f61dc048bb912c.tar.xz | |
runtime: do signal stack clearing when parking Ms
Clearing signal stacks during STW meant an added latency that was linear
with respect to the number of Ms, parked or running. Since that number
be quite high, we need an alternate scheme.
Instead of clearing in the GC cycle, clear the signal stack whenever an
M is parked and has the potential to stay parked until the end of the
next GC cycle. This implements the wanted behavior for runtime/secret at
the cost of a little bit of extra latency that will be dwarfed by the
time it takes to perform a syscall.
Change-Id: Ieb9618f46736c34486e17a3d6185661a98756d0d
Reviewed-on: https://go-review.googlesource.com/c/go/+/724282
Auto-Submit: Daniel Morsing <daniel.morsing@gmail.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Michael Pratt <mpratt@google.com>
Diffstat (limited to 'src/runtime/proc.go')
| -rw-r--r-- | src/runtime/proc.go | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/src/runtime/proc.go b/src/runtime/proc.go index 8027ac5bee..db4febace9 100644 --- a/src/runtime/proc.go +++ b/src/runtime/proc.go @@ -1968,6 +1968,11 @@ func mstartm0() { //go:nosplit func mPark() { gp := getg() + // This M might stay parked through an entire GC cycle. + // Erase any leftovers on the signal stack. + if goexperiment.RuntimeSecret { + eraseSecretsSignalStk() + } notesleep(&gp.m.park) noteclear(&gp.m.park) } @@ -4635,6 +4640,30 @@ func reentersyscall(pc, sp, bp uintptr) { // but can have inconsistent g->sched, do not let GC observe it. gp.m.locks++ + // This M may have a signal stack that is dirtied with secret information + // (see package "runtime/secret"). Since it's about to go into a syscall for + // an arbitrary amount of time and the G that put the secret info there + // might have returned from secret.Do, we have to zero it out now, lest we + // break the guarantee that secrets are purged by the next GC after a return + // to secret.Do. + // + // It might be tempting to think that we only need to zero out this if we're + // not running in secret mode anymore, but that leaves an ABA problem. The G + // that put the secrets onto our signal stack may not be the one that is + // currently executing. + // + // Logically, we should erase this when we lose our P, not when we enter the + // syscall. This would avoid a zeroing in the case where the call returns + // almost immediately. Since we use this path for cgo calls as well, these + // fast "syscalls" are quite common. However, since we only erase the signal + // stack if we were delivered a signal in secret mode and considering the + // cross-thread synchronization cost for the P, it hardly seems worth it. + // + // TODO(dmo): can we encode the goid into mp.signalSecret and avoid the ABA problem? + if goexperiment.RuntimeSecret { + eraseSecretsSignalStk() + } + // Entersyscall must not call any function that might split/grow the stack. // (See details in comment above.) // Catch calls that might, by replacing the stack guard with something that |
