github.com/FenixAra/go@v0.0.0-20170127160404-96ea0918e670/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 // At this point we do not expect any further signals on c1. 143 // However, it is just barely possible that the initial SIGWINCH 144 // at the start of this function was delivered after we called 145 // Notify on c1. In that case the waitSig for SIGWINCH may have 146 // picked up that initial SIGWINCH, and the second SIGWINCH may 147 // then have been delivered on the channel. This sequence of events 148 // may have caused issue 15661. 149 // So, read any possible signal from the channel now. 150 select { 151 case <-c1: 152 default: 153 } 154 155 // Send this process a SIGWINCH. It should be ignored. 156 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) 157 158 // If ignoring, Send this process a SIGHUP. It should be ignored. 159 if ignore { 160 syscall.Kill(syscall.Getpid(), syscall.SIGHUP) 161 } 162 163 select { 164 case s := <-c1: 165 t.Fatalf("unexpected signal %v", s) 166 case <-time.After(100 * time.Millisecond): 167 // nothing to read - good 168 } 169 170 select { 171 case s := <-c2: 172 t.Fatalf("unexpected signal %v", s) 173 case <-time.After(100 * time.Millisecond): 174 // nothing to read - good 175 } 176 177 // Reset the signal handlers for all signals. 178 Reset() 179 } 180 181 // Test that Reset cancels registration for listed signals on all channels. 182 func TestReset(t *testing.T) { 183 testCancel(t, false) 184 } 185 186 // Test that Ignore cancels registration for listed signals on all channels. 187 func TestIgnore(t *testing.T) { 188 testCancel(t, true) 189 } 190 191 var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop") 192 193 // Test that Stop cancels the channel's registrations. 194 func TestStop(t *testing.T) { 195 sigs := []syscall.Signal{ 196 syscall.SIGWINCH, 197 syscall.SIGHUP, 198 syscall.SIGUSR1, 199 } 200 201 for _, sig := range sigs { 202 // Send the signal. 203 // If it's SIGWINCH, we should not see it. 204 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. 205 if sig == syscall.SIGWINCH || (sig == syscall.SIGHUP && *sendUncaughtSighup == 1) { 206 syscall.Kill(syscall.Getpid(), sig) 207 } 208 time.Sleep(100 * time.Millisecond) 209 210 // Ask for signal 211 c := make(chan os.Signal, 1) 212 Notify(c, sig) 213 defer Stop(c) 214 215 // Send this process that signal 216 syscall.Kill(syscall.Getpid(), sig) 217 waitSig(t, c, sig) 218 219 Stop(c) 220 select { 221 case s := <-c: 222 t.Fatalf("unexpected signal %v", s) 223 case <-time.After(100 * time.Millisecond): 224 // nothing to read - good 225 } 226 227 // Send the signal. 228 // If it's SIGWINCH, we should not see it. 229 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. 230 if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 { 231 syscall.Kill(syscall.Getpid(), sig) 232 } 233 234 select { 235 case s := <-c: 236 t.Fatalf("unexpected signal %v", s) 237 case <-time.After(100 * time.Millisecond): 238 // nothing to read - good 239 } 240 } 241 } 242 243 // Test that when run under nohup, an uncaught SIGHUP does not kill the program, 244 // but a 245 func TestNohup(t *testing.T) { 246 // Ugly: ask for SIGHUP so that child will not have no-hup set 247 // even if test is running under nohup environment. 248 // We have no intention of reading from c. 249 c := make(chan os.Signal, 1) 250 Notify(c, syscall.SIGHUP) 251 252 // When run without nohup, the test should crash on an uncaught SIGHUP. 253 // When run under nohup, the test should ignore uncaught SIGHUPs, 254 // because the runtime is not supposed to be listening for them. 255 // Either way, TestStop should still be able to catch them when it wants them 256 // and then when it stops wanting them, the original behavior should resume. 257 // 258 // send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs. 259 // send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs. 260 // 261 // Both should fail without nohup and succeed with nohup. 262 263 for i := 1; i <= 2; i++ { 264 out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() 265 if err == nil { 266 t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out) 267 } 268 } 269 270 Stop(c) 271 272 // Skip the nohup test below when running in tmux on darwin, since nohup 273 // doesn't work correctly there. See issue #5135. 274 if runtime.GOOS == "darwin" && os.Getenv("TMUX") != "" { 275 t.Skip("Skipping nohup test due to running in tmux on darwin") 276 } 277 278 // Again, this time with nohup, assuming we can find it. 279 _, err := os.Stat("/usr/bin/nohup") 280 if err != nil { 281 t.Skip("cannot find nohup; skipping second half of test") 282 } 283 284 for i := 1; i <= 2; i++ { 285 os.Remove("nohup.out") 286 out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() 287 288 data, _ := ioutil.ReadFile("nohup.out") 289 os.Remove("nohup.out") 290 if err != nil { 291 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) 292 } 293 } 294 } 295 296 // Test that SIGCONT works (issue 8953). 297 func TestSIGCONT(t *testing.T) { 298 c := make(chan os.Signal, 1) 299 Notify(c, syscall.SIGCONT) 300 defer Stop(c) 301 syscall.Kill(syscall.Getpid(), syscall.SIGCONT) 302 waitSig(t, c, syscall.SIGCONT) 303 }