Skip to content

Commit ee0d40c

Browse files
author
Bryan C. Mills
committed
runtime: reduce timing sensitivity in TestEINTR
- Don't assume that a process interrupted at 100μs intervals will have enough remaining time to make progress. (Stop sending signals in between signal storms to allow the process to quiesce.) - Don't assume that a child process that spins for 1ms will block long enough for the parent process to receive signals or make meaningful progress. (Instead, have the child block indefinitely, and unblock it explicitly after the signal storm.) For golang#39043 Updates golang#22838 Updates golang#20400 Change-Id: I85cba23498c346a637e6cfe8684ca0c478562a93 Reviewed-on: https://go-review.googlesource.com/c/go/+/233877 Run-TryBot: Bryan C. Mills <bcmills@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
1 parent 810c27e commit ee0d40c

File tree

1 file changed

+48
-22
lines changed
  • src/runtime/testdata/testprogcgo

1 file changed

+48
-22
lines changed

src/runtime/testdata/testprogcgo/eintr.go

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,15 @@ import (
3636
"net"
3737
"os"
3838
"os/exec"
39+
"os/signal"
3940
"sync"
4041
"syscall"
4142
"time"
4243
)
4344

4445
func init() {
4546
register("EINTR", EINTR)
46-
register("Nop", Nop)
47+
register("Block", Block)
4748
}
4849

4950
// Test various operations when a signal handler is installed without
@@ -59,13 +60,6 @@ func EINTR() {
5960
log.Fatal(syscall.Errno(errno))
6061
}
6162

62-
// Send ourselves SIGWINCH regularly.
63-
go func() {
64-
for range time.Tick(100 * time.Microsecond) {
65-
syscall.Kill(0, syscall.SIGWINCH)
66-
}
67-
}()
68-
6963
var wg sync.WaitGroup
7064
testPipe(&wg)
7165
testNet(&wg)
@@ -90,6 +84,22 @@ func spin() (float64, [][]byte) {
9084
return r1, r2
9185
}
9286

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+
for n := 10; n > 0; n-- {
92+
syscall.Kill(0, syscall.SIGWINCH)
93+
<-ticker.C
94+
}
95+
}
96+
97+
// sendSomeSignals triggers a few SIGURG and SIGWINCH signals.
98+
func sendSomeSignals() {
99+
spin()
100+
winch()
101+
}
102+
93103
// testPipe tests pipe operations.
94104
func testPipe(wg *sync.WaitGroup) {
95105
r, w, err := os.Pipe()
@@ -109,19 +119,19 @@ func testPipe(wg *sync.WaitGroup) {
109119
// Spin before calling Write so that the first ReadFull
110120
// in the other goroutine will likely be interrupted
111121
// by a signal.
112-
spin()
122+
sendSomeSignals()
113123
// This Write will likely be interrupted by a signal
114124
// as the other goroutine spins in the middle of reading.
115125
// We write enough data that we should always fill the
116126
// pipe buffer and need multiple write system calls.
117-
if _, err := w.Write(bytes.Repeat([]byte{0}, 2 << 20)); err != nil {
127+
if _, err := w.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil {
118128
log.Fatal(err)
119129
}
120130
}()
121131
go func() {
122132
defer wg.Done()
123133
defer r.Close()
124-
b := make([]byte, 1 << 20)
134+
b := make([]byte, 1<<20)
125135
// This ReadFull will likely be interrupted by a signal,
126136
// as the other goroutine spins before writing anything.
127137
if _, err := io.ReadFull(r, b); err != nil {
@@ -130,7 +140,7 @@ func testPipe(wg *sync.WaitGroup) {
130140
// Spin after reading half the data so that the Write
131141
// in the other goroutine will likely be interrupted
132142
// before it completes.
133-
spin()
143+
sendSomeSignals()
134144
if _, err := io.ReadFull(r, b); err != nil {
135145
log.Fatal(err)
136146
}
@@ -164,14 +174,14 @@ func testNet(wg *sync.WaitGroup) {
164174
log.Fatal(err)
165175
}
166176
// See comments in testPipe.
167-
spin()
168-
if _, err := cf.Write(bytes.Repeat([]byte{0}, 2 << 20)); err != nil {
177+
sendSomeSignals()
178+
if _, err := cf.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil {
169179
log.Fatal(err)
170180
}
171181
}()
172182
go func() {
173183
defer wg.Done()
174-
spin()
184+
sendSomeSignals()
175185
c, err := net.Dial("tcp", ln.Addr().String())
176186
if err != nil {
177187
log.Fatal(err)
@@ -186,11 +196,11 @@ func testNet(wg *sync.WaitGroup) {
186196
log.Fatal(err)
187197
}
188198
// See comments in testPipe.
189-
b := make([]byte, 1 << 20)
199+
b := make([]byte, 1<<20)
190200
if _, err := io.ReadFull(cf, b); err != nil {
191201
log.Fatal(err)
192202
}
193-
spin()
203+
sendSomeSignals()
194204
if _, err := io.ReadFull(cf, b); err != nil {
195205
log.Fatal(err)
196206
}
@@ -201,14 +211,30 @@ func testExec(wg *sync.WaitGroup) {
201211
wg.Add(1)
202212
go func() {
203213
defer wg.Done()
204-
if err := exec.Command(os.Args[0], "Nop").Run(); err != nil {
214+
cmd := exec.Command(os.Args[0], "Block")
215+
cmd.Stderr = new(bytes.Buffer)
216+
cmd.Stdout = cmd.Stderr
217+
if err := cmd.Start(); err != nil {
205218
log.Fatal(err)
206219
}
220+
221+
go func() {
222+
sendSomeSignals()
223+
if err := cmd.Process.Signal(os.Interrupt); err != nil {
224+
panic(err)
225+
}
226+
}()
227+
228+
if err := cmd.Wait(); err != nil {
229+
log.Fatalf("%v:\n%s", err, cmd.Stdout)
230+
}
207231
}()
208232
}
209233

210-
// Nop just sleeps for a bit. This is used to test interrupts while waiting
211-
// for a child.
212-
func Nop() {
213-
time.Sleep(time.Millisecond)
234+
// Block blocks until the process receives os.Interrupt.
235+
func Block() {
236+
c := make(chan os.Signal, 1)
237+
signal.Notify(c, os.Interrupt)
238+
defer signal.Stop(c)
239+
<-c
214240
}

0 commit comments

Comments
 (0)