github.com/rafaeltorres324/go/src@v0.0.0-20210519164414-9fdf653a9838/os/signal/signal_test.go (about)

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