Source file
src/os/timeout_test.go
1
2
3
4
5
6
7 package os_test
8
9 import (
10 "fmt"
11 "io"
12 "math/rand"
13 "os"
14 "os/signal"
15 "runtime"
16 "sync"
17 "syscall"
18 "testing"
19 "time"
20 )
21
22 func TestNonpollableDeadline(t *testing.T) {
23
24
25 if runtime.GOOS != "linux" {
26 t.Skipf("skipping on %s", runtime.GOOS)
27 }
28 t.Parallel()
29
30 f, err := os.CreateTemp("", "ostest")
31 if err != nil {
32 t.Fatal(err)
33 }
34 defer os.Remove(f.Name())
35 defer f.Close()
36 deadline := time.Now().Add(10 * time.Second)
37 if err := f.SetDeadline(deadline); err != os.ErrNoDeadline {
38 t.Errorf("SetDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
39 }
40 if err := f.SetReadDeadline(deadline); err != os.ErrNoDeadline {
41 t.Errorf("SetReadDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
42 }
43 if err := f.SetWriteDeadline(deadline); err != os.ErrNoDeadline {
44 t.Errorf("SetWriteDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline)
45 }
46 }
47
48
49 var noDeadline time.Time
50
51 var readTimeoutTests = []struct {
52 timeout time.Duration
53 xerrs [2]error
54 }{
55
56
57 {-5 * time.Second, [2]error{os.ErrDeadlineExceeded, os.ErrDeadlineExceeded}},
58
59 {50 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
60 }
61
62
63 func TestReadTimeout(t *testing.T) {
64 t.Parallel()
65
66 r, w, err := os.Pipe()
67 if err != nil {
68 t.Fatal(err)
69 }
70 defer r.Close()
71 defer w.Close()
72
73 if _, err := w.Write([]byte("READ TIMEOUT TEST")); err != nil {
74 t.Fatal(err)
75 }
76
77 for i, tt := range readTimeoutTests {
78 if err := r.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
79 t.Fatalf("#%d: %v", i, err)
80 }
81 var b [1]byte
82 for j, xerr := range tt.xerrs {
83 for {
84 n, err := r.Read(b[:])
85 if xerr != nil {
86 if !isDeadlineExceeded(err) {
87 t.Fatalf("#%d/%d: %v", i, j, err)
88 }
89 }
90 if err == nil {
91 time.Sleep(tt.timeout / 3)
92 continue
93 }
94 if n != 0 {
95 t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
96 }
97 break
98 }
99 }
100 }
101 }
102
103
104 func TestReadTimeoutMustNotReturn(t *testing.T) {
105 t.Parallel()
106
107 r, w, err := os.Pipe()
108 if err != nil {
109 t.Fatal(err)
110 }
111 defer r.Close()
112 defer w.Close()
113
114 max := time.NewTimer(100 * time.Millisecond)
115 defer max.Stop()
116 ch := make(chan error)
117 go func() {
118 if err := r.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
119 t.Error(err)
120 }
121 if err := r.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil {
122 t.Error(err)
123 }
124 if err := r.SetReadDeadline(noDeadline); err != nil {
125 t.Error(err)
126 }
127 var b [1]byte
128 _, err := r.Read(b[:])
129 ch <- err
130 }()
131
132 select {
133 case err := <-ch:
134 t.Fatalf("expected Read to not return, but it returned with %v", err)
135 case <-max.C:
136 w.Close()
137 err := <-ch
138 if os.IsTimeout(err) {
139 t.Fatal(err)
140 }
141 }
142 }
143
144 var writeTimeoutTests = []struct {
145 timeout time.Duration
146 xerrs [2]error
147 }{
148
149
150 {-5 * time.Second, [2]error{os.ErrDeadlineExceeded, os.ErrDeadlineExceeded}},
151
152 {10 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}},
153 }
154
155
156 func TestWriteTimeout(t *testing.T) {
157 t.Parallel()
158
159 for i, tt := range writeTimeoutTests {
160 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
161 r, w, err := os.Pipe()
162 if err != nil {
163 t.Fatal(err)
164 }
165 defer r.Close()
166 defer w.Close()
167
168 if err := w.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
169 t.Fatalf("%v", err)
170 }
171 for j, xerr := range tt.xerrs {
172 for {
173 n, err := w.Write([]byte("WRITE TIMEOUT TEST"))
174 if xerr != nil {
175 if !isDeadlineExceeded(err) {
176 t.Fatalf("%d: %v", j, err)
177 }
178 }
179 if err == nil {
180 time.Sleep(tt.timeout / 3)
181 continue
182 }
183 if n != 0 {
184 t.Fatalf("%d: wrote %d; want 0", j, n)
185 }
186 break
187 }
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
232 if os.IsTimeout(err) {
233 t.Fatal(err)
234 }
235 }
236 }
237
238 const (
239
240
241
242
243
244
245 minDynamicTimeout = 1 * time.Millisecond
246
247
248
249
250
251
252
253 maxDynamicTimeout = 4 * time.Second
254 )
255
256
257
258 func timeoutUpperBound(d time.Duration) time.Duration {
259 switch runtime.GOOS {
260 case "openbsd", "netbsd":
261
262
263
264
265
266
267
268 return d * 3 / 2
269 }
270
271
272 return d * 11 / 10
273 }
274
275
276
277 func nextTimeout(actual time.Duration) (next time.Duration, ok bool) {
278 if actual >= maxDynamicTimeout {
279 return maxDynamicTimeout, false
280 }
281
282
283
284 next = actual * 5 / 4
285 return min(next, maxDynamicTimeout), true
286 }
287
288
289 func TestReadTimeoutFluctuation(t *testing.T) {
290 t.Parallel()
291
292 r, w, err := os.Pipe()
293 if err != nil {
294 t.Fatal(err)
295 }
296 defer r.Close()
297 defer w.Close()
298
299 d := minDynamicTimeout
300 b := make([]byte, 256)
301 for {
302 t.Logf("SetReadDeadline(+%v)", d)
303 t0 := time.Now()
304 deadline := t0.Add(d)
305 if err = r.SetReadDeadline(deadline); err != nil {
306 t.Fatalf("SetReadDeadline(%v): %v", deadline, err)
307 }
308 var n int
309 n, err = r.Read(b)
310 t1 := time.Now()
311
312 if n != 0 || err == nil || !isDeadlineExceeded(err) {
313 t.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
314 }
315
316 actual := t1.Sub(t0)
317 if t1.Before(deadline) {
318 t.Errorf("Read took %s; expected at least %s", actual, d)
319 }
320 if t.Failed() {
321 return
322 }
323 if want := timeoutUpperBound(d); actual > want {
324 next, ok := nextTimeout(actual)
325 if !ok {
326 t.Fatalf("Read took %s; expected at most %v", actual, want)
327 }
328
329
330 t.Logf("Read took %s (expected %s); trying with longer timeout", actual, d)
331 d = next
332 continue
333 }
334
335 break
336 }
337 }
338
339
340 func TestWriteTimeoutFluctuation(t *testing.T) {
341 t.Parallel()
342
343 r, w, err := os.Pipe()
344 if err != nil {
345 t.Fatal(err)
346 }
347 defer r.Close()
348 defer w.Close()
349
350 d := minDynamicTimeout
351 for {
352 t.Logf("SetWriteDeadline(+%v)", d)
353 t0 := time.Now()
354 deadline := t0.Add(d)
355 if err := w.SetWriteDeadline(deadline); err != nil {
356 t.Fatalf("SetWriteDeadline(%v): %v", deadline, err)
357 }
358 var n int64
359 var err error
360 for {
361 var dn int
362 dn, err = w.Write([]byte("TIMEOUT TRANSMITTER"))
363 n += int64(dn)
364 if err != nil {
365 break
366 }
367 }
368 t1 := time.Now()
369
370 if !isDeadlineExceeded(err) {
371 t.Fatalf("Write did not return (any, timeout): (%d, %v)", n, err)
372 }
373
374 actual := t1.Sub(t0)
375 if t1.Before(deadline) {
376 t.Errorf("Write took %s; expected at least %s", actual, d)
377 }
378 if t.Failed() {
379 return
380 }
381 if want := timeoutUpperBound(d); actual > want {
382 if n > 0 {
383
384
385
386
387 t.Logf("Wrote %d bytes into send buffer; retrying until buffer is full", n)
388 if d <= maxDynamicTimeout/2 {
389
390
391
392 d *= 2
393 }
394 } else if next, ok := nextTimeout(actual); !ok {
395 t.Fatalf("Write took %s; expected at most %s", actual, want)
396 } else {
397
398
399 t.Logf("Write took %s (expected %s); trying with longer timeout", actual, d)
400 d = next
401 }
402 continue
403 }
404
405 break
406 }
407 }
408
409
410 func TestVariousDeadlines(t *testing.T) {
411 t.Parallel()
412 testVariousDeadlines(t)
413 }
414
415
416 func TestVariousDeadlines1Proc(t *testing.T) {
417
418 if testing.Short() {
419 t.Skip("skipping in short mode")
420 }
421 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
422 testVariousDeadlines(t)
423 }
424
425
426 func TestVariousDeadlines4Proc(t *testing.T) {
427
428 if testing.Short() {
429 t.Skip("skipping in short mode")
430 }
431 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
432 testVariousDeadlines(t)
433 }
434
435 type neverEnding byte
436
437 func (b neverEnding) Read(p []byte) (int, error) {
438 for i := range p {
439 p[i] = byte(b)
440 }
441 return len(p), nil
442 }
443
444 func testVariousDeadlines(t *testing.T) {
445 type result struct {
446 n int64
447 err error
448 d time.Duration
449 }
450
451 handler := func(w *os.File, pasvch chan result) {
452
453
454 t0 := time.Now()
455 n, err := io.Copy(w, neverEnding('a'))
456 dt := time.Since(t0)
457 pasvch <- result{n, err, dt}
458 }
459
460 for _, timeout := range []time.Duration{
461 1 * time.Nanosecond,
462 2 * time.Nanosecond,
463 5 * time.Nanosecond,
464 50 * time.Nanosecond,
465 100 * time.Nanosecond,
466 200 * time.Nanosecond,
467 500 * time.Nanosecond,
468 750 * time.Nanosecond,
469 1 * time.Microsecond,
470 5 * time.Microsecond,
471 25 * time.Microsecond,
472 250 * time.Microsecond,
473 500 * time.Microsecond,
474 1 * time.Millisecond,
475 5 * time.Millisecond,
476 100 * time.Millisecond,
477 250 * time.Millisecond,
478 500 * time.Millisecond,
479 1 * time.Second,
480 } {
481 numRuns := 3
482 if testing.Short() {
483 numRuns = 1
484 if timeout > 500*time.Microsecond {
485 continue
486 }
487 }
488 for run := 0; run < numRuns; run++ {
489 t.Run(fmt.Sprintf("%v-%d", timeout, run+1), func(t *testing.T) {
490 r, w, err := os.Pipe()
491 if err != nil {
492 t.Fatal(err)
493 }
494 defer r.Close()
495 defer w.Close()
496
497 pasvch := make(chan result)
498 go handler(w, pasvch)
499
500 tooLong := 5 * time.Second
501 max := time.NewTimer(tooLong)
502 defer max.Stop()
503 actvch := make(chan result)
504 go func() {
505 t0 := time.Now()
506 if err := r.SetDeadline(t0.Add(timeout)); err != nil {
507 t.Error(err)
508 }
509 n, err := io.Copy(io.Discard, r)
510 dt := time.Since(t0)
511 r.Close()
512 actvch <- result{n, err, dt}
513 }()
514
515 select {
516 case res := <-actvch:
517 if !isDeadlineExceeded(err) {
518 t.Logf("good client timeout after %v, reading %d bytes", res.d, res.n)
519 } else {
520 t.Fatalf("client Copy = %d, %v; want timeout", res.n, res.err)
521 }
522 case <-max.C:
523 t.Fatalf("timeout (%v) waiting for client to timeout (%v) reading", tooLong, timeout)
524 }
525
526 select {
527 case res := <-pasvch:
528 t.Logf("writer in %v wrote %d: %v", res.d, res.n, res.err)
529 case <-max.C:
530 t.Fatalf("timeout waiting for writer to finish writing")
531 }
532 })
533 }
534 }
535 }
536
537
538 func TestReadWriteDeadlineRace(t *testing.T) {
539 t.Parallel()
540
541 N := 1000
542 if testing.Short() {
543 N = 50
544 }
545
546 r, w, err := os.Pipe()
547 if err != nil {
548 t.Fatal(err)
549 }
550 defer r.Close()
551 defer w.Close()
552
553 var wg sync.WaitGroup
554 wg.Add(3)
555 go func() {
556 defer wg.Done()
557 tic := time.NewTicker(2 * time.Microsecond)
558 defer tic.Stop()
559 for i := 0; i < N; i++ {
560 if err := r.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
561 break
562 }
563 if err := w.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
564 break
565 }
566 <-tic.C
567 }
568 }()
569 go func() {
570 defer wg.Done()
571 var b [1]byte
572 for i := 0; i < N; i++ {
573 _, err := r.Read(b[:])
574 if err != nil && !isDeadlineExceeded(err) {
575 t.Error("Read returned non-timeout error", err)
576 }
577 }
578 }()
579 go func() {
580 defer wg.Done()
581 var b [1]byte
582 for i := 0; i < N; i++ {
583 _, err := w.Write(b[:])
584 if err != nil && !isDeadlineExceeded(err) {
585 t.Error("Write returned non-timeout error", err)
586 }
587 }
588 }()
589 wg.Wait()
590 }
591
592
593
594 func TestRacyRead(t *testing.T) {
595 t.Parallel()
596
597 r, w, err := os.Pipe()
598 if err != nil {
599 t.Fatal(err)
600 }
601 defer r.Close()
602 defer w.Close()
603
604 var wg sync.WaitGroup
605 defer wg.Wait()
606
607 go io.Copy(w, rand.New(rand.NewSource(0)))
608
609 r.SetReadDeadline(time.Now().Add(time.Millisecond))
610 for i := 0; i < 10; i++ {
611 wg.Add(1)
612 go func() {
613 defer wg.Done()
614
615 b1 := make([]byte, 1024)
616 b2 := make([]byte, 1024)
617 for j := 0; j < 100; j++ {
618 _, err := r.Read(b1)
619 copy(b1, b2)
620 if err != nil {
621 if !isDeadlineExceeded(err) {
622 t.Error(err)
623 }
624 r.SetReadDeadline(time.Now().Add(time.Millisecond))
625 }
626 }
627 }()
628 }
629 }
630
631
632
633 func TestRacyWrite(t *testing.T) {
634 t.Parallel()
635
636 r, w, err := os.Pipe()
637 if err != nil {
638 t.Fatal(err)
639 }
640 defer r.Close()
641 defer w.Close()
642
643 var wg sync.WaitGroup
644 defer wg.Wait()
645
646 go io.Copy(io.Discard, r)
647
648 w.SetWriteDeadline(time.Now().Add(time.Millisecond))
649 for i := 0; i < 10; i++ {
650 wg.Add(1)
651 go func() {
652 defer wg.Done()
653
654 b1 := make([]byte, 1024)
655 b2 := make([]byte, 1024)
656 for j := 0; j < 100; j++ {
657 _, err := w.Write(b1)
658 copy(b1, b2)
659 if err != nil {
660 if !isDeadlineExceeded(err) {
661 t.Error(err)
662 }
663 w.SetWriteDeadline(time.Now().Add(time.Millisecond))
664 }
665 }
666 }()
667 }
668 }
669
670
671 func TestTTYClose(t *testing.T) {
672
673 signal.Ignore(syscall.SIGTTIN)
674 defer signal.Reset(syscall.SIGTTIN)
675
676 f, err := os.Open("/dev/tty")
677 if err != nil {
678 t.Skipf("skipping because opening /dev/tty failed: %v", err)
679 }
680
681 go func() {
682 var buf [1]byte
683 f.Read(buf[:])
684 }()
685
686
687
688
689 time.Sleep(time.Millisecond)
690
691 c := make(chan bool)
692 go func() {
693 defer close(c)
694 f.Close()
695 }()
696
697 select {
698 case <-c:
699 case <-time.After(time.Second):
700 t.Error("timed out waiting for close")
701 }
702
703
704
705 }
706
View as plain text