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