aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Pratt <mpratt@google.com>2025-04-03 03:26:25 +0000
committerMichael Pratt <mpratt@google.com>2025-04-03 01:25:08 -0700
commit0b31e6d4cc804ab76ae8ced151ee2f50657aec14 (patch)
tree46b0581bb4422386090d702a79f33d83d7e2d28f
parent13b1261175efde5aac7c4c7f6f66ae3b2c609a2d (diff)
downloadgo-0b31e6d4cc804ab76ae8ced151ee2f50657aec14.tar.xz
runtime: cleanup M vgetrandom state before dropping P
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 #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>
-rw-r--r--src/runtime/os3_solaris.go5
-rw-r--r--src/runtime/os_aix.go5
-rw-r--r--src/runtime/os_darwin.go5
-rw-r--r--src/runtime/os_dragonfly.go5
-rw-r--r--src/runtime/os_linux.go9
-rw-r--r--src/runtime/os_netbsd.go5
-rw-r--r--src/runtime/os_openbsd.go5
-rw-r--r--src/runtime/os_plan9.go5
-rw-r--r--src/runtime/os_windows.go4
-rw-r--r--src/runtime/proc.go3
-rw-r--r--src/runtime/vgetrandom_linux.go11
-rw-r--r--src/runtime/vgetrandom_unsupported.go2
12 files changed, 48 insertions, 16 deletions
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
index cf163a6bf4..ded821b2e6 100644
--- a/src/runtime/os3_solaris.go
+++ b/src/runtime/os3_solaris.go
@@ -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) {
}
diff --git a/src/runtime/os_aix.go b/src/runtime/os_aix.go
index 93464cb997..1b483c2a7e 100644
--- a/src/runtime/os_aix.go
+++ b/src/runtime/os_aix.go
@@ -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) {
}
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 0ecbea7ae4..6eab3b5c3d 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -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) {
}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index a02696eb4f..9b3235084d 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -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) {
}
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index 55c4ac8f61..f24d18027b 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -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
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index 735ace25ad..a06e5febbd 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -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) {
}
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index 574bfa8b17..4ce4c3c58d 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -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) {
}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index b45e409b3a..6ddf1d21d4 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -218,8 +218,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) {
}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 489b396fc9..a84832e0ce 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -905,9 +905,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 {
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 74c19e9e43..cee91b6ce8 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -1958,6 +1958,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 {
diff --git a/src/runtime/vgetrandom_linux.go b/src/runtime/vgetrandom_linux.go
index 00ef2c2d4e..6ab12e3c67 100644
--- a/src/runtime/vgetrandom_linux.go
+++ b/src/runtime/vgetrandom_linux.go
@@ -74,9 +74,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)
}
diff --git a/src/runtime/vgetrandom_unsupported.go b/src/runtime/vgetrandom_unsupported.go
index 070392cfaa..43c53e1198 100644
--- a/src/runtime/vgetrandom_unsupported.go
+++ b/src/runtime/vgetrandom_unsupported.go
@@ -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() {}