1// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package main
6
7import (
8	"runtime"
9	"runtime/debug"
10	"sync/atomic"
11)
12
13func init() {
14	register("AsyncPreempt", AsyncPreempt)
15}
16
17func AsyncPreempt() {
18	// Run with just 1 GOMAXPROCS so the runtime is required to
19	// use scheduler preemption.
20	runtime.GOMAXPROCS(1)
21	// Disable GC so we have complete control of what we're testing.
22	debug.SetGCPercent(-1)
23	// Out of an abundance of caution, also make sure that there are
24	// no GCs actively in progress. The sweep phase of a GC cycle
25	// for instance tries to preempt Ps at the very beginning.
26	runtime.GC()
27
28	// Start a goroutine with no sync safe-points.
29	var ready, ready2 uint32
30	go func() {
31		for {
32			atomic.StoreUint32(&ready, 1)
33			dummy()
34			dummy()
35		}
36	}()
37	// Also start one with a frameless function.
38	// This is an especially interesting case for
39	// LR machines.
40	go func() {
41		atomic.AddUint32(&ready2, 1)
42		frameless()
43	}()
44	// Also test empty infinite loop.
45	go func() {
46		atomic.AddUint32(&ready2, 1)
47		for {
48		}
49	}()
50
51	// Wait for the goroutine to stop passing through sync
52	// safe-points.
53	for atomic.LoadUint32(&ready) == 0 || atomic.LoadUint32(&ready2) < 2 {
54		runtime.Gosched()
55	}
56
57	// Run a GC, which will have to stop the goroutine for STW and
58	// for stack scanning. If this doesn't work, the test will
59	// deadlock and timeout.
60	runtime.GC()
61
62	println("OK")
63}
64
65//go:noinline
66func frameless() {
67	for i := int64(0); i < 1<<62; i++ {
68		out += i * i * i * i * i * 12345
69	}
70}
71
72var out int64
73
74//go:noinline
75func dummy() {}
76