]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.24] runtime: cleanup M vgetrandom state before dropping P
authorMichael Pratt <mpratt@google.com>
Thu, 3 Apr 2025 03:26:25 +0000 (03:26 +0000)
committerCarlos Amedee <carlos@golang.org>
Mon, 28 Apr 2025 17:33:46 +0000 (10:33 -0700)
When an M is destroyed, we put its vgetrandom state back on the shared
list for another M to reuse. This list is simply a slice, so appending
to the slice may allocate. Currently this operation is performed in
mdestroy, after the P is released, meaning allocation is not allowed.

More the cleanup earlier in mdestroy when allocation is still OK.

Also add //go:nowritebarrierrec to mdestroy since it runs without a P,
which would have caught this bug.

Fixes #73144.
For #73141.

Change-Id: I6a6a636c3fbf5c6eec09d07a260e39dbb4d2db12
Reviewed-on: https://go-review.googlesource.com/c/go/+/662455
Reviewed-by: Jason Donenfeld <Jason@zx2c4.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Keith Randall <khr@google.com>
(cherry picked from commit 0b31e6d4cc804ab76ae8ced151ee2f50657aec14)
Reviewed-on: https://go-review.googlesource.com/c/go/+/662496

12 files changed:
src/runtime/os3_solaris.go
src/runtime/os_aix.go
src/runtime/os_darwin.go
src/runtime/os_dragonfly.go
src/runtime/os_linux.go
src/runtime/os_netbsd.go
src/runtime/os_openbsd.go
src/runtime/os_plan9.go
src/runtime/os_windows.go
src/runtime/proc.go
src/runtime/vgetrandom_linux.go
src/runtime/vgetrandom_unsupported.go

index cf163a6bf401f69fafe174febdc056c10bc3c8a4..ded821b2e66f817a19e26c24166153bf42159f77 100644 (file)
@@ -234,8 +234,11 @@ func unminit() {
        getg().m.procid = 0
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
 }
 
index 93464cb997f3bea818ec9a192153156d5b133e7a..1b483c2a7e98567410a6041e292cfd00a7cc77a3 100644 (file)
@@ -186,8 +186,11 @@ func unminit() {
        getg().m.procid = 0
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
 }
 
index 0ecbea7ae47c609f97f5a924b8e991c80d64fb90..6eab3b5c3ddba63178a712fc798062fd58769baf 100644 (file)
@@ -344,8 +344,11 @@ func unminit() {
        getg().m.procid = 0
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
 }
 
index a02696eb4f566dfc25747bd69cd32ac5863ad1b1..9b3235084d7c4fd1264424b9c82466e0aaaac6c5 100644 (file)
@@ -216,8 +216,11 @@ func unminit() {
        getg().m.procid = 0
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
 }
 
index 8b3c4d0ecca1ddc782666d9a1120fb82f91380a8..fb46b816823ea48c3dbebd7f362f6e2afdf67517 100644 (file)
@@ -412,13 +412,12 @@ func unminit() {
        getg().m.procid = 0
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
-       if mp.vgetrandomState != 0 {
-               vgetrandomPutState(mp.vgetrandomState)
-               mp.vgetrandomState = 0
-       }
 }
 
 // #ifdef GOARCH_386
index 735ace25adb3b331e6202d7b1e6a8d9ee98e29c7..a06e5febbd5a75a200abe1642555526c3b429ea1 100644 (file)
@@ -320,8 +320,11 @@ func unminit() {
        // must continue working after unminit.
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
 }
 
index 574bfa8b1708be7861d3f605ce1d4c58356338ef..4ce4c3c58d35df6d984ca6c583c8e5c111aea063 100644 (file)
@@ -182,8 +182,11 @@ func unminit() {
        getg().m.procid = 0
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
 }
 
index 2dbb42ad037d1f1ca63a4d930004fa8868dff2de..3b5965ab996648bd1ce2d31a2c41c4ea9caa340e 100644 (file)
@@ -217,8 +217,11 @@ func minit() {
 func unminit() {
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
+//
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 func mdestroy(mp *m) {
 }
 
index 7183e79f7df093f8a8e378c45644b02384792f47..54407a320c054dd8d9f97b83aef31b1c412317fa 100644 (file)
@@ -906,9 +906,11 @@ func unminit() {
        mp.procid = 0
 }
 
-// Called from exitm, but not from drop, to undo the effect of thread-owned
+// Called from mexit, but not from dropm, to undo the effect of thread-owned
 // resources in minit, semacreate, or elsewhere. Do not take locks after calling this.
 //
+// This always runs without a P, so //go:nowritebarrierrec is required.
+//go:nowritebarrierrec
 //go:nosplit
 func mdestroy(mp *m) {
        if mp.highResTimer != 0 {
index e9873e54cd5709494f9d488982ebd311e574d283..21bee4df71a998956c793bbcee02e212dd6ddf03 100644 (file)
@@ -1935,6 +1935,9 @@ func mexit(osStack bool) {
                mp.gsignal = nil
        }
 
+       // Free vgetrandom state.
+       vgetrandomDestroy(mp)
+
        // Remove m from allm.
        lock(&sched.lock)
        for pprev := &allm; *pprev != nil; pprev = &(*pprev).alllink {
index a6ec4b701c1a8fcbf94a79b08fa30012bc8f856d..40be022f24fe77ea93e2e76649d459e9b7e485e6 100644 (file)
@@ -73,9 +73,16 @@ func vgetrandomGetState() uintptr {
        return state
 }
 
-func vgetrandomPutState(state uintptr) {
+// Free vgetrandom state from the M (if any) prior to destroying the M.
+//
+// This may allocate, so it must have a P.
+func vgetrandomDestroy(mp *m) {
+       if mp.vgetrandomState == 0 {
+               return
+       }
+
        lock(&vgetrandomAlloc.statesLock)
-       vgetrandomAlloc.states = append(vgetrandomAlloc.states, state)
+       vgetrandomAlloc.states = append(vgetrandomAlloc.states, mp.vgetrandomState)
        unlock(&vgetrandomAlloc.statesLock)
 }
 
index 070392cfaaf7a901bcaf9db9ef014e8d8e5ce0a4..43c53e1198843c4f8af85a9246c476ff698b4da4 100644 (file)
@@ -13,6 +13,6 @@ func vgetrandom(p []byte, flags uint32) (ret int, supported bool) {
        return -1, false
 }
 
-func vgetrandomPutState(state uintptr) {}
+func vgetrandomDestroy(mp *m) {}
 
 func vgetrandomInit() {}