]> Cypherpunks.ru repositories - gostls13.git/blob - src/os/signal/signal_test.go
os/signal: skip nohup tests on darwin builders
[gostls13.git] / src / os / signal / signal_test.go
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
7 package signal
8
9 import (
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.
32 var 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.
37 var fatalWaitingTime = 30 * time.Second
38
39 func 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
66 func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
67         t.Helper()
68         waitSig1(t, c, sig, false)
69 }
70 func waitSigAll(t *testing.T, c <-chan os.Signal, sig os.Signal) {
71         t.Helper()
72         waitSig1(t, c, sig, true)
73 }
74
75 func 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.
106 func 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.
120 func 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
159 func 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
197 func 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.
260 func TestReset(t *testing.T) {
261         testCancel(t, false)
262 }
263
264 // Test that Ignore cancels registration for listed signals on all channels.
265 func TestIgnore(t *testing.T) {
266         testCancel(t, true)
267 }
268
269 // Test that Ignored correctly detects changes to the ignored status of a signal.
270 func 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
290 var 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.
293 func 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
336 var (
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.
342 func 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.
418 func 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).
529 func 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).
538 func 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.
602 func 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
657 func 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
708 var (
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
713 func 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
779 func 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         select {
801         case <-c.Done():
802                 if got := c.Err(); got != context.Canceled {
803                         t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
804                 }
805         case <-time.After(time.Second):
806                 t.Errorf("timed out waiting for context to be done after calling stop")
807         }
808 }
809
810 func TestNotifyContextCancelParent(t *testing.T) {
811         parent, cancelParent := context.WithCancel(context.Background())
812         defer cancelParent()
813         c, stop := NotifyContext(parent, syscall.SIGINT)
814         defer stop()
815
816         if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
817                 t.Errorf("c.String() = %q, want %q", got, want)
818         }
819
820         cancelParent()
821         select {
822         case <-c.Done():
823                 if got := c.Err(); got != context.Canceled {
824                         t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
825                 }
826         case <-time.After(time.Second):
827                 t.Errorf("timed out waiting for parent context to be canceled")
828         }
829 }
830
831 func TestNotifyContextPrematureCancelParent(t *testing.T) {
832         parent, cancelParent := context.WithCancel(context.Background())
833         defer cancelParent()
834
835         cancelParent() // Prematurely cancel context before calling NotifyContext.
836         c, stop := NotifyContext(parent, syscall.SIGINT)
837         defer stop()
838
839         if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
840                 t.Errorf("c.String() = %q, want %q", got, want)
841         }
842
843         select {
844         case <-c.Done():
845                 if got := c.Err(); got != context.Canceled {
846                         t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
847                 }
848         case <-time.After(time.Second):
849                 t.Errorf("timed out waiting for parent context to be canceled")
850         }
851 }
852
853 func TestNotifyContextSimultaneousStop(t *testing.T) {
854         c, stop := NotifyContext(context.Background(), syscall.SIGINT)
855         defer stop()
856
857         if want, got := "signal.NotifyContext(context.Background, [interrupt])", fmt.Sprint(c); want != got {
858                 t.Errorf("c.String() = %q, want %q", got, want)
859         }
860
861         var wg sync.WaitGroup
862         n := 10
863         wg.Add(n)
864         for i := 0; i < n; i++ {
865                 go func() {
866                         stop()
867                         wg.Done()
868                 }()
869         }
870         wg.Wait()
871         select {
872         case <-c.Done():
873                 if got := c.Err(); got != context.Canceled {
874                         t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
875                 }
876         case <-time.After(time.Second):
877                 t.Errorf("expected context to be canceled")
878         }
879 }
880
881 func TestNotifyContextStringer(t *testing.T) {
882         parent, cancelParent := context.WithCancel(context.Background())
883         defer cancelParent()
884         c, stop := NotifyContext(parent, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
885         defer stop()
886
887         want := `signal.NotifyContext(context.Background.WithCancel, [hangup interrupt terminated])`
888         if got := fmt.Sprint(c); got != want {
889                 t.Errorf("c.String() = %q, want %q", got, want)
890         }
891 }
892
893 // #44193 test signal handling while stopping and starting the world.
894 func TestSignalTrace(t *testing.T) {
895         done := make(chan struct{})
896         quit := make(chan struct{})
897         c := make(chan os.Signal, 1)
898         Notify(c, syscall.SIGHUP)
899
900         // Source and sink for signals busy loop unsynchronized with
901         // trace starts and stops. We are ultimately validating that
902         // signals and runtime.(stop|start)TheWorldGC are compatible.
903         go func() {
904                 defer close(done)
905                 defer Stop(c)
906                 pid := syscall.Getpid()
907                 for {
908                         select {
909                         case <-quit:
910                                 return
911                         default:
912                                 syscall.Kill(pid, syscall.SIGHUP)
913                         }
914                         waitSig(t, c, syscall.SIGHUP)
915                 }
916         }()
917
918         for i := 0; i < 100; i++ {
919                 buf := new(bytes.Buffer)
920                 if err := trace.Start(buf); err != nil {
921                         t.Fatalf("[%d] failed to start tracing: %v", i, err)
922                 }
923                 time.After(1 * time.Microsecond)
924                 trace.Stop()
925                 size := buf.Len()
926                 if size == 0 {
927                         t.Fatalf("[%d] trace is empty", i)
928                 }
929         }
930         close(quit)
931         <-done
932 }