github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/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 darwin dragonfly freebsd linux netbsd openbsd solaris 6 7 package signal 8 9 import ( 10 "flag" 11 "io/ioutil" 12 "os" 13 "os/exec" 14 "runtime" 15 "strconv" 16 "syscall" 17 "testing" 18 "time" 19 ) 20 21 func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) { 22 select { 23 case s := <-c: 24 if s != sig { 25 t.Fatalf("signal was %v, want %v", s, sig) 26 } 27 case <-time.After(1 * time.Second): 28 t.Fatalf("timeout waiting for %v", sig) 29 } 30 } 31 32 // Test that basic signal handling works. 33 func TestSignal(t *testing.T) { 34 // Ask for SIGHUP 35 c := make(chan os.Signal, 1) 36 Notify(c, syscall.SIGHUP) 37 defer Stop(c) 38 39 // Send this process a SIGHUP 40 t.Logf("sighup...") 41 syscall.Kill(syscall.Getpid(), syscall.SIGHUP) 42 waitSig(t, c, syscall.SIGHUP) 43 44 // Ask for everything we can get. 45 c1 := make(chan os.Signal, 1) 46 Notify(c1) 47 48 // Send this process a SIGWINCH 49 t.Logf("sigwinch...") 50 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) 51 waitSig(t, c1, syscall.SIGWINCH) 52 53 // Send two more SIGHUPs, to make sure that 54 // they get delivered on c1 and that not reading 55 // from c does not block everything. 56 t.Logf("sighup...") 57 syscall.Kill(syscall.Getpid(), syscall.SIGHUP) 58 waitSig(t, c1, syscall.SIGHUP) 59 t.Logf("sighup...") 60 syscall.Kill(syscall.Getpid(), syscall.SIGHUP) 61 waitSig(t, c1, syscall.SIGHUP) 62 63 // The first SIGHUP should be waiting for us on c. 64 waitSig(t, c, syscall.SIGHUP) 65 } 66 67 func TestStress(t *testing.T) { 68 dur := 3 * time.Second 69 if testing.Short() { 70 dur = 100 * time.Millisecond 71 } 72 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 73 done := make(chan bool) 74 finished := make(chan bool) 75 go func() { 76 sig := make(chan os.Signal, 1) 77 Notify(sig, syscall.SIGUSR1) 78 defer Stop(sig) 79 Loop: 80 for { 81 select { 82 case <-sig: 83 case <-done: 84 break Loop 85 } 86 } 87 finished <- true 88 }() 89 go func() { 90 Loop: 91 for { 92 select { 93 case <-done: 94 break Loop 95 default: 96 syscall.Kill(syscall.Getpid(), syscall.SIGUSR1) 97 runtime.Gosched() 98 } 99 } 100 finished <- true 101 }() 102 time.Sleep(dur) 103 close(done) 104 <-finished 105 <-finished 106 // When run with 'go test -cpu=1,2,4' SIGUSR1 from this test can slip 107 // into subsequent TestSignal() causing failure. 108 // Sleep for a while to reduce the possibility of the failure. 109 time.Sleep(10 * time.Millisecond) 110 } 111 112 func testCancel(t *testing.T, ignore bool) { 113 // Send SIGWINCH. By default this signal should be ignored. 114 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) 115 time.Sleep(100 * time.Millisecond) 116 117 // Ask to be notified on c1 when a SIGWINCH is received. 118 c1 := make(chan os.Signal, 1) 119 Notify(c1, syscall.SIGWINCH) 120 defer Stop(c1) 121 122 // Ask to be notified on c2 when a SIGHUP is received. 123 c2 := make(chan os.Signal, 1) 124 Notify(c2, syscall.SIGHUP) 125 defer Stop(c2) 126 127 // Send this process a SIGWINCH and wait for notification on c1. 128 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) 129 waitSig(t, c1, syscall.SIGWINCH) 130 131 // Send this process a SIGHUP and wait for notification on c2. 132 syscall.Kill(syscall.Getpid(), syscall.SIGHUP) 133 waitSig(t, c2, syscall.SIGHUP) 134 135 // Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP. 136 if ignore { 137 Ignore(syscall.SIGWINCH, syscall.SIGHUP) 138 } else { 139 Reset(syscall.SIGWINCH, syscall.SIGHUP) 140 } 141 142 // Send this process a SIGWINCH. It should be ignored. 143 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) 144 145 // If ignoring, Send this process a SIGHUP. It should be ignored. 146 if ignore { 147 syscall.Kill(syscall.Getpid(), syscall.SIGHUP) 148 } 149 150 select { 151 case s := <-c1: 152 t.Fatalf("unexpected signal %v", s) 153 case <-time.After(100 * time.Millisecond): 154 // nothing to read - good 155 } 156 157 select { 158 case s := <-c2: 159 t.Fatalf("unexpected signal %v", s) 160 case <-time.After(100 * time.Millisecond): 161 // nothing to read - good 162 } 163 164 // Reset the signal handlers for all signals. 165 Reset() 166 } 167 168 // Test that Reset cancels registration for listed signals on all channels. 169 func TestReset(t *testing.T) { 170 testCancel(t, false) 171 } 172 173 // Test that Ignore cancels registration for listed signals on all channels. 174 func TestIgnore(t *testing.T) { 175 testCancel(t, true) 176 } 177 178 var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop") 179 180 // Test that Stop cancels the channel's registrations. 181 func TestStop(t *testing.T) { 182 sigs := []syscall.Signal{ 183 syscall.SIGWINCH, 184 syscall.SIGHUP, 185 syscall.SIGUSR1, 186 } 187 188 for _, sig := range sigs { 189 // Send the signal. 190 // If it's SIGWINCH, we should not see it. 191 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. 192 if sig == syscall.SIGWINCH || (sig == syscall.SIGHUP && *sendUncaughtSighup == 1) { 193 syscall.Kill(syscall.Getpid(), sig) 194 } 195 time.Sleep(100 * time.Millisecond) 196 197 // Ask for signal 198 c := make(chan os.Signal, 1) 199 Notify(c, sig) 200 defer Stop(c) 201 202 // Send this process that signal 203 syscall.Kill(syscall.Getpid(), sig) 204 waitSig(t, c, sig) 205 206 Stop(c) 207 select { 208 case s := <-c: 209 t.Fatalf("unexpected signal %v", s) 210 case <-time.After(100 * time.Millisecond): 211 // nothing to read - good 212 } 213 214 // Send the signal. 215 // If it's SIGWINCH, we should not see it. 216 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. 217 if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 { 218 syscall.Kill(syscall.Getpid(), sig) 219 } 220 221 select { 222 case s := <-c: 223 t.Fatalf("unexpected signal %v", s) 224 case <-time.After(100 * time.Millisecond): 225 // nothing to read - good 226 } 227 } 228 } 229 230 // Test that when run under nohup, an uncaught SIGHUP does not kill the program, 231 // but a 232 func TestNohup(t *testing.T) { 233 // Ugly: ask for SIGHUP so that child will not have no-hup set 234 // even if test is running under nohup environment. 235 // We have no intention of reading from c. 236 c := make(chan os.Signal, 1) 237 Notify(c, syscall.SIGHUP) 238 239 // When run without nohup, the test should crash on an uncaught SIGHUP. 240 // When run under nohup, the test should ignore uncaught SIGHUPs, 241 // because the runtime is not supposed to be listening for them. 242 // Either way, TestStop should still be able to catch them when it wants them 243 // and then when it stops wanting them, the original behavior should resume. 244 // 245 // send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs. 246 // send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs. 247 // 248 // Both should fail without nohup and succeed with nohup. 249 250 for i := 1; i <= 2; i++ { 251 out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() 252 if err == nil { 253 t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out) 254 } 255 } 256 257 Stop(c) 258 259 // Skip the nohup test below when running in tmux on darwin, since nohup 260 // doesn't work correctly there. See issue #5135. 261 if runtime.GOOS == "darwin" && os.Getenv("TMUX") != "" { 262 t.Skip("Skipping nohup test due to running in tmux on darwin") 263 } 264 265 // Again, this time with nohup, assuming we can find it. 266 _, err := os.Stat("/usr/bin/nohup") 267 if err != nil { 268 t.Skip("cannot find nohup; skipping second half of test") 269 } 270 271 for i := 1; i <= 2; i++ { 272 os.Remove("nohup.out") 273 out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() 274 275 data, _ := ioutil.ReadFile("nohup.out") 276 os.Remove("nohup.out") 277 if err != nil { 278 t.Fatalf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", i, err, out, data) 279 } 280 } 281 } 282 283 // Test that SIGCONT works (issue 8953). 284 func TestSIGCONT(t *testing.T) { 285 c := make(chan os.Signal, 1) 286 Notify(c, syscall.SIGCONT) 287 defer Stop(c) 288 syscall.Kill(syscall.Getpid(), syscall.SIGCONT) 289 waitSig(t, c, syscall.SIGCONT) 290 }