blob: fb6755a37253a90ef3c72f20b943a8db745560dd [file] [log] [blame]
// 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() {}