1// Copyright 2011 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 runtime_test
6
7import (
8	"fmt"
9	"internal/testenv"
10	"math"
11	"net"
12	"runtime"
13	"runtime/debug"
14	"strings"
15	"sync"
16	"sync/atomic"
17	"syscall"
18	"testing"
19	"time"
20)
21
22var stop = make(chan bool, 1)
23
24func perpetuumMobile() {
25	select {
26	case <-stop:
27	default:
28		go perpetuumMobile()
29	}
30}
31
32func TestStopTheWorldDeadlock(t *testing.T) {
33	if runtime.GOARCH == "wasm" {
34		t.Skip("no preemption on wasm yet")
35	}
36	if testing.Short() {
37		t.Skip("skipping during short test")
38	}
39	maxprocs := runtime.GOMAXPROCS(3)
40	compl := make(chan bool, 2)
41	go func() {
42		for i := 0; i != 1000; i += 1 {
43			runtime.GC()
44		}
45		compl <- true
46	}()
47	go func() {
48		for i := 0; i != 1000; i += 1 {
49			runtime.GOMAXPROCS(3)
50		}
51		compl <- true
52	}()
53	go perpetuumMobile()
54	<-compl
55	<-compl
56	stop <- true
57	runtime.GOMAXPROCS(maxprocs)
58}
59
60func TestYieldProgress(t *testing.T) {
61	testYieldProgress(false)
62}
63
64func TestYieldLockedProgress(t *testing.T) {
65	testYieldProgress(true)
66}
67
68func testYieldProgress(locked bool) {
69	c := make(chan bool)
70	cack := make(chan bool)
71	go func() {
72		if locked {
73			runtime.LockOSThread()
74		}
75		for {
76			select {
77			case <-c:
78				cack <- true
79				return
80			default:
81				runtime.Gosched()
82			}
83		}
84	}()
85	time.Sleep(10 * time.Millisecond)
86	c <- true
87	<-cack
88}
89
90func TestYieldLocked(t *testing.T) {
91	const N = 10
92	c := make(chan bool)
93	go func() {
94		runtime.LockOSThread()
95		for i := 0; i < N; i++ {
96			runtime.Gosched()
97			time.Sleep(time.Millisecond)
98		}
99		c <- true
100		// runtime.UnlockOSThread() is deliberately omitted
101	}()
102	<-c
103}
104
105func TestGoroutineParallelism(t *testing.T) {
106	if runtime.NumCPU() == 1 {
107		// Takes too long, too easy to deadlock, etc.
108		t.Skip("skipping on uniprocessor")
109	}
110	P := 4
111	N := 10
112	if testing.Short() {
113		P = 3
114		N = 3
115	}
116	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
117	// If runtime triggers a forced GC during this test then it will deadlock,
118	// since the goroutines can't be stopped/preempted.
119	// Disable GC for this test (see issue #10958).
120	defer debug.SetGCPercent(debug.SetGCPercent(-1))
121	for try := 0; try < N; try++ {
122		done := make(chan bool)
123		x := uint32(0)
124		for p := 0; p < P; p++ {
125			// Test that all P goroutines are scheduled at the same time
126			go func(p int) {
127				for i := 0; i < 3; i++ {
128					expected := uint32(P*i + p)
129					for atomic.LoadUint32(&x) != expected {
130					}
131					atomic.StoreUint32(&x, expected+1)
132				}
133				done <- true
134			}(p)
135		}
136		for p := 0; p < P; p++ {
137			<-done
138		}
139	}
140}
141
142// Test that all runnable goroutines are scheduled at the same time.
143func TestGoroutineParallelism2(t *testing.T) {
144	//testGoroutineParallelism2(t, false, false)
145	testGoroutineParallelism2(t, true, false)
146	testGoroutineParallelism2(t, false, true)
147	testGoroutineParallelism2(t, true, true)
148}
149
150func testGoroutineParallelism2(t *testing.T, load, netpoll bool) {
151	if runtime.NumCPU() == 1 {
152		// Takes too long, too easy to deadlock, etc.
153		t.Skip("skipping on uniprocessor")
154	}
155	P := 4
156	N := 10
157	if testing.Short() {
158		N = 3
159	}
160	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
161	// If runtime triggers a forced GC during this test then it will deadlock,
162	// since the goroutines can't be stopped/preempted.
163	// Disable GC for this test (see issue #10958).
164	defer debug.SetGCPercent(debug.SetGCPercent(-1))
165	for try := 0; try < N; try++ {
166		if load {
167			// Create P goroutines and wait until they all run.
168			// When we run the actual test below, worker threads
169			// running the goroutines will start parking.
170			done := make(chan bool)
171			x := uint32(0)
172			for p := 0; p < P; p++ {
173				go func() {
174					if atomic.AddUint32(&x, 1) == uint32(P) {
175						done <- true
176						return
177					}
178					for atomic.LoadUint32(&x) != uint32(P) {
179					}
180				}()
181			}
182			<-done
183		}
184		if netpoll {
185			// Enable netpoller, affects schedler behavior.
186			laddr := "localhost:0"
187			if runtime.GOOS == "android" {
188				// On some Android devices, there are no records for localhost,
189				// see https://golang.org/issues/14486.
190				// Don't use 127.0.0.1 for every case, it won't work on IPv6-only systems.
191				laddr = "127.0.0.1:0"
192			}
193			ln, err := net.Listen("tcp", laddr)
194			if err != nil {
195				defer ln.Close() // yup, defer in a loop
196			}
197		}
198		done := make(chan bool)
199		x := uint32(0)
200		// Spawn P goroutines in a nested fashion just to differ from TestGoroutineParallelism.
201		for p := 0; p < P/2; p++ {
202			go func(p int) {
203				for p2 := 0; p2 < 2; p2++ {
204					go func(p2 int) {
205						for i := 0; i < 3; i++ {
206							expected := uint32(P*i + p*2 + p2)
207							for atomic.LoadUint32(&x) != expected {
208							}
209							atomic.StoreUint32(&x, expected+1)
210						}
211						done <- true
212					}(p2)
213				}
214			}(p)
215		}
216		for p := 0; p < P; p++ {
217			<-done
218		}
219	}
220}
221
222func TestBlockLocked(t *testing.T) {
223	const N = 10
224	c := make(chan bool)
225	go func() {
226		runtime.LockOSThread()
227		for i := 0; i < N; i++ {
228			c <- true
229		}
230		runtime.UnlockOSThread()
231	}()
232	for i := 0; i < N; i++ {
233		<-c
234	}
235}
236
237func TestTimerFairness(t *testing.T) {
238	if runtime.GOARCH == "wasm" {
239		t.Skip("no preemption on wasm yet")
240	}
241
242	done := make(chan bool)
243	c := make(chan bool)
244	for i := 0; i < 2; i++ {
245		go func() {
246			for {
247				select {
248				case c <- true:
249				case <-done:
250					return
251				}
252			}
253		}()
254	}
255
256	timer := time.After(20 * time.Millisecond)
257	for {
258		select {
259		case <-c:
260		case <-timer:
261			close(done)
262			return
263		}
264	}
265}
266
267func TestTimerFairness2(t *testing.T) {
268	if runtime.GOARCH == "wasm" {
269		t.Skip("no preemption on wasm yet")
270	}
271
272	done := make(chan bool)
273	c := make(chan bool)
274	for i := 0; i < 2; i++ {
275		go func() {
276			timer := time.After(20 * time.Millisecond)
277			var buf [1]byte
278			for {
279				syscall.Read(0, buf[0:0])
280				select {
281				case c <- true:
282				case <-c:
283				case <-timer:
284					done <- true
285					return
286				}
287			}
288		}()
289	}
290	<-done
291	<-done
292}
293
294// The function is used to test preemption at split stack checks.
295// Declaring a var avoids inlining at the call site.
296var preempt = func() int {
297	var a [128]int
298	sum := 0
299	for _, v := range a {
300		sum += v
301	}
302	return sum
303}
304
305func TestPreemption(t *testing.T) {
306	if runtime.Compiler == "gccgo" {
307		t.Skip("gccgo does not implement preemption")
308	}
309	if runtime.GOARCH == "wasm" {
310		t.Skip("no preemption on wasm yet")
311	}
312
313	// Test that goroutines are preempted at function calls.
314	N := 5
315	if testing.Short() {
316		N = 2
317	}
318	c := make(chan bool)
319	var x uint32
320	for g := 0; g < 2; g++ {
321		go func(g int) {
322			for i := 0; i < N; i++ {
323				for atomic.LoadUint32(&x) != uint32(g) {
324					preempt()
325				}
326				atomic.StoreUint32(&x, uint32(1-g))
327			}
328			c <- true
329		}(g)
330	}
331	<-c
332	<-c
333}
334
335func TestPreemptionGC(t *testing.T) {
336	if runtime.Compiler == "gccgo" {
337		t.Skip("gccgo does not implement preemption")
338	}
339	if runtime.GOARCH == "wasm" {
340		t.Skip("no preemption on wasm yet")
341	}
342
343	// Test that pending GC preempts running goroutines.
344	P := 5
345	N := 10
346	if testing.Short() {
347		P = 3
348		N = 2
349	}
350	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P + 1))
351	var stop uint32
352	for i := 0; i < P; i++ {
353		go func() {
354			for atomic.LoadUint32(&stop) == 0 {
355				preempt()
356			}
357		}()
358	}
359	for i := 0; i < N; i++ {
360		runtime.Gosched()
361		runtime.GC()
362	}
363	atomic.StoreUint32(&stop, 1)
364}
365
366func TestAsyncPreempt(t *testing.T) {
367	if !runtime.PreemptMSupported {
368		t.Skip("asynchronous preemption not supported on this platform")
369	}
370	output := runTestProg(t, "testprog", "AsyncPreempt")
371	want := "OK\n"
372	if output != want {
373		t.Fatalf("want %s, got %s\n", want, output)
374	}
375}
376
377func TestGCFairness(t *testing.T) {
378	output := runTestProg(t, "testprog", "GCFairness")
379	want := "OK\n"
380	if output != want {
381		t.Fatalf("want %s, got %s\n", want, output)
382	}
383}
384
385func TestGCFairness2(t *testing.T) {
386	output := runTestProg(t, "testprog", "GCFairness2")
387	want := "OK\n"
388	if output != want {
389		t.Fatalf("want %s, got %s\n", want, output)
390	}
391}
392
393func TestNumGoroutine(t *testing.T) {
394	output := runTestProg(t, "testprog", "NumGoroutine")
395	want := "1\n"
396	if output != want {
397		t.Fatalf("want %q, got %q", want, output)
398	}
399
400	buf := make([]byte, 1<<20)
401
402	// Try up to 10 times for a match before giving up.
403	// This is a fundamentally racy check but it's important
404	// to notice if NumGoroutine and Stack are _always_ out of sync.
405	for i := 0; ; i++ {
406		// Give goroutines about to exit a chance to exit.
407		// The NumGoroutine and Stack below need to see
408		// the same state of the world, so anything we can do
409		// to keep it quiet is good.
410		runtime.Gosched()
411
412		n := runtime.NumGoroutine()
413		buf = buf[:runtime.Stack(buf, true)]
414
415		nstk := strings.Count(string(buf), "goroutine ")
416		if n == nstk {
417			break
418		}
419		if i >= 10 {
420			t.Fatalf("NumGoroutine=%d, but found %d goroutines in stack dump: %s", n, nstk, buf)
421		}
422	}
423}
424
425func TestPingPongHog(t *testing.T) {
426	if runtime.GOARCH == "wasm" {
427		t.Skip("no preemption on wasm yet")
428	}
429	if testing.Short() {
430		t.Skip("skipping in -short mode")
431	}
432
433	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
434	done := make(chan bool)
435	hogChan, lightChan := make(chan bool), make(chan bool)
436	hogCount, lightCount := 0, 0
437
438	run := func(limit int, counter *int, wake chan bool) {
439		for {
440			select {
441			case <-done:
442				return
443
444			case <-wake:
445				for i := 0; i < limit; i++ {
446					*counter++
447				}
448				wake <- true
449			}
450		}
451	}
452
453	// Start two co-scheduled hog goroutines.
454	for i := 0; i < 2; i++ {
455		go run(1e6, &hogCount, hogChan)
456	}
457
458	// Start two co-scheduled light goroutines.
459	for i := 0; i < 2; i++ {
460		go run(1e3, &lightCount, lightChan)
461	}
462
463	// Start goroutine pairs and wait for a few preemption rounds.
464	hogChan <- true
465	lightChan <- true
466	time.Sleep(100 * time.Millisecond)
467	close(done)
468	<-hogChan
469	<-lightChan
470
471	// Check that hogCount and lightCount are within a factor of
472	// 5, which indicates that both pairs of goroutines handed off
473	// the P within a time-slice to their buddy. We can use a
474	// fairly large factor here to make this robust: if the
475	// scheduler isn't working right, the gap should be ~1000X.
476	const factor = 5
477	if hogCount > lightCount*factor || lightCount > hogCount*factor {
478		t.Fatalf("want hogCount/lightCount in [%v, %v]; got %d/%d = %g", 1.0/factor, factor, hogCount, lightCount, float64(hogCount)/float64(lightCount))
479	}
480}
481
482func BenchmarkPingPongHog(b *testing.B) {
483	if b.N == 0 {
484		return
485	}
486	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
487
488	// Create a CPU hog
489	stop, done := make(chan bool), make(chan bool)
490	go func() {
491		for {
492			select {
493			case <-stop:
494				done <- true
495				return
496			default:
497			}
498		}
499	}()
500
501	// Ping-pong b.N times
502	ping, pong := make(chan bool), make(chan bool)
503	go func() {
504		for j := 0; j < b.N; j++ {
505			pong <- <-ping
506		}
507		close(stop)
508		done <- true
509	}()
510	go func() {
511		for i := 0; i < b.N; i++ {
512			ping <- <-pong
513		}
514		done <- true
515	}()
516	b.ResetTimer()
517	ping <- true // Start ping-pong
518	<-stop
519	b.StopTimer()
520	<-ping // Let last ponger exit
521	<-done // Make sure goroutines exit
522	<-done
523	<-done
524}
525
526func stackGrowthRecursive(i int) {
527	var pad [128]uint64
528	if i != 0 && pad[0] == 0 {
529		stackGrowthRecursive(i - 1)
530	}
531}
532
533func TestPreemptSplitBig(t *testing.T) {
534	if testing.Short() {
535		t.Skip("skipping in -short mode")
536	}
537	t.Skip("gccgo does not implement preemption")
538	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
539	stop := make(chan int)
540	go big(stop)
541	for i := 0; i < 3; i++ {
542		time.Sleep(10 * time.Microsecond) // let big start running
543		runtime.GC()
544	}
545	close(stop)
546}
547
548func big(stop chan int) int {
549	n := 0
550	for {
551		// delay so that gc is sure to have asked for a preemption
552		for i := 0; i < 1e9; i++ {
553			n++
554		}
555
556		// call bigframe, which used to miss the preemption in its prologue.
557		bigframe(stop)
558
559		// check if we've been asked to stop.
560		select {
561		case <-stop:
562			return n
563		}
564	}
565}
566
567func bigframe(stop chan int) int {
568	// not splitting the stack will overflow.
569	// small will notice that it needs a stack split and will
570	// catch the overflow.
571	var x [8192]byte
572	return small(stop, &x)
573}
574
575func small(stop chan int, x *[8192]byte) int {
576	for i := range x {
577		x[i] = byte(i)
578	}
579	sum := 0
580	for i := range x {
581		sum += int(x[i])
582	}
583
584	// keep small from being a leaf function, which might
585	// make it not do any stack check at all.
586	nonleaf(stop)
587
588	return sum
589}
590
591func nonleaf(stop chan int) bool {
592	// do something that won't be inlined:
593	select {
594	case <-stop:
595		return true
596	default:
597		return false
598	}
599}
600
601func TestSchedLocalQueue(t *testing.T) {
602	runtime.RunSchedLocalQueueTest()
603}
604
605func TestSchedLocalQueueSteal(t *testing.T) {
606	runtime.RunSchedLocalQueueStealTest()
607}
608
609func TestSchedLocalQueueEmpty(t *testing.T) {
610	if runtime.NumCPU() == 1 {
611		// Takes too long and does not trigger the race.
612		t.Skip("skipping on uniprocessor")
613	}
614	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
615
616	// If runtime triggers a forced GC during this test then it will deadlock,
617	// since the goroutines can't be stopped/preempted during spin wait.
618	defer debug.SetGCPercent(debug.SetGCPercent(-1))
619
620	iters := int(1e5)
621	if testing.Short() {
622		iters = 1e2
623	}
624	runtime.RunSchedLocalQueueEmptyTest(iters)
625}
626
627func benchmarkStackGrowth(b *testing.B, rec int) {
628	b.RunParallel(func(pb *testing.PB) {
629		for pb.Next() {
630			stackGrowthRecursive(rec)
631		}
632	})
633}
634
635func BenchmarkStackGrowth(b *testing.B) {
636	benchmarkStackGrowth(b, 10)
637}
638
639func BenchmarkStackGrowthDeep(b *testing.B) {
640	benchmarkStackGrowth(b, 1024)
641}
642
643func BenchmarkCreateGoroutines(b *testing.B) {
644	benchmarkCreateGoroutines(b, 1)
645}
646
647func BenchmarkCreateGoroutinesParallel(b *testing.B) {
648	benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
649}
650
651func benchmarkCreateGoroutines(b *testing.B, procs int) {
652	c := make(chan bool)
653	var f func(n int)
654	f = func(n int) {
655		if n == 0 {
656			c <- true
657			return
658		}
659		go f(n - 1)
660	}
661	for i := 0; i < procs; i++ {
662		go f(b.N / procs)
663	}
664	for i := 0; i < procs; i++ {
665		<-c
666	}
667}
668
669func BenchmarkCreateGoroutinesCapture(b *testing.B) {
670	b.ReportAllocs()
671	for i := 0; i < b.N; i++ {
672		const N = 4
673		var wg sync.WaitGroup
674		wg.Add(N)
675		for i := 0; i < N; i++ {
676			i := i
677			go func() {
678				if i >= N {
679					b.Logf("bad") // just to capture b
680				}
681				wg.Done()
682			}()
683		}
684		wg.Wait()
685	}
686}
687
688func BenchmarkClosureCall(b *testing.B) {
689	sum := 0
690	off1 := 1
691	for i := 0; i < b.N; i++ {
692		off2 := 2
693		func() {
694			sum += i + off1 + off2
695		}()
696	}
697	_ = sum
698}
699
700func benchmarkWakeupParallel(b *testing.B, spin func(time.Duration)) {
701	if runtime.GOMAXPROCS(0) == 1 {
702		b.Skip("skipping: GOMAXPROCS=1")
703	}
704
705	wakeDelay := 5 * time.Microsecond
706	for _, delay := range []time.Duration{
707		0,
708		1 * time.Microsecond,
709		2 * time.Microsecond,
710		5 * time.Microsecond,
711		10 * time.Microsecond,
712		20 * time.Microsecond,
713		50 * time.Microsecond,
714		100 * time.Microsecond,
715	} {
716		b.Run(delay.String(), func(b *testing.B) {
717			if b.N == 0 {
718				return
719			}
720			// Start two goroutines, which alternate between being
721			// sender and receiver in the following protocol:
722			//
723			// - The receiver spins for `delay` and then does a
724			// blocking receive on a channel.
725			//
726			// - The sender spins for `delay+wakeDelay` and then
727			// sends to the same channel. (The addition of
728			// `wakeDelay` improves the probability that the
729			// receiver will be blocking when the send occurs when
730			// the goroutines execute in parallel.)
731			//
732			// In each iteration of the benchmark, each goroutine
733			// acts once as sender and once as receiver, so each
734			// goroutine spins for delay twice.
735			//
736			// BenchmarkWakeupParallel is used to estimate how
737			// efficiently the scheduler parallelizes goroutines in
738			// the presence of blocking:
739			//
740			// - If both goroutines are executed on the same core,
741			// an increase in delay by N will increase the time per
742			// iteration by 4*N, because all 4 delays are
743			// serialized.
744			//
745			// - Otherwise, an increase in delay by N will increase
746			// the time per iteration by 2*N, and the time per
747			// iteration is 2 * (runtime overhead + chan
748			// send/receive pair + delay + wakeDelay). This allows
749			// the runtime overhead, including the time it takes
750			// for the unblocked goroutine to be scheduled, to be
751			// estimated.
752			ping, pong := make(chan struct{}), make(chan struct{})
753			start := make(chan struct{})
754			done := make(chan struct{})
755			go func() {
756				<-start
757				for i := 0; i < b.N; i++ {
758					// sender
759					spin(delay + wakeDelay)
760					ping <- struct{}{}
761					// receiver
762					spin(delay)
763					<-pong
764				}
765				done <- struct{}{}
766			}()
767			go func() {
768				for i := 0; i < b.N; i++ {
769					// receiver
770					spin(delay)
771					<-ping
772					// sender
773					spin(delay + wakeDelay)
774					pong <- struct{}{}
775				}
776				done <- struct{}{}
777			}()
778			b.ResetTimer()
779			start <- struct{}{}
780			<-done
781			<-done
782		})
783	}
784}
785
786func BenchmarkWakeupParallelSpinning(b *testing.B) {
787	benchmarkWakeupParallel(b, func(d time.Duration) {
788		end := time.Now().Add(d)
789		for time.Now().Before(end) {
790			// do nothing
791		}
792	})
793}
794
795// sysNanosleep is defined by OS-specific files (such as runtime_linux_test.go)
796// to sleep for the given duration. If nil, dependent tests are skipped.
797// The implementation should invoke a blocking system call and not
798// call time.Sleep, which would deschedule the goroutine.
799var sysNanosleep func(d time.Duration)
800
801func BenchmarkWakeupParallelSyscall(b *testing.B) {
802	if sysNanosleep == nil {
803		b.Skipf("skipping on %v; sysNanosleep not defined", runtime.GOOS)
804	}
805	benchmarkWakeupParallel(b, func(d time.Duration) {
806		sysNanosleep(d)
807	})
808}
809
810type Matrix [][]float64
811
812func BenchmarkMatmult(b *testing.B) {
813	b.StopTimer()
814	// matmult is O(N**3) but testing expects O(b.N),
815	// so we need to take cube root of b.N
816	n := int(math.Cbrt(float64(b.N))) + 1
817	A := makeMatrix(n)
818	B := makeMatrix(n)
819	C := makeMatrix(n)
820	b.StartTimer()
821	matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
822}
823
824func makeMatrix(n int) Matrix {
825	m := make(Matrix, n)
826	for i := 0; i < n; i++ {
827		m[i] = make([]float64, n)
828		for j := 0; j < n; j++ {
829			m[i][j] = float64(i*n + j)
830		}
831	}
832	return m
833}
834
835func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
836	di := i1 - i0
837	dj := j1 - j0
838	dk := k1 - k0
839	if di >= dj && di >= dk && di >= threshold {
840		// divide in two by y axis
841		mi := i0 + di/2
842		done1 := make(chan struct{}, 1)
843		go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
844		matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
845		<-done1
846	} else if dj >= dk && dj >= threshold {
847		// divide in two by x axis
848		mj := j0 + dj/2
849		done1 := make(chan struct{}, 1)
850		go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
851		matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
852		<-done1
853	} else if dk >= threshold {
854		// divide in two by "k" axis
855		// deliberately not parallel because of data races
856		mk := k0 + dk/2
857		matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
858		matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
859	} else {
860		// the matrices are small enough, compute directly
861		for i := i0; i < i1; i++ {
862			for j := j0; j < j1; j++ {
863				for k := k0; k < k1; k++ {
864					C[i][j] += A[i][k] * B[k][j]
865				}
866			}
867		}
868	}
869	if done != nil {
870		done <- struct{}{}
871	}
872}
873
874func TestStealOrder(t *testing.T) {
875	runtime.RunStealOrderTest()
876}
877
878func TestLockOSThreadNesting(t *testing.T) {
879	if runtime.GOARCH == "wasm" {
880		t.Skip("no threads on wasm yet")
881	}
882
883	go func() {
884		e, i := runtime.LockOSCounts()
885		if e != 0 || i != 0 {
886			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
887			return
888		}
889		runtime.LockOSThread()
890		runtime.LockOSThread()
891		runtime.UnlockOSThread()
892		e, i = runtime.LockOSCounts()
893		if e != 1 || i != 0 {
894			t.Errorf("want locked counts 1, 0; got %d, %d", e, i)
895			return
896		}
897		runtime.UnlockOSThread()
898		e, i = runtime.LockOSCounts()
899		if e != 0 || i != 0 {
900			t.Errorf("want locked counts 0, 0; got %d, %d", e, i)
901			return
902		}
903	}()
904}
905
906func TestLockOSThreadExit(t *testing.T) {
907	testLockOSThreadExit(t, "testprog")
908}
909
910func testLockOSThreadExit(t *testing.T, prog string) {
911	output := runTestProg(t, prog, "LockOSThreadMain", "GOMAXPROCS=1")
912	want := "OK\n"
913	if output != want {
914		t.Errorf("want %q, got %q", want, output)
915	}
916
917	output = runTestProg(t, prog, "LockOSThreadAlt")
918	if output != want {
919		t.Errorf("want %q, got %q", want, output)
920	}
921}
922
923func TestLockOSThreadAvoidsStatePropagation(t *testing.T) {
924	want := "OK\n"
925	skip := "unshare not permitted\n"
926	output := runTestProg(t, "testprog", "LockOSThreadAvoidsStatePropagation", "GOMAXPROCS=1")
927	if output == skip {
928		t.Skip("unshare syscall not permitted on this system")
929	} else if output != want {
930		t.Errorf("want %q, got %q", want, output)
931	}
932}
933
934func TestLockOSThreadTemplateThreadRace(t *testing.T) {
935	testenv.MustHaveGoRun(t)
936
937	exe, err := buildTestProg(t, "testprog")
938	if err != nil {
939		t.Fatal(err)
940	}
941
942	iterations := 100
943	if testing.Short() {
944		// Reduce run time to ~100ms, with much lower probability of
945		// catching issues.
946		iterations = 5
947	}
948	for i := 0; i < iterations; i++ {
949		want := "OK\n"
950		output := runBuiltTestProg(t, exe, "LockOSThreadTemplateThreadRace")
951		if output != want {
952			t.Fatalf("run %d: want %q, got %q", i, want, output)
953		}
954	}
955}
956
957// fakeSyscall emulates a system call.
958//go:nosplit
959func fakeSyscall(duration time.Duration) {
960	runtime.Entersyscall()
961	for start := runtime.Nanotime(); runtime.Nanotime()-start < int64(duration); {
962	}
963	runtime.Exitsyscall()
964}
965
966// Check that a goroutine will be preempted if it is calling short system calls.
967func testPreemptionAfterSyscall(t *testing.T, syscallDuration time.Duration) {
968	if runtime.GOARCH == "wasm" {
969		t.Skip("no preemption on wasm yet")
970	}
971
972	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
973
974	interations := 10
975	if testing.Short() {
976		interations = 1
977	}
978	const (
979		maxDuration = 3 * time.Second
980		nroutines   = 8
981	)
982
983	for i := 0; i < interations; i++ {
984		c := make(chan bool, nroutines)
985		stop := uint32(0)
986
987		start := time.Now()
988		for g := 0; g < nroutines; g++ {
989			go func(stop *uint32) {
990				c <- true
991				for atomic.LoadUint32(stop) == 0 {
992					fakeSyscall(syscallDuration)
993				}
994				c <- true
995			}(&stop)
996		}
997		// wait until all goroutines have started.
998		for g := 0; g < nroutines; g++ {
999			<-c
1000		}
1001		atomic.StoreUint32(&stop, 1)
1002		// wait until all goroutines have finished.
1003		for g := 0; g < nroutines; g++ {
1004			<-c
1005		}
1006		duration := time.Since(start)
1007
1008		if duration > maxDuration {
1009			t.Errorf("timeout exceeded: %v (%v)", duration, maxDuration)
1010		}
1011	}
1012}
1013
1014func TestPreemptionAfterSyscall(t *testing.T) {
1015	for _, i := range []time.Duration{10, 100, 1000} {
1016		d := i * time.Microsecond
1017		t.Run(fmt.Sprint(d), func(t *testing.T) {
1018			testPreemptionAfterSyscall(t, d)
1019		})
1020	}
1021}
1022
1023func TestGetgThreadSwitch(t *testing.T) {
1024	runtime.RunGetgThreadSwitchTest()
1025}
1026
1027// TestNetpollBreak tests that netpollBreak can break a netpoll.
1028// This test is not particularly safe since the call to netpoll
1029// will pick up any stray files that are ready, but it should work
1030// OK as long it is not run in parallel.
1031func TestNetpollBreak(t *testing.T) {
1032	if runtime.GOMAXPROCS(0) == 1 {
1033		t.Skip("skipping: GOMAXPROCS=1")
1034	}
1035
1036	// Make sure that netpoll is initialized.
1037	runtime.NetpollGenericInit()
1038
1039	start := time.Now()
1040	c := make(chan bool, 2)
1041	go func() {
1042		c <- true
1043		runtime.Netpoll(10 * time.Second.Nanoseconds())
1044		c <- true
1045	}()
1046	<-c
1047	// Loop because the break might get eaten by the scheduler.
1048	// Break twice to break both the netpoll we started and the
1049	// scheduler netpoll.
1050loop:
1051	for {
1052		runtime.Usleep(100)
1053		runtime.NetpollBreak()
1054		runtime.NetpollBreak()
1055		select {
1056		case <-c:
1057			break loop
1058		default:
1059		}
1060	}
1061	if dur := time.Since(start); dur > 5*time.Second {
1062		t.Errorf("netpollBreak did not interrupt netpoll: slept for: %v", dur)
1063	}
1064}
1065