1// Copyright 2009 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
5//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
6
7package signal
8
9import (
10	"bytes"
11	"context"
12	"flag"
13	"fmt"
14	"internal/testenv"
15	"os"
16	"os/exec"
17	"runtime"
18	"runtime/trace"
19	"strconv"
20	"strings"
21	"sync"
22	"syscall"
23	"testing"
24	"time"
25)
26
27// settleTime is an upper bound on how long we expect signals to take to be
28// delivered. Lower values make the test faster, but also flakier — especially
29// on heavily loaded systems.
30//
31// The current value is set based on flakes observed in the Go builders.
32var settleTime = 100 * time.Millisecond
33
34// fatalWaitingTime is an absurdly long time to wait for signals to be
35// delivered but, using it, we (hopefully) eliminate test flakes on the
36// build servers. See #46736 for discussion.
37var fatalWaitingTime = 30 * time.Second
38
39func init() {
40	if testenv.Builder() == "solaris-amd64-oraclerel" {
41		// The solaris-amd64-oraclerel builder has been observed to time out in
42		// TestNohup even with a 250ms settle time.
43		//
44		// Use a much longer settle time on that builder to try to suss out whether
45		// the test is flaky due to builder slowness (which may mean we need a
46		// longer GO_TEST_TIMEOUT_SCALE) or due to a dropped signal (which may
47		// instead need a test-skip and upstream bug filed against the Solaris
48		// kernel).
49		//
50		// This constant is chosen so as to make the test as generous as possible
51		// while still reliably completing within 3 minutes in non-short mode.
52		//
53		// See https://golang.org/issue/33174.
54		settleTime = 11 * time.Second
55	} else if runtime.GOOS == "linux" && strings.HasPrefix(runtime.GOARCH, "ppc64") {
56		// Older linux kernels seem to have some hiccups delivering the signal
57		// in a timely manner on ppc64 and ppc64le. When running on a
58		// ppc64le/ubuntu 16.04/linux 4.4 host the time can vary quite
59		// substantially even on a idle system. 5 seconds is twice any value
60		// observed when running 10000 tests on such a system.
61		settleTime = 5 * time.Second
62	} else if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
63		if scale, err := strconv.Atoi(s); err == nil {
64			settleTime *= time.Duration(scale)
65		}
66	}
67}
68
69func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
70	t.Helper()
71	waitSig1(t, c, sig, false)
72}
73func waitSigAll(t *testing.T, c <-chan os.Signal, sig os.Signal) {
74	t.Helper()
75	waitSig1(t, c, sig, true)
76}
77
78func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) {
79	t.Helper()
80
81	// Sleep multiple times to give the kernel more tries to
82	// deliver the signal.
83	start := time.Now()
84	timer := time.NewTimer(settleTime / 10)
85	defer timer.Stop()
86	// If the caller notified for all signals on c, filter out SIGURG,
87	// which is used for runtime preemption and can come at unpredictable times.
88	// General user code should filter out all unexpected signals instead of just
89	// SIGURG, but since os/signal is tightly coupled to the runtime it seems
90	// appropriate to be stricter here.
91	for time.Since(start) < fatalWaitingTime {
92		select {
93		case s := <-c:
94			if s == sig {
95				return
96			}
97			if !all || s != syscall.SIGURG {
98				t.Fatalf("signal was %v, want %v", s, sig)
99			}
100		case <-timer.C:
101			timer.Reset(settleTime / 10)
102		}
103	}
104	t.Fatalf("timeout after %v waiting for %v", fatalWaitingTime, sig)
105}
106
107// quiesce waits until we can be reasonably confident that all pending signals
108// have been delivered by the OS.
109func quiesce() {
110	// The kernel will deliver a signal as a thread returns
111	// from a syscall. If the only active thread is sleeping,
112	// and the system is busy, the kernel may not get around
113	// to waking up a thread to catch the signal.
114	// We try splitting up the sleep to give the kernel
115	// many chances to deliver the signal.
116	start := time.Now()
117	for time.Since(start) < settleTime {
118		time.Sleep(settleTime / 10)
119	}
120}
121
122// Test that basic signal handling works.
123func TestSignal(t *testing.T) {
124	// Ask for SIGHUP
125	c := make(chan os.Signal, 1)
126	Notify(c, syscall.SIGHUP)
127	defer Stop(c)
128
129	// Send this process a SIGHUP
130	t.Logf("sighup...")
131	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
132	waitSig(t, c, syscall.SIGHUP)
133
134	// Ask for everything we can get. The buffer size has to be
135	// more than 1, since the runtime might send SIGURG signals.
136	// Using 10 is arbitrary.
137	c1 := make(chan os.Signal, 10)
138	Notify(c1)
139	// Stop relaying the SIGURG signals. See #49724
140	Reset(syscall.SIGURG)
141	defer Stop(c1)
142
143	// Send this process a SIGWINCH
144	t.Logf("sigwinch...")
145	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
146	waitSigAll(t, c1, syscall.SIGWINCH)
147
148	// Send two more SIGHUPs, to make sure that
149	// they get delivered on c1 and that not reading
150	// from c does not block everything.
151	t.Logf("sighup...")
152	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
153	waitSigAll(t, c1, syscall.SIGHUP)
154	t.Logf("sighup...")
155	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
156	waitSigAll(t, c1, syscall.SIGHUP)
157
158	// The first SIGHUP should be waiting for us on c.
159	waitSig(t, c, syscall.SIGHUP)
160}
161
162func TestStress(t *testing.T) {
163	dur := 3 * time.Second
164	if testing.Short() {
165		dur = 100 * time.Millisecond
166	}
167	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
168
169	sig := make(chan os.Signal, 1)
170	Notify(sig, syscall.SIGUSR1)
171
172	go func() {
173		stop := time.After(dur)
174		for {
175			select {
176			case <-stop:
177				// Allow enough time for all signals to be delivered before we stop
178				// listening for them.
179				quiesce()
180				Stop(sig)
181				// According to its documentation, “[w]hen Stop returns, it in
182				// guaranteed that c will receive no more signals.” So we can safely
183				// close sig here: if there is a send-after-close race here, that is a
184				// bug in Stop and we would like to detect it.
185				close(sig)
186				return
187
188			default:
189				syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
190				runtime.Gosched()
191			}
192		}
193	}()
194
195	for range sig {
196		// Receive signals until the sender closes sig.
197	}
198}
199
200func testCancel(t *testing.T, ignore bool) {
201	// Ask to be notified on c1 when a SIGWINCH is received.
202	c1 := make(chan os.Signal, 1)
203	Notify(c1, syscall.SIGWINCH)
204	defer Stop(c1)
205
206	// Ask to be notified on c2 when a SIGHUP is received.
207	c2 := make(chan os.Signal, 1)
208	Notify(c2, syscall.SIGHUP)
209	defer Stop(c2)
210
211	// Send this process a SIGWINCH and wait for notification on c1.
212	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
213	waitSig(t, c1, syscall.SIGWINCH)
214
215	// Send this process a SIGHUP and wait for notification on c2.
216	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
217	waitSig(t, c2, syscall.SIGHUP)
218
219	// Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP.
220	// Either way, this should undo both calls to Notify above.
221	if ignore {
222		Ignore(syscall.SIGWINCH, syscall.SIGHUP)
223		// Don't bother deferring a call to Reset: it is documented to undo Notify,
224		// but its documentation says nothing about Ignore, and (as of the time of
225		// writing) it empirically does not undo an Ignore.
226	} else {
227		Reset(syscall.SIGWINCH, syscall.SIGHUP)
228	}
229
230	// Send this process a SIGWINCH. It should be ignored.
231	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
232
233	// If ignoring, Send this process a SIGHUP. It should be ignored.
234	if ignore {
235		syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
236	}
237
238	quiesce()
239
240	select {
241	case s := <-c1:
242		t.Errorf("unexpected signal %v", s)
243	default:
244		// nothing to read - good
245	}
246
247	select {
248	case s := <-c2:
249		t.Errorf("unexpected signal %v", s)
250	default:
251		// nothing to read - good
252	}
253
254	// One or both of the signals may have been blocked for this process
255	// by the calling process.
256	// Discard any queued signals now to avoid interfering with other tests.
257	Notify(c1, syscall.SIGWINCH)
258	Notify(c2, syscall.SIGHUP)
259	quiesce()
260}
261
262// Test that Reset cancels registration for listed signals on all channels.
263func TestReset(t *testing.T) {
264	testCancel(t, false)
265}
266
267// Test that Ignore cancels registration for listed signals on all channels.
268func TestIgnore(t *testing.T) {
269	testCancel(t, true)
270}
271
272// Test that Ignored correctly detects changes to the ignored status of a signal.
273func TestIgnored(t *testing.T) {
274	// Ask to be notified on SIGWINCH.
275	c := make(chan os.Signal, 1)
276	Notify(c, syscall.SIGWINCH)
277
278	// If we're being notified, then the signal should not be ignored.
279	if Ignored(syscall.SIGWINCH) {
280		t.Errorf("expected SIGWINCH to not be ignored.")
281	}
282	Stop(c)
283	Ignore(syscall.SIGWINCH)
284
285	// We're no longer paying attention to this signal.
286	if !Ignored(syscall.SIGWINCH) {
287		t.Errorf("expected SIGWINCH to be ignored when explicitly ignoring it.")
288	}
289
290	Reset()
291}
292
293var checkSighupIgnored = flag.Bool("check_sighup_ignored", false, "if true, TestDetectNohup will fail if SIGHUP is not ignored.")
294
295// Test that Ignored(SIGHUP) correctly detects whether it is being run under nohup.
296func TestDetectNohup(t *testing.T) {
297	if *checkSighupIgnored {
298		if !Ignored(syscall.SIGHUP) {
299			t.Fatal("SIGHUP is not ignored.")
300		} else {
301			t.Log("SIGHUP is ignored.")
302		}
303	} else {
304		defer Reset()
305		// Ugly: ask for SIGHUP so that child will not have no-hup set
306		// even if test is running under nohup environment.
307		// We have no intention of reading from c.
308		c := make(chan os.Signal, 1)
309		Notify(c, syscall.SIGHUP)
310		if out, err := exec.Command(os.Args[0], "-test.run=TestDetectNohup", "-check_sighup_ignored").CombinedOutput(); err == nil {
311			t.Errorf("ran test with -check_sighup_ignored and it succeeded: expected failure.\nOutput:\n%s", out)
312		}
313		Stop(c)
314		// Again, this time with nohup, assuming we can find it.
315		_, err := os.Stat("/usr/bin/nohup")
316		if err != nil {
317			t.Skip("cannot find nohup; skipping second half of test")
318		}
319		Ignore(syscall.SIGHUP)
320		os.Remove("nohup.out")
321		out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestDetectNohup", "-check_sighup_ignored").CombinedOutput()
322
323		data, _ := os.ReadFile("nohup.out")
324		os.Remove("nohup.out")
325		if err != nil {
326			t.Errorf("ran test with -check_sighup_ignored under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", err, out, data)
327		}
328	}
329}
330
331var (
332	sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
333	dieFromSighup      = flag.Bool("die_from_sighup", false, "wait to die from uncaught SIGHUP")
334)
335
336// Test that Stop cancels the channel's registrations.
337func TestStop(t *testing.T) {
338	sigs := []syscall.Signal{
339		syscall.SIGWINCH,
340		syscall.SIGHUP,
341		syscall.SIGUSR1,
342	}
343
344	for _, sig := range sigs {
345		sig := sig
346		t.Run(fmt.Sprint(sig), func(t *testing.T) {
347			// When calling Notify with a specific signal,
348			// independent signals should not interfere with each other,
349			// and we end up needing to wait for signals to quiesce a lot.
350			// Test the three different signals concurrently.
351			t.Parallel()
352
353			// If the signal is not ignored, send the signal before registering a
354			// channel to verify the behavior of the default Go handler.
355			// If it's SIGWINCH or SIGUSR1 we should not see it.
356			// If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
357			mayHaveBlockedSignal := false
358			if !Ignored(sig) && (sig != syscall.SIGHUP || *sendUncaughtSighup == 1) {
359				syscall.Kill(syscall.Getpid(), sig)
360				quiesce()
361
362				// We don't know whether sig is blocked for this process; see
363				// https://golang.org/issue/38165. Assume that it could be.
364				mayHaveBlockedSignal = true
365			}
366
367			// Ask for signal
368			c := make(chan os.Signal, 1)
369			Notify(c, sig)
370
371			// Send this process the signal again.
372			syscall.Kill(syscall.Getpid(), sig)
373			waitSig(t, c, sig)
374
375			if mayHaveBlockedSignal {
376				// We may have received a queued initial signal in addition to the one
377				// that we sent after Notify. If so, waitSig may have observed that
378				// initial signal instead of the second one, and we may need to wait for
379				// the second signal to clear. Do that now.
380				quiesce()
381				select {
382				case <-c:
383				default:
384				}
385			}
386
387			// Stop watching for the signal and send it again.
388			// If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
389			Stop(c)
390			if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 {
391				syscall.Kill(syscall.Getpid(), sig)
392				quiesce()
393
394				select {
395				case s := <-c:
396					t.Errorf("unexpected signal %v", s)
397				default:
398					// nothing to read - good
399				}
400
401				// If we're going to receive a signal, it has almost certainly been
402				// received by now. However, it may have been blocked for this process —
403				// we don't know. Explicitly unblock it and wait for it to clear now.
404				Notify(c, sig)
405				quiesce()
406				Stop(c)
407			}
408		})
409	}
410}
411
412// Test that when run under nohup, an uncaught SIGHUP does not kill the program.
413func TestNohup(t *testing.T) {
414	// Ugly: ask for SIGHUP so that child will not have no-hup set
415	// even if test is running under nohup environment.
416	// We have no intention of reading from c.
417	c := make(chan os.Signal, 1)
418	Notify(c, syscall.SIGHUP)
419
420	// When run without nohup, the test should crash on an uncaught SIGHUP.
421	// When run under nohup, the test should ignore uncaught SIGHUPs,
422	// because the runtime is not supposed to be listening for them.
423	// Either way, TestStop should still be able to catch them when it wants them
424	// and then when it stops wanting them, the original behavior should resume.
425	//
426	// send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs.
427	// send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs.
428	//
429	// Both should fail without nohup and succeed with nohup.
430
431	var subTimeout time.Duration
432
433	var wg sync.WaitGroup
434	wg.Add(2)
435	if deadline, ok := t.Deadline(); ok {
436		subTimeout = time.Until(deadline)
437		subTimeout -= subTimeout / 10 // Leave 10% headroom for propagating output.
438	}
439	for i := 1; i <= 2; i++ {
440		i := i
441		go t.Run(fmt.Sprintf("uncaught-%d", i), func(t *testing.T) {
442			defer wg.Done()
443
444			args := []string{
445				"-test.v",
446				"-test.run=TestStop",
447				"-send_uncaught_sighup=" + strconv.Itoa(i),
448				"-die_from_sighup",
449			}
450			if subTimeout != 0 {
451				args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout))
452			}
453			out, err := exec.Command(os.Args[0], args...).CombinedOutput()
454
455			if err == nil {
456				t.Errorf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out)
457			} else {
458				t.Logf("test with -send_uncaught_sighup=%d failed as expected.\nError: %v\nOutput:\n%s", i, err, out)
459			}
460		})
461	}
462	wg.Wait()
463
464	Stop(c)
465
466	// Skip the nohup test below when running in tmux on darwin, since nohup
467	// doesn't work correctly there. See issue #5135.
468	if runtime.GOOS == "darwin" && os.Getenv("TMUX") != "" {
469		t.Skip("Skipping nohup test due to running in tmux on darwin")
470	}
471
472	// Again, this time with nohup, assuming we can find it.
473	_, err := exec.LookPath("nohup")
474	if err != nil {
475		t.Skip("cannot find nohup; skipping second half of test")
476	}
477
478	wg.Add(2)
479	if deadline, ok := t.Deadline(); ok {
480		subTimeout = time.Until(deadline)
481		subTimeout -= subTimeout / 10 // Leave 10% headroom for propagating output.
482	}
483	for i := 1; i <= 2; i++ {
484		i := i
485		go t.Run(fmt.Sprintf("nohup-%d", i), func(t *testing.T) {
486			defer wg.Done()
487
488			// POSIX specifies that nohup writes to a file named nohup.out if standard
489			// output is a terminal. However, for an exec.Command, standard output is
490			// not a terminal — so we don't need to read or remove that file (and,
491			// indeed, cannot even create it if the current user is unable to write to
492			// GOROOT/src, such as when GOROOT is installed and owned by root).
493
494			args := []string{
495				os.Args[0],
496				"-test.v",
497				"-test.run=TestStop",
498				"-send_uncaught_sighup=" + strconv.Itoa(i),
499			}
500			if subTimeout != 0 {
501				args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout))
502			}
503			out, err := exec.Command("nohup", args...).CombinedOutput()
504
505			if err != nil {
506				t.Errorf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s", i, err, out)
507			} else {
508				t.Logf("ran test with -send_uncaught_sighup=%d under nohup.\nOutput:\n%s", i, out)
509			}
510		})
511	}
512	wg.Wait()
513}
514
515// Test that SIGCONT works (issue 8953).
516func TestSIGCONT(t *testing.T) {
517	c := make(chan os.Signal, 1)
518	Notify(c, syscall.SIGCONT)
519	defer Stop(c)
520	syscall.Kill(syscall.Getpid(), syscall.SIGCONT)
521	waitSig(t, c, syscall.SIGCONT)
522}
523
524// Test race between stopping and receiving a signal (issue 14571).
525func TestAtomicStop(t *testing.T) {
526	if os.Getenv("GO_TEST_ATOMIC_STOP") != "" {
527		atomicStopTestProgram(t)
528		t.Fatal("atomicStopTestProgram returned")
529	}
530
531	testenv.MustHaveExec(t)
532
533	// Call Notify for SIGINT before starting the child process.
534	// That ensures that SIGINT is not ignored for the child.
535	// This is necessary because if SIGINT is ignored when a
536	// Go program starts, then it remains ignored, and closing
537	// the last notification channel for SIGINT will switch it
538	// back to being ignored. In that case the assumption of
539	// atomicStopTestProgram, that it will either die from SIGINT
540	// or have it be reported, breaks down, as there is a third
541	// option: SIGINT might be ignored.
542	cs := make(chan os.Signal, 1)
543	Notify(cs, syscall.SIGINT)
544	defer Stop(cs)
545
546	const execs = 10
547	for i := 0; i < execs; i++ {
548		timeout := "0"
549		if deadline, ok := t.Deadline(); ok {
550			timeout = time.Until(deadline).String()
551		}
552		cmd := exec.Command(os.Args[0], "-test.run=TestAtomicStop", "-test.timeout="+timeout)
553		cmd.Env = append(os.Environ(), "GO_TEST_ATOMIC_STOP=1")
554		out, err := cmd.CombinedOutput()
555		if err == nil {
556			if len(out) > 0 {
557				t.Logf("iteration %d: output %s", i, out)
558			}
559		} else {
560			t.Logf("iteration %d: exit status %q: output: %s", i, err, out)
561		}
562
563		lost := bytes.Contains(out, []byte("lost signal"))
564		if lost {
565			t.Errorf("iteration %d: lost signal", i)
566		}
567
568		// The program should either die due to SIGINT,
569		// or exit with success without printing "lost signal".
570		if err == nil {
571			if len(out) > 0 && !lost {
572				t.Errorf("iteration %d: unexpected output", i)
573			}
574		} else {
575			if ee, ok := err.(*exec.ExitError); !ok {
576				t.Errorf("iteration %d: error (%v) has type %T; expected exec.ExitError", i, err, err)
577			} else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
578				t.Errorf("iteration %d: error.Sys (%v) has type %T; expected syscall.WaitStatus", i, ee.Sys(), ee.Sys())
579			} else if !ws.Signaled() || ws.Signal() != syscall.SIGINT {
580				t.Errorf("iteration %d: got exit status %v; expected SIGINT", i, ee)
581			}
582		}
583	}
584}
585
586// atomicStopTestProgram is run in a subprocess by TestAtomicStop.
587// It tries to trigger a signal delivery race. This function should
588// either catch a signal or die from it.
589func atomicStopTestProgram(t *testing.T) {
590	// This test won't work if SIGINT is ignored here.
591	if Ignored(syscall.SIGINT) {
592		fmt.Println("SIGINT is ignored")
593		os.Exit(1)
594	}
595
596	const tries = 10
597
598	timeout := 2 * time.Second
599	if deadline, ok := t.Deadline(); ok {
600		// Give each try an equal slice of the deadline, with one slice to spare for
601		// cleanup.
602		timeout = time.Until(deadline) / (tries + 1)
603	}
604
605	pid := syscall.Getpid()
606	printed := false
607	for i := 0; i < tries; i++ {
608		cs := make(chan os.Signal, 1)
609		Notify(cs, syscall.SIGINT)
610
611		var wg sync.WaitGroup
612		wg.Add(1)
613		go func() {
614			defer wg.Done()
615			Stop(cs)
616		}()
617
618		syscall.Kill(pid, syscall.SIGINT)
619
620		// At this point we should either die from SIGINT or
621		// get a notification on cs. If neither happens, we
622		// dropped the signal. It is given 2 seconds to
623		// deliver, as needed for gccgo on some loaded test systems.
624
625		select {
626		case <-cs:
627		case <-time.After(timeout):
628			if !printed {
629				fmt.Print("lost signal on tries:")
630				printed = true
631			}
632			fmt.Printf(" %d", i)
633		}
634
635		wg.Wait()
636	}
637	if printed {
638		fmt.Print("\n")
639	}
640
641	os.Exit(0)
642}
643
644func TestTime(t *testing.T) {
645	// Test that signal works fine when we are in a call to get time,
646	// which on some platforms is using VDSO. See issue #34391.
647	dur := 3 * time.Second
648	if testing.Short() {
649		dur = 100 * time.Millisecond
650	}
651	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
652
653	sig := make(chan os.Signal, 1)
654	Notify(sig, syscall.SIGUSR1)
655
656	stop := make(chan struct{})
657	go func() {
658		for {
659			select {
660			case <-stop:
661				// Allow enough time for all signals to be delivered before we stop
662				// listening for them.
663				quiesce()
664				Stop(sig)
665				// According to its documentation, “[w]hen Stop returns, it in
666				// guaranteed that c will receive no more signals.” So we can safely
667				// close sig here: if there is a send-after-close race, that is a bug in
668				// Stop and we would like to detect it.
669				close(sig)
670				return
671
672			default:
673				syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
674				runtime.Gosched()
675			}
676		}
677	}()
678
679	done := make(chan struct{})
680	go func() {
681		for range sig {
682			// Receive signals until the sender closes sig.
683		}
684		close(done)
685	}()
686
687	t0 := time.Now()
688	for t1 := t0; t1.Sub(t0) < dur; t1 = time.Now() {
689	} // hammering on getting time
690
691	close(stop)
692	<-done
693}
694
695var (
696	checkNotifyContext = flag.Bool("check_notify_ctx", false, "if true, TestNotifyContext will fail if SIGINT is not received.")
697	ctxNotifyTimes     = flag.Int("ctx_notify_times", 1, "number of times a SIGINT signal should be received")
698)
699
700func TestNotifyContextNotifications(t *testing.T) {
701	if *checkNotifyContext {
702		ctx, _ := NotifyContext(context.Background(), syscall.SIGINT)
703		// We want to make sure not to be calling Stop() internally on NotifyContext() when processing a received signal.
704		// Being able to wait for a number of received system signals allows us to do so.
705		var wg sync.WaitGroup
706		n := *ctxNotifyTimes
707		wg.Add(n)
708		for i := 0; i < n; i++ {
709			go func() {
710				syscall.Kill(syscall.Getpid(), syscall.SIGINT)
711				wg.Done()
712			}()
713		}
714		wg.Wait()
715		<-ctx.Done()
716		fmt.Print("received SIGINT")
717		// Sleep to give time to simultaneous signals to reach the process.
718		// These signals must be ignored given stop() is not called on this code.
719		// We want to guarantee a SIGINT doesn't cause a premature termination of the program.
720		time.Sleep(settleTime)
721		return
722	}
723
724	t.Parallel()
725	testCases := []struct {
726		name string
727		n    int // number of times a SIGINT should be notified.
728	}{
729		{"once", 1},
730		{"multiple", 10},
731	}
732	for _, tc := range testCases {
733		t.Run(tc.name, func(t *testing.T) {
734			var subTimeout time.Duration
735			if deadline, ok := t.Deadline(); ok {
736				subTimeout := time.Until(deadline)
737				subTimeout -= subTimeout / 10 // Leave 10% headroom for cleaning up subprocess.
738			}
739
740			args := []string{
741				"-test.v",
742				"-test.run=TestNotifyContextNotifications$",
743				"-check_notify_ctx",
744				fmt.Sprintf("-ctx_notify_times=%d", tc.n),
745			}
746			if subTimeout != 0 {
747				args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout))
748			}
749			out, err := exec.Command(os.Args[0], args...).CombinedOutput()
750			if err != nil {
751				t.Errorf("ran test with -check_notify_ctx_notification and it failed with %v.\nOutput:\n%s", err, out)
752			}
753			if want := []byte("received SIGINT"); !bytes.Contains(out, want) {
754				t.Errorf("got %q, wanted %q", out, want)
755			}
756		})
757	}
758}
759
760func TestNotifyContextStop(t *testing.T) {
761	Ignore(syscall.SIGHUP)
762	if !Ignored(syscall.SIGHUP) {
763		t.Errorf("expected SIGHUP to be ignored when explicitly ignoring it.")
764	}
765
766	parent, cancelParent := context.WithCancel(context.Background())
767	defer cancelParent()
768	c, stop := NotifyContext(parent, syscall.SIGHUP)
769	defer stop()
770
771	// If we're being notified, then the signal should not be ignored.
772	if Ignored(syscall.SIGHUP) {
773		t.Errorf("expected SIGHUP to not be ignored.")
774	}
775
776	if want, got := "signal.NotifyContext(context.Background.WithCancel, [hangup])", fmt.Sprint(c); want != got {
777		t.Errorf("c.String() = %q, wanted %q", got, want)
778	}
779
780	stop()
781	select {
782	case <-c.Done():
783		if got := c.Err(); got != context.Canceled {
784			t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
785		}
786	case <-time.After(time.Second):
787		t.Errorf("timed out waiting for context to be done after calling stop")
788	}
789}
790
791func TestNotifyContextCancelParent(t *testing.T) {
792	parent, cancelParent := context.WithCancel(context.Background())
793	defer cancelParent()
794	c, stop := NotifyContext(parent, syscall.SIGINT)
795	defer stop()
796
797	if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
798		t.Errorf("c.String() = %q, want %q", got, want)
799	}
800
801	cancelParent()
802	select {
803	case <-c.Done():
804		if got := c.Err(); got != context.Canceled {
805			t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
806		}
807	case <-time.After(time.Second):
808		t.Errorf("timed out waiting for parent context to be canceled")
809	}
810}
811
812func TestNotifyContextPrematureCancelParent(t *testing.T) {
813	parent, cancelParent := context.WithCancel(context.Background())
814	defer cancelParent()
815
816	cancelParent() // Prematurely cancel context before calling NotifyContext.
817	c, stop := NotifyContext(parent, syscall.SIGINT)
818	defer stop()
819
820	if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
821		t.Errorf("c.String() = %q, want %q", got, want)
822	}
823
824	select {
825	case <-c.Done():
826		if got := c.Err(); got != context.Canceled {
827			t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
828		}
829	case <-time.After(time.Second):
830		t.Errorf("timed out waiting for parent context to be canceled")
831	}
832}
833
834func TestNotifyContextSimultaneousStop(t *testing.T) {
835	c, stop := NotifyContext(context.Background(), syscall.SIGINT)
836	defer stop()
837
838	if want, got := "signal.NotifyContext(context.Background, [interrupt])", fmt.Sprint(c); want != got {
839		t.Errorf("c.String() = %q, want %q", got, want)
840	}
841
842	var wg sync.WaitGroup
843	n := 10
844	wg.Add(n)
845	for i := 0; i < n; i++ {
846		go func() {
847			stop()
848			wg.Done()
849		}()
850	}
851	wg.Wait()
852	select {
853	case <-c.Done():
854		if got := c.Err(); got != context.Canceled {
855			t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
856		}
857	case <-time.After(time.Second):
858		t.Errorf("expected context to be canceled")
859	}
860}
861
862func TestNotifyContextStringer(t *testing.T) {
863	parent, cancelParent := context.WithCancel(context.Background())
864	defer cancelParent()
865	c, stop := NotifyContext(parent, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
866	defer stop()
867
868	want := `signal.NotifyContext(context.Background.WithCancel, [hangup interrupt terminated])`
869	if got := fmt.Sprint(c); got != want {
870		t.Errorf("c.String() = %q, want %q", got, want)
871	}
872}
873
874// #44193 test signal handling while stopping and starting the world.
875func TestSignalTrace(t *testing.T) {
876	done := make(chan struct{})
877	quit := make(chan struct{})
878	c := make(chan os.Signal, 1)
879	Notify(c, syscall.SIGHUP)
880
881	// Source and sink for signals busy loop unsynchronized with
882	// trace starts and stops. We are ultimately validating that
883	// signals and runtime.(stop|start)TheWorldGC are compatible.
884	go func() {
885		defer close(done)
886		defer Stop(c)
887		pid := syscall.Getpid()
888		for {
889			select {
890			case <-quit:
891				return
892			default:
893				syscall.Kill(pid, syscall.SIGHUP)
894			}
895			waitSig(t, c, syscall.SIGHUP)
896		}
897	}()
898
899	for i := 0; i < 100; i++ {
900		buf := new(bytes.Buffer)
901		if err := trace.Start(buf); err != nil {
902			t.Fatalf("[%d] failed to start tracing: %v", i, err)
903		}
904		time.After(1 * time.Microsecond)
905		trace.Stop()
906		size := buf.Len()
907		if size == 0 {
908			t.Fatalf("[%d] trace is empty", i)
909		}
910	}
911	close(quit)
912	<-done
913}
914