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