runtime: abort stack scan in cases that we cannot unwind the stack
[gcc.git] / libgo / go / os / timeout_test.go
1 // Copyright 2017 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 !nacl
6 // +build !js
7 // +build !plan9
8 // +build !windows
9
10 package os_test
11
12 import (
13 "fmt"
14 "internal/poll"
15 "io"
16 "io/ioutil"
17 "math/rand"
18 "os"
19 "os/signal"
20 "runtime"
21 "sync"
22 "syscall"
23 "testing"
24 "time"
25 )
26
27 func TestNonpollableDeadline(t *testing.T) {
28 // On BSD systems regular files seem to be pollable,
29 // so just run this test on Linux.
30 if runtime.GOOS != "linux" {
31 t.Skipf("skipping on %s", runtime.GOOS)
32 }
33
34 f, err := ioutil.TempFile("", "ostest")
35 if err != nil {
36 t.Fatal(err)
37 }
38 defer os.Remove(f.Name())
39 defer f.Close()
40 deadline := time.Now().Add(10 * time.Second)
41 if err := f.SetDeadline(deadline); err != os.ErrNoDeadline {
42 t.Errorf("SetDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
43 }
44 if err := f.SetReadDeadline(deadline); err != os.ErrNoDeadline {
45 t.Errorf("SetReadDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
46 }
47 if err := f.SetWriteDeadline(deadline); err != os.ErrNoDeadline {
48 t.Errorf("SetWriteDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
49 }
50 }
51
52 // noDeadline is a zero time.Time value, which cancels a deadline.
53 var noDeadline time.Time
54
55 var readTimeoutTests = []struct {
56 timeout time.Duration
57 xerrs [2]error // expected errors in transition
58 }{
59 // Tests that read deadlines work, even if there's data ready
60 // to be read.
61 {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
62
63 {50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
64 }
65
66 func TestReadTimeout(t *testing.T) {
67 t.Parallel()
68
69 r, w, err := os.Pipe()
70 if err != nil {
71 t.Fatal(err)
72 }
73 defer r.Close()
74 defer w.Close()
75
76 if _, err := w.Write([]byte("READ TIMEOUT TEST")); err != nil {
77 t.Fatal(err)
78 }
79
80 for i, tt := range readTimeoutTests {
81 if err := r.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
82 t.Fatalf("#%d: %v", i, err)
83 }
84 var b [1]byte
85 for j, xerr := range tt.xerrs {
86 for {
87 n, err := r.Read(b[:])
88 if xerr != nil {
89 if !os.IsTimeout(err) {
90 t.Fatalf("#%d/%d: %v", i, j, err)
91 }
92 }
93 if err == nil {
94 time.Sleep(tt.timeout / 3)
95 continue
96 }
97 if n != 0 {
98 t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
99 }
100 break
101 }
102 }
103 }
104 }
105
106 func TestReadTimeoutMustNotReturn(t *testing.T) {
107 t.Parallel()
108
109 r, w, err := os.Pipe()
110 if err != nil {
111 t.Fatal(err)
112 }
113 defer r.Close()
114 defer w.Close()
115
116 max := time.NewTimer(100 * time.Millisecond)
117 defer max.Stop()
118 ch := make(chan error)
119 go func() {
120 if err := r.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
121 t.Error(err)
122 }
123 if err := r.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil {
124 t.Error(err)
125 }
126 if err := r.SetReadDeadline(noDeadline); err != nil {
127 t.Error(err)
128 }
129 var b [1]byte
130 _, err := r.Read(b[:])
131 ch <- err
132 }()
133
134 select {
135 case err := <-ch:
136 t.Fatalf("expected Read to not return, but it returned with %v", err)
137 case <-max.C:
138 w.Close()
139 err := <-ch // wait for tester goroutine to stop
140 if os.IsTimeout(err) {
141 t.Fatal(err)
142 }
143 }
144 }
145
146 var writeTimeoutTests = []struct {
147 timeout time.Duration
148 xerrs [2]error // expected errors in transition
149 }{
150 // Tests that write deadlines work, even if there's buffer
151 // space available to write.
152 {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}},
153
154 {10 * time.Millisecond, [2]error{nil, poll.ErrTimeout}},
155 }
156
157 func TestWriteTimeout(t *testing.T) {
158 t.Parallel()
159
160 for i, tt := range writeTimeoutTests {
161 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
162 r, w, err := os.Pipe()
163 if err != nil {
164 t.Fatal(err)
165 }
166 defer r.Close()
167 defer w.Close()
168
169 if err := w.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
170 t.Fatalf("%v", err)
171 }
172 for j, xerr := range tt.xerrs {
173 for {
174 n, err := w.Write([]byte("WRITE TIMEOUT TEST"))
175 if xerr != nil {
176 if !os.IsTimeout(err) {
177 t.Fatalf("%d: %v", j, err)
178 }
179 }
180 if err == nil {
181 time.Sleep(tt.timeout / 3)
182 continue
183 }
184 if n != 0 {
185 t.Fatalf("%d: wrote %d; want 0", j, n)
186 }
187 break
188 }
189 }
190 })
191 }
192 }
193
194 func TestWriteTimeoutMustNotReturn(t *testing.T) {
195 t.Parallel()
196
197 r, w, err := os.Pipe()
198 if err != nil {
199 t.Fatal(err)
200 }
201 defer r.Close()
202 defer w.Close()
203
204 max := time.NewTimer(100 * time.Millisecond)
205 defer max.Stop()
206 ch := make(chan error)
207 go func() {
208 if err := w.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
209 t.Error(err)
210 }
211 if err := w.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil {
212 t.Error(err)
213 }
214 if err := w.SetWriteDeadline(noDeadline); err != nil {
215 t.Error(err)
216 }
217 var b [1]byte
218 for {
219 if _, err := w.Write(b[:]); err != nil {
220 ch <- err
221 break
222 }
223 }
224 }()
225
226 select {
227 case err := <-ch:
228 t.Fatalf("expected Write to not return, but it returned with %v", err)
229 case <-max.C:
230 r.Close()
231 err := <-ch // wait for tester goroutine to stop
232 if os.IsTimeout(err) {
233 t.Fatal(err)
234 }
235 }
236 }
237
238 func timeoutReader(r *os.File, d, min, max time.Duration, ch chan<- error) {
239 var err error
240 defer func() { ch <- err }()
241
242 t0 := time.Now()
243 if err = r.SetReadDeadline(time.Now().Add(d)); err != nil {
244 return
245 }
246 b := make([]byte, 256)
247 var n int
248 n, err = r.Read(b)
249 t1 := time.Now()
250 if n != 0 || err == nil || !os.IsTimeout(err) {
251 err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
252 return
253 }
254 if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
255 err = fmt.Errorf("Read took %s; expected %s", dt, d)
256 return
257 }
258 }
259
260 func TestReadTimeoutFluctuation(t *testing.T) {
261 t.Parallel()
262
263 r, w, err := os.Pipe()
264 if err != nil {
265 t.Fatal(err)
266 }
267 defer r.Close()
268 defer w.Close()
269
270 max := time.NewTimer(time.Second)
271 defer max.Stop()
272 ch := make(chan error)
273 go timeoutReader(r, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
274
275 select {
276 case <-max.C:
277 t.Fatal("Read took over 1s; expected 0.1s")
278 case err := <-ch:
279 if !os.IsTimeout(err) {
280 t.Fatal(err)
281 }
282 }
283 }
284
285 func timeoutWriter(w *os.File, d, min, max time.Duration, ch chan<- error) {
286 var err error
287 defer func() { ch <- err }()
288
289 t0 := time.Now()
290 if err = w.SetWriteDeadline(time.Now().Add(d)); err != nil {
291 return
292 }
293 var n int
294 for {
295 n, err = w.Write([]byte("TIMEOUT WRITER"))
296 if err != nil {
297 break
298 }
299 }
300 t1 := time.Now()
301 if err == nil || !os.IsTimeout(err) {
302 err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err)
303 return
304 }
305 if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
306 err = fmt.Errorf("Write took %s; expected %s", dt, d)
307 return
308 }
309 }
310
311 func TestWriteTimeoutFluctuation(t *testing.T) {
312 t.Parallel()
313
314 r, w, err := os.Pipe()
315 if err != nil {
316 t.Fatal(err)
317 }
318 defer r.Close()
319 defer w.Close()
320
321 d := time.Second
322 max := time.NewTimer(d)
323 defer max.Stop()
324 ch := make(chan error)
325 go timeoutWriter(w, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
326
327 select {
328 case <-max.C:
329 t.Fatalf("Write took over %v; expected 0.1s", d)
330 case err := <-ch:
331 if !os.IsTimeout(err) {
332 t.Fatal(err)
333 }
334 }
335 }
336
337 func TestVariousDeadlines(t *testing.T) {
338 t.Parallel()
339 testVariousDeadlines(t)
340 }
341
342 func TestVariousDeadlines1Proc(t *testing.T) {
343 // Cannot use t.Parallel - modifies global GOMAXPROCS.
344 if testing.Short() {
345 t.Skip("skipping in short mode")
346 }
347 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
348 testVariousDeadlines(t)
349 }
350
351 func TestVariousDeadlines4Proc(t *testing.T) {
352 // Cannot use t.Parallel - modifies global GOMAXPROCS.
353 if testing.Short() {
354 t.Skip("skipping in short mode")
355 }
356 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
357 testVariousDeadlines(t)
358 }
359
360 type neverEnding byte
361
362 func (b neverEnding) Read(p []byte) (int, error) {
363 for i := range p {
364 p[i] = byte(b)
365 }
366 return len(p), nil
367 }
368
369 func testVariousDeadlines(t *testing.T) {
370 type result struct {
371 n int64
372 err error
373 d time.Duration
374 }
375
376 handler := func(w *os.File, pasvch chan result) {
377 // The writer, with no timeouts of its own,
378 // sending bytes to clients as fast as it can.
379 t0 := time.Now()
380 n, err := io.Copy(w, neverEnding('a'))
381 dt := time.Since(t0)
382 pasvch <- result{n, err, dt}
383 }
384
385 for _, timeout := range []time.Duration{
386 1 * time.Nanosecond,
387 2 * time.Nanosecond,
388 5 * time.Nanosecond,
389 50 * time.Nanosecond,
390 100 * time.Nanosecond,
391 200 * time.Nanosecond,
392 500 * time.Nanosecond,
393 750 * time.Nanosecond,
394 1 * time.Microsecond,
395 5 * time.Microsecond,
396 25 * time.Microsecond,
397 250 * time.Microsecond,
398 500 * time.Microsecond,
399 1 * time.Millisecond,
400 5 * time.Millisecond,
401 100 * time.Millisecond,
402 250 * time.Millisecond,
403 500 * time.Millisecond,
404 1 * time.Second,
405 } {
406 numRuns := 3
407 if testing.Short() {
408 numRuns = 1
409 if timeout > 500*time.Microsecond {
410 continue
411 }
412 }
413 for run := 0; run < numRuns; run++ {
414 t.Run(fmt.Sprintf("%v-%d", timeout, run+1), func(t *testing.T) {
415 r, w, err := os.Pipe()
416 if err != nil {
417 t.Fatal(err)
418 }
419 defer r.Close()
420 defer w.Close()
421
422 pasvch := make(chan result)
423 go handler(w, pasvch)
424
425 tooLong := 5 * time.Second
426 max := time.NewTimer(tooLong)
427 defer max.Stop()
428 actvch := make(chan result)
429 go func() {
430 t0 := time.Now()
431 if err := r.SetDeadline(t0.Add(timeout)); err != nil {
432 t.Error(err)
433 }
434 n, err := io.Copy(ioutil.Discard, r)
435 dt := time.Since(t0)
436 r.Close()
437 actvch <- result{n, err, dt}
438 }()
439
440 select {
441 case res := <-actvch:
442 if os.IsTimeout(res.err) {
443 t.Logf("good client timeout after %v, reading %d bytes", res.d, res.n)
444 } else {
445 t.Fatalf("client Copy = %d, %v; want timeout", res.n, res.err)
446 }
447 case <-max.C:
448 t.Fatalf("timeout (%v) waiting for client to timeout (%v) reading", tooLong, timeout)
449 }
450
451 select {
452 case res := <-pasvch:
453 t.Logf("writer in %v wrote %d: %v", res.d, res.n, res.err)
454 case <-max.C:
455 t.Fatalf("timeout waiting for writer to finish writing")
456 }
457 })
458 }
459 }
460 }
461
462 func TestReadWriteDeadlineRace(t *testing.T) {
463 t.Parallel()
464
465 N := 1000
466 if testing.Short() {
467 N = 50
468 }
469
470 r, w, err := os.Pipe()
471 if err != nil {
472 t.Fatal(err)
473 }
474 defer r.Close()
475 defer w.Close()
476
477 var wg sync.WaitGroup
478 wg.Add(3)
479 go func() {
480 defer wg.Done()
481 tic := time.NewTicker(2 * time.Microsecond)
482 defer tic.Stop()
483 for i := 0; i < N; i++ {
484 if err := r.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
485 break
486 }
487 if err := w.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
488 break
489 }
490 <-tic.C
491 }
492 }()
493 go func() {
494 defer wg.Done()
495 var b [1]byte
496 for i := 0; i < N; i++ {
497 _, err := r.Read(b[:])
498 if err != nil && !os.IsTimeout(err) {
499 t.Error("Read returned non-timeout error", err)
500 }
501 }
502 }()
503 go func() {
504 defer wg.Done()
505 var b [1]byte
506 for i := 0; i < N; i++ {
507 _, err := w.Write(b[:])
508 if err != nil && !os.IsTimeout(err) {
509 t.Error("Write returned non-timeout error", err)
510 }
511 }
512 }()
513 wg.Wait() // wait for tester goroutine to stop
514 }
515
516 // TestRacyRead tests that it is safe to mutate the input Read buffer
517 // immediately after cancelation has occurred.
518 func TestRacyRead(t *testing.T) {
519 t.Parallel()
520
521 r, w, err := os.Pipe()
522 if err != nil {
523 t.Fatal(err)
524 }
525 defer r.Close()
526 defer w.Close()
527
528 var wg sync.WaitGroup
529 defer wg.Wait()
530
531 go io.Copy(w, rand.New(rand.NewSource(0)))
532
533 r.SetReadDeadline(time.Now().Add(time.Millisecond))
534 for i := 0; i < 10; i++ {
535 wg.Add(1)
536 go func() {
537 defer wg.Done()
538
539 b1 := make([]byte, 1024)
540 b2 := make([]byte, 1024)
541 for j := 0; j < 100; j++ {
542 _, err := r.Read(b1)
543 copy(b1, b2) // Mutate b1 to trigger potential race
544 if err != nil {
545 if !os.IsTimeout(err) {
546 t.Error(err)
547 }
548 r.SetReadDeadline(time.Now().Add(time.Millisecond))
549 }
550 }
551 }()
552 }
553 }
554
555 // TestRacyWrite tests that it is safe to mutate the input Write buffer
556 // immediately after cancelation has occurred.
557 func TestRacyWrite(t *testing.T) {
558 t.Parallel()
559
560 r, w, err := os.Pipe()
561 if err != nil {
562 t.Fatal(err)
563 }
564 defer r.Close()
565 defer w.Close()
566
567 var wg sync.WaitGroup
568 defer wg.Wait()
569
570 go io.Copy(ioutil.Discard, r)
571
572 w.SetWriteDeadline(time.Now().Add(time.Millisecond))
573 for i := 0; i < 10; i++ {
574 wg.Add(1)
575 go func() {
576 defer wg.Done()
577
578 b1 := make([]byte, 1024)
579 b2 := make([]byte, 1024)
580 for j := 0; j < 100; j++ {
581 _, err := w.Write(b1)
582 copy(b1, b2) // Mutate b1 to trigger potential race
583 if err != nil {
584 if !os.IsTimeout(err) {
585 t.Error(err)
586 }
587 w.SetWriteDeadline(time.Now().Add(time.Millisecond))
588 }
589 }
590 }()
591 }
592 }
593
594 // Closing a TTY while reading from it should not hang. Issue 23943.
595 func TestTTYClose(t *testing.T) {
596 // Ignore SIGTTIN in case we are running in the background.
597 signal.Ignore(syscall.SIGTTIN)
598 defer signal.Reset(syscall.SIGTTIN)
599
600 f, err := os.Open("/dev/tty")
601 if err != nil {
602 t.Skipf("skipping because opening /dev/tty failed: %v", err)
603 }
604
605 go func() {
606 var buf [1]byte
607 f.Read(buf[:])
608 }()
609
610 // Give the goroutine a chance to enter the read.
611 // It doesn't matter much if it occasionally fails to do so,
612 // we won't be testing what we want to test but the test will pass.
613 time.Sleep(time.Millisecond)
614
615 c := make(chan bool)
616 go func() {
617 defer close(c)
618 f.Close()
619 }()
620
621 select {
622 case <-c:
623 case <-time.After(time.Second):
624 t.Error("timed out waiting for close")
625 }
626
627 // On some systems the goroutines may now be hanging.
628 // There's not much we can do about that.
629 }