| // Copyright 2025 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package main | |
| import ( | |
| "runtime" | |
| ) | |
| func init() { | |
| register("mexitSTW", mexitSTW) | |
| } | |
| // Stress test for pp.oldm pointing to an exited M. | |
| // | |
| // If pp.oldm points to an exited M it should be ignored and another M used | |
| // instead. To stress: | |
| // | |
| // 1. Start and exit many threads (thus setting oldm on some P). | |
| // 2. Meanwhile, frequently stop the world. | |
| // | |
| // If procresize incorrect attempts to assign a P to an exited M, likely | |
| // failure modes are: | |
| // | |
| // 1. Crash in startTheWorldWithSema attempting to access the M, if it is nil. | |
| // | |
| // 2. Memory corruption elsewhere after startTheWorldWithSema writes to the M, | |
| // if it is not nil, but is freed and reused for another allocation. | |
| // | |
| // 3. Hang on a subsequent stop the world waiting for the P to stop, if the M | |
| // object is valid, but the M is exited, because startTheWorldWithSema didn't | |
| // actually wake anything to run the P. The P is _Pidle, but not in the pidle | |
| // list, thus startTheWorldWithSema will wake for it to actively stop. | |
| // | |
| // For this to go wrong, an exited M must fail to clear mp.self and must leave | |
| // the M on the sched.midle list. | |
| // | |
| // Similar to TraceSTW. | |
| func mexitSTW() { | |
| // Ensure we have multiple Ps, but not too many, as we want the | |
| // runnable goroutines likely to run on Ps with oldm set. | |
| runtime.GOMAXPROCS(4) | |
| // Background busy work so there is always something runnable. | |
| for i := range 2 { | |
| go traceSTWTarget(i) | |
| } | |
| // Wait for children to start running. | |
| ping.Store(1) | |
| for pong[0].Load() != 1 {} | |
| for pong[1].Load() != 1 {} | |
| for range 100 { | |
| // Exit a thread. The last P to run this will have it in oldm. | |
| go func() { | |
| runtime.LockOSThread() | |
| }() | |
| // STW | |
| var ms runtime.MemStats | |
| runtime.ReadMemStats(&ms) | |
| } | |
| stop.Store(true) | |
| println("OK") | |
| } | |