]> gcc.gnu.org Git - gcc.git/blame - libgo/go/os/signal/signal_test.go
libgo: update to Go 1.11
[gcc.git] / libgo / go / os / signal / signal_test.go
CommitLineData
cbb6491d
ILT
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
f163907e 5// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
cbb6491d
ILT
6
7package signal
8
9import (
bc998d03 10 "bytes"
be47d6ec 11 "flag"
bc998d03
ILT
12 "fmt"
13 "internal/testenv"
be47d6ec 14 "io/ioutil"
cbb6491d 15 "os"
be47d6ec 16 "os/exec"
d6f2922e 17 "runtime"
be47d6ec 18 "strconv"
bc998d03 19 "sync"
cbb6491d
ILT
20 "syscall"
21 "testing"
22 "time"
23)
24
cbb6491d
ILT
25func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
26 select {
27 case s := <-c:
28 if s != sig {
29 t.Fatalf("signal was %v, want %v", s, sig)
30 }
31 case <-time.After(1 * time.Second):
32 t.Fatalf("timeout waiting for %v", sig)
33 }
34}
35
be47d6ec 36// Test that basic signal handling works.
cbb6491d
ILT
37func TestSignal(t *testing.T) {
38 // Ask for SIGHUP
39 c := make(chan os.Signal, 1)
be47d6ec
ILT
40 Notify(c, syscall.SIGHUP)
41 defer Stop(c)
cbb6491d 42
cbb6491d 43 // Send this process a SIGHUP
f038dae6 44 t.Logf("sighup...")
be47d6ec
ILT
45 syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
46 waitSig(t, c, syscall.SIGHUP)
cbb6491d
ILT
47
48 // Ask for everything we can get.
49 c1 := make(chan os.Signal, 1)
50 Notify(c1)
51
cbb6491d 52 // Send this process a SIGWINCH
f038dae6 53 t.Logf("sigwinch...")
cbb6491d
ILT
54 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
55 waitSig(t, c1, syscall.SIGWINCH)
56
57 // Send two more SIGHUPs, to make sure that
58 // they get delivered on c1 and that not reading
59 // from c does not block everything.
f038dae6 60 t.Logf("sighup...")
cbb6491d
ILT
61 syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
62 waitSig(t, c1, syscall.SIGHUP)
f038dae6 63 t.Logf("sighup...")
cbb6491d
ILT
64 syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
65 waitSig(t, c1, syscall.SIGHUP)
66
67 // The first SIGHUP should be waiting for us on c.
68 waitSig(t, c, syscall.SIGHUP)
69}
d6f2922e
ILT
70
71func TestStress(t *testing.T) {
72 dur := 3 * time.Second
73 if testing.Short() {
74 dur = 100 * time.Millisecond
75 }
76 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
77 done := make(chan bool)
78 finished := make(chan bool)
79 go func() {
80 sig := make(chan os.Signal, 1)
81 Notify(sig, syscall.SIGUSR1)
be47d6ec 82 defer Stop(sig)
d6f2922e
ILT
83 Loop:
84 for {
85 select {
86 case <-sig:
87 case <-done:
88 break Loop
89 }
90 }
91 finished <- true
92 }()
93 go func() {
94 Loop:
95 for {
96 select {
97 case <-done:
98 break Loop
99 default:
100 syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
101 runtime.Gosched()
102 }
103 }
104 finished <- true
105 }()
106 time.Sleep(dur)
107 close(done)
108 <-finished
109 <-finished
be47d6ec
ILT
110 // When run with 'go test -cpu=1,2,4' SIGUSR1 from this test can slip
111 // into subsequent TestSignal() causing failure.
112 // Sleep for a while to reduce the possibility of the failure.
113 time.Sleep(10 * time.Millisecond)
114}
115
af146490
ILT
116func testCancel(t *testing.T, ignore bool) {
117 // Send SIGWINCH. By default this signal should be ignored.
118 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
119 time.Sleep(100 * time.Millisecond)
120
121 // Ask to be notified on c1 when a SIGWINCH is received.
122 c1 := make(chan os.Signal, 1)
123 Notify(c1, syscall.SIGWINCH)
124 defer Stop(c1)
125
126 // Ask to be notified on c2 when a SIGHUP is received.
127 c2 := make(chan os.Signal, 1)
128 Notify(c2, syscall.SIGHUP)
129 defer Stop(c2)
130
131 // Send this process a SIGWINCH and wait for notification on c1.
132 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
133 waitSig(t, c1, syscall.SIGWINCH)
134
135 // Send this process a SIGHUP and wait for notification on c2.
136 syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
137 waitSig(t, c2, syscall.SIGHUP)
138
139 // Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP.
140 if ignore {
141 Ignore(syscall.SIGWINCH, syscall.SIGHUP)
142 } else {
143 Reset(syscall.SIGWINCH, syscall.SIGHUP)
144 }
145
22b955cc
ILT
146 // At this point we do not expect any further signals on c1.
147 // However, it is just barely possible that the initial SIGWINCH
148 // at the start of this function was delivered after we called
149 // Notify on c1. In that case the waitSig for SIGWINCH may have
150 // picked up that initial SIGWINCH, and the second SIGWINCH may
151 // then have been delivered on the channel. This sequence of events
152 // may have caused issue 15661.
153 // So, read any possible signal from the channel now.
154 select {
155 case <-c1:
156 default:
157 }
158
af146490
ILT
159 // Send this process a SIGWINCH. It should be ignored.
160 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
161
162 // If ignoring, Send this process a SIGHUP. It should be ignored.
163 if ignore {
164 syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
165 }
166
167 select {
168 case s := <-c1:
169 t.Fatalf("unexpected signal %v", s)
170 case <-time.After(100 * time.Millisecond):
171 // nothing to read - good
172 }
173
174 select {
175 case s := <-c2:
176 t.Fatalf("unexpected signal %v", s)
177 case <-time.After(100 * time.Millisecond):
178 // nothing to read - good
179 }
180
181 // Reset the signal handlers for all signals.
182 Reset()
183}
184
185// Test that Reset cancels registration for listed signals on all channels.
186func TestReset(t *testing.T) {
187 testCancel(t, false)
188}
189
190// Test that Ignore cancels registration for listed signals on all channels.
191func TestIgnore(t *testing.T) {
192 testCancel(t, true)
193}
194
dd931d9b
ILT
195// Test that Ignored correctly detects changes to the ignored status of a signal.
196func TestIgnored(t *testing.T) {
197 // Ask to be notified on SIGWINCH.
198 c := make(chan os.Signal, 1)
199 Notify(c, syscall.SIGWINCH)
200
201 // If we're being notified, then the signal should not be ignored.
202 if Ignored(syscall.SIGWINCH) {
203 t.Errorf("expected SIGWINCH to not be ignored.")
204 }
205 Stop(c)
206 Ignore(syscall.SIGWINCH)
207
208 // We're no longer paying attention to this signal.
209 if !Ignored(syscall.SIGWINCH) {
210 t.Errorf("expected SIGWINCH to be ignored when explicitly ignoring it.")
211 }
212
213 Reset()
214}
215
216var checkSighupIgnored = flag.Bool("check_sighup_ignored", false, "if true, TestDetectNohup will fail if SIGHUP is not ignored.")
217
218// Test that Ignored(SIGHUP) correctly detects whether it is being run under nohup.
219func TestDetectNohup(t *testing.T) {
220 if *checkSighupIgnored {
221 if !Ignored(syscall.SIGHUP) {
222 t.Fatal("SIGHUP is not ignored.")
223 } else {
224 t.Log("SIGHUP is ignored.")
225 }
226 } else {
227 defer Reset()
228 // Ugly: ask for SIGHUP so that child will not have no-hup set
229 // even if test is running under nohup environment.
230 // We have no intention of reading from c.
231 c := make(chan os.Signal, 1)
232 Notify(c, syscall.SIGHUP)
233 if out, err := exec.Command(os.Args[0], "-test.run=TestDetectNohup", "-check_sighup_ignored").CombinedOutput(); err == nil {
234 t.Errorf("ran test with -check_sighup_ignored and it succeeded: expected failure.\nOutput:\n%s", out)
235 }
236 Stop(c)
237 // Again, this time with nohup, assuming we can find it.
238 _, err := os.Stat("/usr/bin/nohup")
239 if err != nil {
240 t.Skip("cannot find nohup; skipping second half of test")
241 }
242 Ignore(syscall.SIGHUP)
243 os.Remove("nohup.out")
244 out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestDetectNohup", "-check_sighup_ignored").CombinedOutput()
245
246 data, _ := ioutil.ReadFile("nohup.out")
247 os.Remove("nohup.out")
248 if err != nil {
249 t.Errorf("ran test with -check_sighup_ignored under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", err, out, data)
250 }
251 }
252}
253
be47d6ec
ILT
254var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
255
256// Test that Stop cancels the channel's registrations.
257func TestStop(t *testing.T) {
258 sigs := []syscall.Signal{
259 syscall.SIGWINCH,
260 syscall.SIGHUP,
f98dd1a3 261 syscall.SIGUSR1,
be47d6ec
ILT
262 }
263
264 for _, sig := range sigs {
265 // Send the signal.
266 // If it's SIGWINCH, we should not see it.
267 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
f98dd1a3 268 if sig == syscall.SIGWINCH || (sig == syscall.SIGHUP && *sendUncaughtSighup == 1) {
be47d6ec
ILT
269 syscall.Kill(syscall.Getpid(), sig)
270 }
f8d9fa9e 271 time.Sleep(100 * time.Millisecond)
be47d6ec
ILT
272
273 // Ask for signal
274 c := make(chan os.Signal, 1)
275 Notify(c, sig)
276 defer Stop(c)
277
278 // Send this process that signal
279 syscall.Kill(syscall.Getpid(), sig)
280 waitSig(t, c, sig)
281
282 Stop(c)
283 select {
284 case s := <-c:
285 t.Fatalf("unexpected signal %v", s)
f8d9fa9e 286 case <-time.After(100 * time.Millisecond):
be47d6ec
ILT
287 // nothing to read - good
288 }
289
290 // Send the signal.
291 // If it's SIGWINCH, we should not see it.
292 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
293 if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 {
294 syscall.Kill(syscall.Getpid(), sig)
295 }
296
297 select {
298 case s := <-c:
299 t.Fatalf("unexpected signal %v", s)
f8d9fa9e 300 case <-time.After(100 * time.Millisecond):
be47d6ec
ILT
301 // nothing to read - good
302 }
303 }
304}
305
306// Test that when run under nohup, an uncaught SIGHUP does not kill the program,
307// but a
308func TestNohup(t *testing.T) {
309 // Ugly: ask for SIGHUP so that child will not have no-hup set
310 // even if test is running under nohup environment.
311 // We have no intention of reading from c.
312 c := make(chan os.Signal, 1)
313 Notify(c, syscall.SIGHUP)
314
315 // When run without nohup, the test should crash on an uncaught SIGHUP.
316 // When run under nohup, the test should ignore uncaught SIGHUPs,
317 // because the runtime is not supposed to be listening for them.
318 // Either way, TestStop should still be able to catch them when it wants them
319 // and then when it stops wanting them, the original behavior should resume.
320 //
321 // send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs.
322 // send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs.
323 //
324 // Both should fail without nohup and succeed with nohup.
325
326 for i := 1; i <= 2; i++ {
327 out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
328 if err == nil {
329 t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out)
330 }
331 }
332
333 Stop(c)
334
f98dd1a3
ILT
335 // Skip the nohup test below when running in tmux on darwin, since nohup
336 // doesn't work correctly there. See issue #5135.
337 if runtime.GOOS == "darwin" && os.Getenv("TMUX") != "" {
338 t.Skip("Skipping nohup test due to running in tmux on darwin")
339 }
340
be47d6ec
ILT
341 // Again, this time with nohup, assuming we can find it.
342 _, err := os.Stat("/usr/bin/nohup")
343 if err != nil {
344 t.Skip("cannot find nohup; skipping second half of test")
345 }
346
347 for i := 1; i <= 2; i++ {
348 os.Remove("nohup.out")
349 out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
350
351 data, _ := ioutil.ReadFile("nohup.out")
352 os.Remove("nohup.out")
353 if err != nil {
354 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)
355 }
356 }
d6f2922e 357}
f98dd1a3
ILT
358
359// Test that SIGCONT works (issue 8953).
360func TestSIGCONT(t *testing.T) {
361 c := make(chan os.Signal, 1)
362 Notify(c, syscall.SIGCONT)
363 defer Stop(c)
364 syscall.Kill(syscall.Getpid(), syscall.SIGCONT)
365 waitSig(t, c, syscall.SIGCONT)
366}
bc998d03
ILT
367
368// Test race between stopping and receiving a signal (issue 14571).
369func TestAtomicStop(t *testing.T) {
370 if os.Getenv("GO_TEST_ATOMIC_STOP") != "" {
371 atomicStopTestProgram()
372 t.Fatal("atomicStopTestProgram returned")
373 }
374
375 testenv.MustHaveExec(t)
376
377 const execs = 10
378 for i := 0; i < execs; i++ {
379 cmd := exec.Command(os.Args[0], "-test.run=TestAtomicStop")
380 cmd.Env = append(os.Environ(), "GO_TEST_ATOMIC_STOP=1")
381 out, err := cmd.CombinedOutput()
382 if err == nil {
1a2f01ef
ILT
383 if len(out) > 0 {
384 t.Logf("iteration %d: output %s", i, out)
385 }
bc998d03
ILT
386 } else {
387 t.Logf("iteration %d: exit status %q: output: %s", i, err, out)
388 }
389
390 lost := bytes.Contains(out, []byte("lost signal"))
391 if lost {
392 t.Errorf("iteration %d: lost signal", i)
393 }
394
395 // The program should either die due to SIGINT,
396 // or exit with success without printing "lost signal".
397 if err == nil {
398 if len(out) > 0 && !lost {
399 t.Errorf("iteration %d: unexpected output", i)
400 }
401 } else {
402 if ee, ok := err.(*exec.ExitError); !ok {
403 t.Errorf("iteration %d: error (%v) has type %T; expected exec.ExitError", i, err, err)
404 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
405 t.Errorf("iteration %d: error.Sys (%v) has type %T; expected syscall.WaitStatus", i, ee.Sys(), ee.Sys())
406 } else if !ws.Signaled() || ws.Signal() != syscall.SIGINT {
407 t.Errorf("iteration %d: got exit status %v; expected SIGINT", i, ee)
408 }
409 }
410 }
411}
412
413// atomicStopTestProgram is run in a subprocess by TestAtomicStop.
414// It tries to trigger a signal delivery race. This function should
415// either catch a signal or die from it.
416func atomicStopTestProgram() {
417 const tries = 10
418 pid := syscall.Getpid()
419 printed := false
420 for i := 0; i < tries; i++ {
421 cs := make(chan os.Signal, 1)
422 Notify(cs, syscall.SIGINT)
423
424 var wg sync.WaitGroup
425 wg.Add(1)
426 go func() {
427 defer wg.Done()
428 Stop(cs)
429 }()
430
431 syscall.Kill(pid, syscall.SIGINT)
432
433 // At this point we should either die from SIGINT or
434 // get a notification on cs. If neither happens, we
435 // dropped the signal. Give it a second to deliver,
436 // which is far far longer than it should require.
437
438 select {
439 case <-cs:
440 case <-time.After(1 * time.Second):
441 if !printed {
1a2f01ef 442 fmt.Print("lost signal on tries:")
bc998d03
ILT
443 printed = true
444 }
445 fmt.Printf(" %d", i)
446 }
447
448 wg.Wait()
449 }
450 if printed {
451 fmt.Print("\n")
452 }
453
454 os.Exit(0)
455}
This page took 0.613913 seconds and 5 git commands to generate.