...

Source file src/os/signal/signal_test.go

Documentation: os/signal

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

View as plain text