1
2
3
4
5
6
7
8
9
10
11
12 package main
13
14 import (
15 "fmt"
16 "io"
17 "os"
18 "os/exec"
19 "os/signal"
20 "runtime"
21 "sync"
22 "syscall"
23 "time"
24 )
25
26 func init() {
27 register("SignalDuringExec", SignalDuringExec)
28 register("SignalDuringExecPgrp", SignalDuringExecPgrp)
29 register("Nop", Nop)
30 }
31
32 func SignalDuringExec() {
33
34 cmd := exec.Command(os.Args[0], "SignalDuringExecPgrp")
35 cmd.Stdout = os.Stdout
36 cmd.Stderr = os.Stderr
37 cmd.SysProcAttr = &syscall.SysProcAttr{
38 Setpgid: true,
39 }
40
41
42
43 rp, wp, err := os.Pipe()
44 if err != nil {
45 fmt.Printf("Failed to create pipe: %v", err)
46 return
47 }
48 cmd.ExtraFiles = []*os.File{rp}
49
50
51 if err := cmd.Run(); err != nil {
52 fmt.Printf("Run failed: %v", err)
53 }
54
55
56
57
58 runtime.KeepAlive(wp)
59 }
60
61 func SignalDuringExecPgrp() {
62
63 f := os.NewFile(3, "pipe")
64 go func() {
65
66
67
68 io.ReadAll(f)
69 os.Exit(1)
70 }()
71
72
73 pgrp := syscall.Getpgrp()
74
75 const tries = 10
76
77 var wg sync.WaitGroup
78 c := make(chan os.Signal, tries)
79 signal.Notify(c, syscall.SIGWINCH)
80 wg.Add(1)
81 go func() {
82 defer wg.Done()
83 for range c {
84 }
85 }()
86
87 for i := 0; i < tries; i++ {
88 time.Sleep(time.Microsecond)
89 wg.Add(2)
90 go func() {
91 defer wg.Done()
92 cmd := exec.Command(os.Args[0], "Nop")
93 cmd.Stdout = os.Stdout
94 cmd.Stderr = os.Stderr
95 if err := cmd.Run(); err != nil {
96 fmt.Printf("Start failed: %v", err)
97 }
98 }()
99 go func() {
100 defer wg.Done()
101 syscall.Kill(-pgrp, syscall.SIGWINCH)
102 }()
103 }
104
105 signal.Stop(c)
106 close(c)
107 wg.Wait()
108
109 fmt.Println("OK")
110 }
111
112 func Nop() {
113
114 }
115
View as plain text