summaryrefslogtreecommitdiffstats
path: root/src/runtime/testdata/testprog/preempt.go
blob: fb6755a37253a90ef3c72f20b943a8db745560dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// 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() {}