github.com/geraldss/go/src@v0.0.0-20210511222824-ac7d0ebfc235/runtime/testdata/testprogcgo/eintr.go (about) 1 // Copyright 2020 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 !plan9,!windows 6 7 package main 8 9 /* 10 #include <errno.h> 11 #include <signal.h> 12 #include <string.h> 13 14 static int clearRestart(int sig) { 15 struct sigaction sa; 16 17 memset(&sa, 0, sizeof sa); 18 if (sigaction(sig, NULL, &sa) < 0) { 19 return errno; 20 } 21 sa.sa_flags &=~ SA_RESTART; 22 if (sigaction(sig, &sa, NULL) < 0) { 23 return errno; 24 } 25 return 0; 26 } 27 */ 28 import "C" 29 30 import ( 31 "bytes" 32 "errors" 33 "fmt" 34 "io" 35 "log" 36 "net" 37 "os" 38 "os/exec" 39 "sync" 40 "syscall" 41 "time" 42 ) 43 44 func init() { 45 register("EINTR", EINTR) 46 register("Block", Block) 47 } 48 49 // Test various operations when a signal handler is installed without 50 // the SA_RESTART flag. This tests that the os and net APIs handle EINTR. 51 func EINTR() { 52 if errno := C.clearRestart(C.int(syscall.SIGURG)); errno != 0 { 53 log.Fatal(syscall.Errno(errno)) 54 } 55 if errno := C.clearRestart(C.int(syscall.SIGWINCH)); errno != 0 { 56 log.Fatal(syscall.Errno(errno)) 57 } 58 if errno := C.clearRestart(C.int(syscall.SIGCHLD)); errno != 0 { 59 log.Fatal(syscall.Errno(errno)) 60 } 61 62 var wg sync.WaitGroup 63 testPipe(&wg) 64 testNet(&wg) 65 testExec(&wg) 66 wg.Wait() 67 fmt.Println("OK") 68 } 69 70 // spin does CPU bound spinning and allocating for a millisecond, 71 // to get a SIGURG. 72 //go:noinline 73 func spin() (float64, []byte) { 74 stop := time.Now().Add(time.Millisecond) 75 r1 := 0.0 76 r2 := make([]byte, 200) 77 for time.Now().Before(stop) { 78 for i := 1; i < 1e6; i++ { 79 r1 += r1 / float64(i) 80 r2 = append(r2, bytes.Repeat([]byte{byte(i)}, 100)...) 81 r2 = r2[100:] 82 } 83 } 84 return r1, r2 85 } 86 87 // winch sends a few SIGWINCH signals to the process. 88 func winch() { 89 ticker := time.NewTicker(100 * time.Microsecond) 90 defer ticker.Stop() 91 pid := syscall.Getpid() 92 for n := 10; n > 0; n-- { 93 syscall.Kill(pid, syscall.SIGWINCH) 94 <-ticker.C 95 } 96 } 97 98 // sendSomeSignals triggers a few SIGURG and SIGWINCH signals. 99 func sendSomeSignals() { 100 done := make(chan struct{}) 101 go func() { 102 spin() 103 close(done) 104 }() 105 winch() 106 <-done 107 } 108 109 // testPipe tests pipe operations. 110 func testPipe(wg *sync.WaitGroup) { 111 r, w, err := os.Pipe() 112 if err != nil { 113 log.Fatal(err) 114 } 115 if err := syscall.SetNonblock(int(r.Fd()), false); err != nil { 116 log.Fatal(err) 117 } 118 if err := syscall.SetNonblock(int(w.Fd()), false); err != nil { 119 log.Fatal(err) 120 } 121 wg.Add(2) 122 go func() { 123 defer wg.Done() 124 defer w.Close() 125 // Spin before calling Write so that the first ReadFull 126 // in the other goroutine will likely be interrupted 127 // by a signal. 128 sendSomeSignals() 129 // This Write will likely be interrupted by a signal 130 // as the other goroutine spins in the middle of reading. 131 // We write enough data that we should always fill the 132 // pipe buffer and need multiple write system calls. 133 if _, err := w.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil { 134 log.Fatal(err) 135 } 136 }() 137 go func() { 138 defer wg.Done() 139 defer r.Close() 140 b := make([]byte, 1<<20) 141 // This ReadFull will likely be interrupted by a signal, 142 // as the other goroutine spins before writing anything. 143 if _, err := io.ReadFull(r, b); err != nil { 144 log.Fatal(err) 145 } 146 // Spin after reading half the data so that the Write 147 // in the other goroutine will likely be interrupted 148 // before it completes. 149 sendSomeSignals() 150 if _, err := io.ReadFull(r, b); err != nil { 151 log.Fatal(err) 152 } 153 }() 154 } 155 156 // testNet tests network operations. 157 func testNet(wg *sync.WaitGroup) { 158 ln, err := net.Listen("tcp4", "127.0.0.1:0") 159 if err != nil { 160 if errors.Is(err, syscall.EAFNOSUPPORT) || errors.Is(err, syscall.EPROTONOSUPPORT) { 161 return 162 } 163 log.Fatal(err) 164 } 165 wg.Add(2) 166 go func() { 167 defer wg.Done() 168 defer ln.Close() 169 c, err := ln.Accept() 170 if err != nil { 171 log.Fatal(err) 172 } 173 defer c.Close() 174 cf, err := c.(*net.TCPConn).File() 175 if err != nil { 176 log.Fatal(err) 177 } 178 defer cf.Close() 179 if err := syscall.SetNonblock(int(cf.Fd()), false); err != nil { 180 log.Fatal(err) 181 } 182 // See comments in testPipe. 183 sendSomeSignals() 184 if _, err := cf.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil { 185 log.Fatal(err) 186 } 187 }() 188 go func() { 189 defer wg.Done() 190 sendSomeSignals() 191 c, err := net.Dial("tcp", ln.Addr().String()) 192 if err != nil { 193 log.Fatal(err) 194 } 195 defer c.Close() 196 cf, err := c.(*net.TCPConn).File() 197 if err != nil { 198 log.Fatal(err) 199 } 200 defer cf.Close() 201 if err := syscall.SetNonblock(int(cf.Fd()), false); err != nil { 202 log.Fatal(err) 203 } 204 // See comments in testPipe. 205 b := make([]byte, 1<<20) 206 if _, err := io.ReadFull(cf, b); err != nil { 207 log.Fatal(err) 208 } 209 sendSomeSignals() 210 if _, err := io.ReadFull(cf, b); err != nil { 211 log.Fatal(err) 212 } 213 }() 214 } 215 216 func testExec(wg *sync.WaitGroup) { 217 wg.Add(1) 218 go func() { 219 defer wg.Done() 220 cmd := exec.Command(os.Args[0], "Block") 221 stdin, err := cmd.StdinPipe() 222 if err != nil { 223 log.Fatal(err) 224 } 225 cmd.Stderr = new(bytes.Buffer) 226 cmd.Stdout = cmd.Stderr 227 if err := cmd.Start(); err != nil { 228 log.Fatal(err) 229 } 230 231 go func() { 232 sendSomeSignals() 233 stdin.Close() 234 }() 235 236 if err := cmd.Wait(); err != nil { 237 log.Fatalf("%v:\n%s", err, cmd.Stdout) 238 } 239 }() 240 } 241 242 // Block blocks until stdin is closed. 243 func Block() { 244 io.Copy(io.Discard, os.Stdin) 245 }