| // Copyright 2019 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" | |
| "runtime/debug" | |
| "sync/atomic" | |
| ) | |
| func init() { | |
| register("AsyncPreempt", AsyncPreempt) | |
| } | |
| func AsyncPreempt() { | |
| // Run with just 1 GOMAXPROCS so the runtime is required to | |
| // use scheduler preemption. | |
| runtime.GOMAXPROCS(1) | |
| // Disable GC so we have complete control of what we're testing. | |
| debug.SetGCPercent(-1) | |
| // Out of an abundance of caution, also make sure that there are | |
| // no GCs actively in progress. The sweep phase of a GC cycle | |
| // for instance tries to preempt Ps at the very beginning. | |
| runtime.GC() | |
| // Start a goroutine with no sync safe-points. | |
| var ready, ready2 uint32 | |
| go func() { | |
| for { | |
| atomic.StoreUint32(&ready, 1) | |
| dummy() | |
| dummy() | |
| } | |
| }() | |
| // Also start one with a frameless function. | |
| // This is an especially interesting case for | |
| // LR machines. | |
| go func() { | |
| atomic.AddUint32(&ready2, 1) | |
| frameless() | |
| }() | |
| // Also test empty infinite loop. | |
| go func() { | |
| atomic.AddUint32(&ready2, 1) | |
| for { | |
| } | |
| }() | |
| // Wait for the goroutine to stop passing through sync | |
| // safe-points. | |
| for atomic.LoadUint32(&ready) == 0 || atomic.LoadUint32(&ready2) < 2 { | |
| runtime.Gosched() | |
| } | |
| // Run a GC, which will have to stop the goroutine for STW and | |
| // for stack scanning. If this doesn't work, the test will | |
| // deadlock and timeout. | |
| runtime.GC() | |
| println("OK") | |
| } | |
| //go:noinline | |
| func frameless() { | |
| for i := int64(0); i < 1<<62; i++ { | |
| out += i * i * i * i * i * 12345 | |
| } | |
| } | |
| var out int64 | |
| //go:noinline | |
| func dummy() {} | |