Source file
src/os/signal/signal_test.go
1
2
3
4
5
6
7 package signal
8
9 import (
10 "bytes"
11 "context"
12 "errors"
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
29
30
31
32
33 var settleTime = 100 * time.Millisecond
34
35
36
37
38 var fatalWaitingTime = 30 * time.Second
39
40 func init() {
41 if testenv.Builder() == "solaris-amd64-oraclerel" {
42
43
44
45
46
47
48
49
50
51
52 settleTime = 5 * time.Second
53 } else if runtime.GOOS == "linux" && strings.HasPrefix(runtime.GOARCH, "ppc64") {
54
55
56
57
58
59 settleTime = 5 * time.Second
60 } else if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
61 if scale, err := strconv.Atoi(s); err == nil {
62 settleTime *= time.Duration(scale)
63 }
64 }
65 }
66
67 func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
68 t.Helper()
69 waitSig1(t, c, sig, false)
70 }
71 func waitSigAll(t *testing.T, c <-chan os.Signal, sig os.Signal) {
72 t.Helper()
73 waitSig1(t, c, sig, true)
74 }
75
76 func waitSig1(t *testing.T, c <-chan os.Signal, sig os.Signal, all bool) {
77 t.Helper()
78
79
80
81 start := time.Now()
82 timer := time.NewTimer(settleTime / 10)
83 defer timer.Stop()
84
85
86
87
88
89 for time.Since(start) < fatalWaitingTime {
90 select {
91 case s := <-c:
92 if s == sig {
93 return
94 }
95 if !all || s != syscall.SIGURG {
96 t.Fatalf("signal was %v, want %v", s, sig)
97 }
98 case <-timer.C:
99 timer.Reset(settleTime / 10)
100 }
101 }
102 t.Fatalf("timeout after %v waiting for %v", fatalWaitingTime, sig)
103 }
104
105
106
107 func quiesce() {
108
109
110
111
112
113
114 start := time.Now()
115 for time.Since(start) < settleTime {
116 time.Sleep(settleTime / 10)
117 }
118 }
119
120
121 func TestSignal(t *testing.T) {
122
123 c := make(chan os.Signal, 1)
124 Notify(c, syscall.SIGHUP)
125 defer Stop(c)
126
127
128 t.Logf("sighup...")
129 syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
130 waitSig(t, c, syscall.SIGHUP)
131
132
133
134
135 c1 := make(chan os.Signal, 10)
136 Notify(c1)
137
138 Reset(syscall.SIGURG)
139 defer Stop(c1)
140
141
142 t.Logf("sigwinch...")
143 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
144 waitSigAll(t, c1, syscall.SIGWINCH)
145
146
147
148
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
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
176
177 quiesce()
178 Stop(sig)
179
180
181
182
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
195 }
196 }
197
198 func testCancel(t *testing.T, ignore bool) {
199
200 c1 := make(chan os.Signal, 1)
201 Notify(c1, syscall.SIGWINCH)
202 defer Stop(c1)
203
204
205 c2 := make(chan os.Signal, 1)
206 Notify(c2, syscall.SIGHUP)
207 defer Stop(c2)
208
209
210 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
211 waitSig(t, c1, syscall.SIGWINCH)
212
213
214 syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
215 waitSig(t, c2, syscall.SIGHUP)
216
217
218
219 if ignore {
220 Ignore(syscall.SIGWINCH, syscall.SIGHUP)
221
222
223
224 } else {
225 Reset(syscall.SIGWINCH, syscall.SIGHUP)
226 }
227
228
229 syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
230
231
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
243 }
244
245 select {
246 case s := <-c2:
247 t.Errorf("unexpected signal %v", s)
248 default:
249
250 }
251
252
253
254
255 Notify(c1, syscall.SIGWINCH)
256 Notify(c2, syscall.SIGHUP)
257 quiesce()
258 }
259
260
261 func TestReset(t *testing.T) {
262 testCancel(t, false)
263 }
264
265
266 func TestIgnore(t *testing.T) {
267 testCancel(t, true)
268 }
269
270
271 func TestIgnored(t *testing.T) {
272
273 c := make(chan os.Signal, 1)
274 Notify(c, syscall.SIGWINCH)
275
276
277 if Ignored(syscall.SIGWINCH) {
278 t.Errorf("expected SIGWINCH to not be ignored.")
279 }
280 Stop(c)
281 Ignore(syscall.SIGWINCH)
282
283
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
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
304
305
306 c := make(chan os.Signal, 1)
307 Notify(c, syscall.SIGHUP)
308 if out, err := testenv.Command(t, testenv.Executable(t), "-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
313
314 _, err := os.Stat("/usr/bin/nohup")
315 if err != nil {
316 t.Skip("cannot find nohup; skipping second half of test")
317 }
318 Ignore(syscall.SIGHUP)
319 os.Remove("nohup.out")
320 out, err := testenv.Command(t, "/usr/bin/nohup", testenv.Executable(t), "-test.run=^TestDetectNohup$", "-check_sighup_ignored").CombinedOutput()
321
322 data, _ := os.ReadFile("nohup.out")
323 os.Remove("nohup.out")
324 if err != nil {
325
326
327
328 if runtime.GOOS == "darwin" && strings.Contains(string(out), "nohup: can't detach from console: Inappropriate ioctl for device") {
329 t.Skip("Skipping nohup test due to darwin builder limitation. See https://go.dev/issue/63875.")
330 }
331
332 t.Errorf("ran test with -check_sighup_ignored under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", err, out, data)
333 }
334 }
335 }
336
337 var (
338 sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
339 dieFromSighup = flag.Bool("die_from_sighup", false, "wait to die from uncaught SIGHUP")
340 )
341
342
343 func TestStop(t *testing.T) {
344 sigs := []syscall.Signal{
345 syscall.SIGWINCH,
346 syscall.SIGHUP,
347 syscall.SIGUSR1,
348 }
349
350 for _, sig := range sigs {
351 t.Run(fmt.Sprint(sig), func(t *testing.T) {
352
353
354
355
356 t.Parallel()
357
358
359
360
361
362 mayHaveBlockedSignal := false
363 if !Ignored(sig) && (sig != syscall.SIGHUP || *sendUncaughtSighup == 1) {
364 syscall.Kill(syscall.Getpid(), sig)
365 quiesce()
366
367
368
369 mayHaveBlockedSignal = true
370 }
371
372
373 c := make(chan os.Signal, 1)
374 Notify(c, sig)
375
376
377 syscall.Kill(syscall.Getpid(), sig)
378 waitSig(t, c, sig)
379
380 if mayHaveBlockedSignal {
381
382
383
384
385 quiesce()
386 select {
387 case <-c:
388 default:
389 }
390 }
391
392
393
394 Stop(c)
395 if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 {
396 syscall.Kill(syscall.Getpid(), sig)
397 quiesce()
398
399 select {
400 case s := <-c:
401 t.Errorf("unexpected signal %v", s)
402 default:
403
404 }
405
406
407
408
409 Notify(c, sig)
410 quiesce()
411 Stop(c)
412 }
413 })
414 }
415 }
416
417
418 func TestNohup(t *testing.T) {
419
420
421
422
423
424
425
426
427
428
429
430 t.Run("uncaught", func(t *testing.T) {
431
432
433
434 c := make(chan os.Signal, 1)
435 Notify(c, syscall.SIGHUP)
436 t.Cleanup(func() { Stop(c) })
437
438 var subTimeout time.Duration
439 if deadline, ok := t.Deadline(); ok {
440 subTimeout = time.Until(deadline)
441 subTimeout -= subTimeout / 10
442 }
443 for i := 1; i <= 2; i++ {
444 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
445 t.Parallel()
446
447 args := []string{
448 "-test.v",
449 "-test.run=^TestStop$",
450 "-send_uncaught_sighup=" + strconv.Itoa(i),
451 "-die_from_sighup",
452 }
453 if subTimeout != 0 {
454 args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout))
455 }
456 out, err := testenv.Command(t, testenv.Executable(t), args...).CombinedOutput()
457
458 if err == nil {
459 t.Errorf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out)
460 } else {
461 t.Logf("test with -send_uncaught_sighup=%d failed as expected.\nError: %v\nOutput:\n%s", i, err, out)
462 }
463 })
464 }
465 })
466
467 t.Run("nohup", func(t *testing.T) {
468
469
470 if runtime.GOOS == "darwin" && os.Getenv("TMUX") != "" {
471 t.Skip("Skipping nohup test due to running in tmux on darwin")
472 }
473
474
475 _, err := exec.LookPath("nohup")
476 if err != nil {
477 t.Skip("cannot find nohup; skipping second half of test")
478 }
479
480 var subTimeout time.Duration
481 if deadline, ok := t.Deadline(); ok {
482 subTimeout = time.Until(deadline)
483 subTimeout -= subTimeout / 10
484 }
485 for i := 1; i <= 2; i++ {
486 t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
487 t.Parallel()
488
489
490
491
492
493
494
495 args := []string{
496 os.Args[0],
497 "-test.v",
498 "-test.run=^TestStop$",
499 "-send_uncaught_sighup=" + strconv.Itoa(i),
500 }
501 if subTimeout != 0 {
502 args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout))
503 }
504 out, err := testenv.Command(t, "nohup", args...).CombinedOutput()
505
506 if err != nil {
507
508
509
510 if runtime.GOOS == "darwin" && strings.Contains(string(out), "nohup: can't detach from console: Inappropriate ioctl for device") {
511
512
513 t.Logf("Skipping nohup test due to darwin builder limitation. See https://go.dev/issue/63875.")
514 return
515 }
516
517 t.Errorf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s", i, err, out)
518 } else {
519 t.Logf("ran test with -send_uncaught_sighup=%d under nohup.\nOutput:\n%s", i, out)
520 }
521 })
522 }
523 })
524 }
525
526
527 func TestSIGCONT(t *testing.T) {
528 c := make(chan os.Signal, 1)
529 Notify(c, syscall.SIGCONT)
530 defer Stop(c)
531 syscall.Kill(syscall.Getpid(), syscall.SIGCONT)
532 waitSig(t, c, syscall.SIGCONT)
533 }
534
535
536 func TestAtomicStop(t *testing.T) {
537 if os.Getenv("GO_TEST_ATOMIC_STOP") != "" {
538 atomicStopTestProgram(t)
539 t.Fatal("atomicStopTestProgram returned")
540 }
541
542 testenv.MustHaveExec(t)
543
544
545
546
547
548
549
550
551
552
553 cs := make(chan os.Signal, 1)
554 Notify(cs, syscall.SIGINT)
555 defer Stop(cs)
556
557 const execs = 10
558 for i := 0; i < execs; i++ {
559 timeout := "0"
560 if deadline, ok := t.Deadline(); ok {
561 timeout = time.Until(deadline).String()
562 }
563 cmd := testenv.Command(t, testenv.Executable(t), "-test.run=^TestAtomicStop$", "-test.timeout="+timeout)
564 cmd.Env = append(os.Environ(), "GO_TEST_ATOMIC_STOP=1")
565 out, err := cmd.CombinedOutput()
566 if err == nil {
567 if len(out) > 0 {
568 t.Logf("iteration %d: output %s", i, out)
569 }
570 } else {
571 t.Logf("iteration %d: exit status %q: output: %s", i, err, out)
572 }
573
574 lost := bytes.Contains(out, []byte("lost signal"))
575 if lost {
576 t.Errorf("iteration %d: lost signal", i)
577 }
578
579
580
581 if err == nil {
582 if len(out) > 0 && !lost {
583 t.Errorf("iteration %d: unexpected output", i)
584 }
585 } else {
586 if ee, ok := err.(*exec.ExitError); !ok {
587 t.Errorf("iteration %d: error (%v) has type %T; expected exec.ExitError", i, err, err)
588 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
589 t.Errorf("iteration %d: error.Sys (%v) has type %T; expected syscall.WaitStatus", i, ee.Sys(), ee.Sys())
590 } else if !ws.Signaled() || ws.Signal() != syscall.SIGINT {
591 t.Errorf("iteration %d: got exit status %v; expected SIGINT", i, ee)
592 }
593 }
594 }
595 }
596
597
598
599
600 func atomicStopTestProgram(t *testing.T) {
601
602 if Ignored(syscall.SIGINT) {
603 fmt.Println("SIGINT is ignored")
604 os.Exit(1)
605 }
606
607 const tries = 10
608
609 timeout := 2 * time.Second
610 if deadline, ok := t.Deadline(); ok {
611
612
613 timeout = time.Until(deadline) / (tries + 1)
614 }
615
616 pid := syscall.Getpid()
617 printed := false
618 for i := 0; i < tries; i++ {
619 cs := make(chan os.Signal, 1)
620 Notify(cs, syscall.SIGINT)
621
622 var wg sync.WaitGroup
623 wg.Add(1)
624 go func() {
625 defer wg.Done()
626 Stop(cs)
627 }()
628
629 syscall.Kill(pid, syscall.SIGINT)
630
631
632
633
634
635
636 select {
637 case <-cs:
638 case <-time.After(timeout):
639 if !printed {
640 fmt.Print("lost signal on tries:")
641 printed = true
642 }
643 fmt.Printf(" %d", i)
644 }
645
646 wg.Wait()
647 }
648 if printed {
649 fmt.Print("\n")
650 }
651
652 os.Exit(0)
653 }
654
655 func TestTime(t *testing.T) {
656
657
658 dur := 3 * time.Second
659 if testing.Short() {
660 dur = 100 * time.Millisecond
661 }
662 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
663
664 sig := make(chan os.Signal, 1)
665 Notify(sig, syscall.SIGUSR1)
666
667 stop := make(chan struct{})
668 go func() {
669 for {
670 select {
671 case <-stop:
672
673
674 quiesce()
675 Stop(sig)
676
677
678
679
680 close(sig)
681 return
682
683 default:
684 syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
685 runtime.Gosched()
686 }
687 }
688 }()
689
690 done := make(chan struct{})
691 go func() {
692 for range sig {
693
694 }
695 close(done)
696 }()
697
698 t0 := time.Now()
699 for t1 := t0; t1.Sub(t0) < dur; t1 = time.Now() {
700 }
701
702 close(stop)
703 <-done
704 }
705
706 var (
707 checkNotifyContext = flag.Bool("check_notify_ctx", false, "if true, TestNotifyContext will fail if SIGINT is not received.")
708 ctxNotifyTimes = flag.Int("ctx_notify_times", 1, "number of times a SIGINT signal should be received")
709 )
710
711 func TestNotifyContextNotifications(t *testing.T) {
712 if *checkNotifyContext {
713 ctx, _ := NotifyContext(context.Background(), syscall.SIGINT)
714
715
716 var wg sync.WaitGroup
717 n := *ctxNotifyTimes
718 wg.Add(n)
719 for i := 0; i < n; i++ {
720 go func() {
721 syscall.Kill(syscall.Getpid(), syscall.SIGINT)
722 wg.Done()
723 }()
724 }
725 wg.Wait()
726 <-ctx.Done()
727 if got, want := context.Cause(ctx).Error(), "interrupt signal received"; got != want {
728 t.Errorf("context.Cause(ctx) = %q, want %q", got, want)
729 }
730 fmt.Println("received SIGINT")
731
732
733
734 time.Sleep(settleTime)
735 return
736 }
737
738 t.Parallel()
739 testCases := []struct {
740 name string
741 n int
742 }{
743 {"once", 1},
744 {"multiple", 10},
745 }
746 for _, tc := range testCases {
747 t.Run(tc.name, func(t *testing.T) {
748 t.Parallel()
749
750 var subTimeout time.Duration
751 if deadline, ok := t.Deadline(); ok {
752 timeout := time.Until(deadline)
753 if timeout < 2*settleTime {
754 t.Fatalf("starting test with less than %v remaining", 2*settleTime)
755 }
756 subTimeout = timeout - (timeout / 10)
757 }
758
759 args := []string{
760 "-test.v",
761 "-test.run=^TestNotifyContextNotifications$",
762 "-check_notify_ctx",
763 fmt.Sprintf("-ctx_notify_times=%d", tc.n),
764 }
765 if subTimeout != 0 {
766 args = append(args, fmt.Sprintf("-test.timeout=%v", subTimeout))
767 }
768 out, err := testenv.Command(t, testenv.Executable(t), args...).CombinedOutput()
769 if err != nil {
770 t.Errorf("ran test with -check_notify_ctx_notification and it failed with %v.\nOutput:\n%s", err, out)
771 }
772 if want := []byte("received SIGINT\n"); !bytes.Contains(out, want) {
773 t.Errorf("got %q, wanted %q", out, want)
774 }
775 })
776 }
777 }
778
779 func TestNotifyContextStop(t *testing.T) {
780 Ignore(syscall.SIGHUP)
781 if !Ignored(syscall.SIGHUP) {
782 t.Errorf("expected SIGHUP to be ignored when explicitly ignoring it.")
783 }
784
785 parent, cancelParent := context.WithCancel(context.Background())
786 defer cancelParent()
787 c, stop := NotifyContext(parent, syscall.SIGHUP)
788 defer stop()
789
790
791 if Ignored(syscall.SIGHUP) {
792 t.Errorf("expected SIGHUP to not be ignored.")
793 }
794
795 if want, got := "signal.NotifyContext(context.Background.WithCancel, [hangup])", fmt.Sprint(c); want != got {
796 t.Errorf("c.String() = %q, wanted %q", got, want)
797 }
798
799 stop()
800 <-c.Done()
801 if got := c.Err(); got != context.Canceled {
802 t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
803 }
804 if got := context.Cause(c); got != context.Canceled {
805 t.Errorf("context.Cause(c.Err()) = %q, want %q", got, context.Canceled)
806 }
807 }
808
809 func TestNotifyContextCancelParent(t *testing.T) {
810 parent, cancelParent := context.WithCancelCause(context.Background())
811 parentCause := errors.New("parent canceled")
812 defer cancelParent(parentCause)
813 c, stop := NotifyContext(parent, syscall.SIGINT)
814 defer stop()
815
816 if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
817 t.Errorf("c.String() = %q, want %q", got, want)
818 }
819
820 cancelParent(parentCause)
821 <-c.Done()
822 if got := c.Err(); got != context.Canceled {
823 t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
824 }
825 if got := context.Cause(c); got != parentCause {
826 t.Errorf("context.Cause(c) = %q, want %q", got, parentCause)
827 }
828 }
829
830 func TestNotifyContextPrematureCancelParent(t *testing.T) {
831 parent, cancelParent := context.WithCancelCause(context.Background())
832 parentCause := errors.New("parent canceled")
833 defer cancelParent(parentCause)
834
835 cancelParent(parentCause)
836 c, stop := NotifyContext(parent, syscall.SIGINT)
837 defer stop()
838
839 if want, got := "signal.NotifyContext(context.Background.WithCancel, [interrupt])", fmt.Sprint(c); want != got {
840 t.Errorf("c.String() = %q, want %q", got, want)
841 }
842
843 <-c.Done()
844 if got := c.Err(); got != context.Canceled {
845 t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
846 }
847 if got := context.Cause(c); got != parentCause {
848 t.Errorf("context.Cause(c) = %q, want %q", got, parentCause)
849 }
850 }
851
852 func TestNotifyContextSimultaneousStop(t *testing.T) {
853 c, stop := NotifyContext(context.Background(), syscall.SIGINT)
854 defer stop()
855
856 if want, got := "signal.NotifyContext(context.Background, [interrupt])", fmt.Sprint(c); want != got {
857 t.Errorf("c.String() = %q, want %q", got, want)
858 }
859
860 var wg sync.WaitGroup
861 n := 10
862 wg.Add(n)
863 for i := 0; i < n; i++ {
864 go func() {
865 stop()
866 wg.Done()
867 }()
868 }
869 wg.Wait()
870 <-c.Done()
871 if got := c.Err(); got != context.Canceled {
872 t.Errorf("c.Err() = %q, want %q", got, context.Canceled)
873 }
874 }
875
876 func TestNotifyContextStringer(t *testing.T) {
877 parent, cancelParent := context.WithCancel(context.Background())
878 defer cancelParent()
879 c, stop := NotifyContext(parent, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM)
880 defer stop()
881
882 want := `signal.NotifyContext(context.Background.WithCancel, [hangup interrupt terminated])`
883 if got := fmt.Sprint(c); got != want {
884 t.Errorf("c.String() = %q, want %q", got, want)
885 }
886 }
887
888
889 func TestSignalTrace(t *testing.T) {
890 done := make(chan struct{})
891 quit := make(chan struct{})
892 c := make(chan os.Signal, 1)
893 Notify(c, syscall.SIGHUP)
894
895
896
897
898 go func() {
899 defer close(done)
900 defer Stop(c)
901 pid := syscall.Getpid()
902 for {
903 select {
904 case <-quit:
905 return
906 default:
907 syscall.Kill(pid, syscall.SIGHUP)
908 }
909 waitSig(t, c, syscall.SIGHUP)
910 }
911 }()
912
913 for i := 0; i < 100; i++ {
914 buf := new(bytes.Buffer)
915 if err := trace.Start(buf); err != nil {
916 t.Fatalf("[%d] failed to start tracing: %v", i, err)
917 }
918 trace.Stop()
919 size := buf.Len()
920 if size == 0 {
921 t.Fatalf("[%d] trace is empty", i)
922 }
923 }
924 close(quit)
925 <-done
926 }
927
View as plain text