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 if next > maxDynamicTimeout {
286 return maxDynamicTimeout, true
287 }
288 return next, true
289 }
290
291
292 func TestReadTimeoutFluctuation(t *testing.T) {
293 t.Parallel()
294
295 r, w, err := os.Pipe()
296 if err != nil {
297 t.Fatal(err)
298 }
299 defer r.Close()
300 defer w.Close()
301
302 d := minDynamicTimeout
303 b := make([]byte, 256)
304 for {
305 t.Logf("SetReadDeadline(+%v)", d)
306 t0 := time.Now()
307 deadline := t0.Add(d)
308 if err = r.SetReadDeadline(deadline); err != nil {
309 t.Fatalf("SetReadDeadline(%v): %v", deadline, err)
310 }
311 var n int
312 n, err = r.Read(b)
313 t1 := time.Now()
314
315 if n != 0 || err == nil || !isDeadlineExceeded(err) {
316 t.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
317 }
318
319 actual := t1.Sub(t0)
320 if t1.Before(deadline) {
321 t.Errorf("Read took %s; expected at least %s", actual, d)
322 }
323 if t.Failed() {
324 return
325 }
326 if want := timeoutUpperBound(d); actual > want {
327 next, ok := nextTimeout(actual)
328 if !ok {
329 t.Fatalf("Read took %s; expected at most %v", actual, want)
330 }
331
332
333 t.Logf("Read took %s (expected %s); trying with longer timeout", actual, d)
334 d = next
335 continue
336 }
337
338 break
339 }
340 }
341
342
343 func TestWriteTimeoutFluctuation(t *testing.T) {
344 t.Parallel()
345
346 r, w, err := os.Pipe()
347 if err != nil {
348 t.Fatal(err)
349 }
350 defer r.Close()
351 defer w.Close()
352
353 d := minDynamicTimeout
354 for {
355 t.Logf("SetWriteDeadline(+%v)", d)
356 t0 := time.Now()
357 deadline := t0.Add(d)
358 if err := w.SetWriteDeadline(deadline); err != nil {
359 t.Fatalf("SetWriteDeadline(%v): %v", deadline, err)
360 }
361 var n int64
362 var err error
363 for {
364 var dn int
365 dn, err = w.Write([]byte("TIMEOUT TRANSMITTER"))
366 n += int64(dn)
367 if err != nil {
368 break
369 }
370 }
371 t1 := time.Now()
372
373 if !isDeadlineExceeded(err) {
374 t.Fatalf("Write did not return (any, timeout): (%d, %v)", n, err)
375 }
376
377 actual := t1.Sub(t0)
378 if t1.Before(deadline) {
379 t.Errorf("Write took %s; expected at least %s", actual, d)
380 }
381 if t.Failed() {
382 return
383 }
384 if want := timeoutUpperBound(d); actual > want {
385 if n > 0 {
386
387
388
389
390 t.Logf("Wrote %d bytes into send buffer; retrying until buffer is full", n)
391 if d <= maxDynamicTimeout/2 {
392
393
394
395 d *= 2
396 }
397 } else if next, ok := nextTimeout(actual); !ok {
398 t.Fatalf("Write took %s; expected at most %s", actual, want)
399 } else {
400
401
402 t.Logf("Write took %s (expected %s); trying with longer timeout", actual, d)
403 d = next
404 }
405 continue
406 }
407
408 break
409 }
410 }
411
412
413 func TestVariousDeadlines(t *testing.T) {
414 t.Parallel()
415 testVariousDeadlines(t)
416 }
417
418
419 func TestVariousDeadlines1Proc(t *testing.T) {
420
421 if testing.Short() {
422 t.Skip("skipping in short mode")
423 }
424 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
425 testVariousDeadlines(t)
426 }
427
428
429 func TestVariousDeadlines4Proc(t *testing.T) {
430
431 if testing.Short() {
432 t.Skip("skipping in short mode")
433 }
434 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
435 testVariousDeadlines(t)
436 }
437
438 type neverEnding byte
439
440 func (b neverEnding) Read(p []byte) (int, error) {
441 for i := range p {
442 p[i] = byte(b)
443 }
444 return len(p), nil
445 }
446
447 func testVariousDeadlines(t *testing.T) {
448 type result struct {
449 n int64
450 err error
451 d time.Duration
452 }
453
454 handler := func(w *os.File, pasvch chan result) {
455
456
457 t0 := time.Now()
458 n, err := io.Copy(w, neverEnding('a'))
459 dt := time.Since(t0)
460 pasvch <- result{n, err, dt}
461 }
462
463 for _, timeout := range []time.Duration{
464 1 * time.Nanosecond,
465 2 * time.Nanosecond,
466 5 * time.Nanosecond,
467 50 * time.Nanosecond,
468 100 * time.Nanosecond,
469 200 * time.Nanosecond,
470 500 * time.Nanosecond,
471 750 * time.Nanosecond,
472 1 * time.Microsecond,
473 5 * time.Microsecond,
474 25 * time.Microsecond,
475 250 * time.Microsecond,
476 500 * time.Microsecond,
477 1 * time.Millisecond,
478 5 * time.Millisecond,
479 100 * time.Millisecond,
480 250 * time.Millisecond,
481 500 * time.Millisecond,
482 1 * time.Second,
483 } {
484 numRuns := 3
485 if testing.Short() {
486 numRuns = 1
487 if timeout > 500*time.Microsecond {
488 continue
489 }
490 }
491 for run := 0; run < numRuns; run++ {
492 t.Run(fmt.Sprintf("%v-%d", timeout, run+1), func(t *testing.T) {
493 r, w, err := os.Pipe()
494 if err != nil {
495 t.Fatal(err)
496 }
497 defer r.Close()
498 defer w.Close()
499
500 pasvch := make(chan result)
501 go handler(w, pasvch)
502
503 tooLong := 5 * time.Second
504 max := time.NewTimer(tooLong)
505 defer max.Stop()
506 actvch := make(chan result)
507 go func() {
508 t0 := time.Now()
509 if err := r.SetDeadline(t0.Add(timeout)); err != nil {
510 t.Error(err)
511 }
512 n, err := io.Copy(io.Discard, r)
513 dt := time.Since(t0)
514 r.Close()
515 actvch <- result{n, err, dt}
516 }()
517
518 select {
519 case res := <-actvch:
520 if !isDeadlineExceeded(err) {
521 t.Logf("good client timeout after %v, reading %d bytes", res.d, res.n)
522 } else {
523 t.Fatalf("client Copy = %d, %v; want timeout", res.n, res.err)
524 }
525 case <-max.C:
526 t.Fatalf("timeout (%v) waiting for client to timeout (%v) reading", tooLong, timeout)
527 }
528
529 select {
530 case res := <-pasvch:
531 t.Logf("writer in %v wrote %d: %v", res.d, res.n, res.err)
532 case <-max.C:
533 t.Fatalf("timeout waiting for writer to finish writing")
534 }
535 })
536 }
537 }
538 }
539
540
541 func TestReadWriteDeadlineRace(t *testing.T) {
542 t.Parallel()
543
544 N := 1000
545 if testing.Short() {
546 N = 50
547 }
548
549 r, w, err := os.Pipe()
550 if err != nil {
551 t.Fatal(err)
552 }
553 defer r.Close()
554 defer w.Close()
555
556 var wg sync.WaitGroup
557 wg.Add(3)
558 go func() {
559 defer wg.Done()
560 tic := time.NewTicker(2 * time.Microsecond)
561 defer tic.Stop()
562 for i := 0; i < N; i++ {
563 if err := r.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
564 break
565 }
566 if err := w.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
567 break
568 }
569 <-tic.C
570 }
571 }()
572 go func() {
573 defer wg.Done()
574 var b [1]byte
575 for i := 0; i < N; i++ {
576 _, err := r.Read(b[:])
577 if err != nil && !isDeadlineExceeded(err) {
578 t.Error("Read returned non-timeout error", err)
579 }
580 }
581 }()
582 go func() {
583 defer wg.Done()
584 var b [1]byte
585 for i := 0; i < N; i++ {
586 _, err := w.Write(b[:])
587 if err != nil && !isDeadlineExceeded(err) {
588 t.Error("Write returned non-timeout error", err)
589 }
590 }
591 }()
592 wg.Wait()
593 }
594
595
596
597 func TestRacyRead(t *testing.T) {
598 t.Parallel()
599
600 r, w, err := os.Pipe()
601 if err != nil {
602 t.Fatal(err)
603 }
604 defer r.Close()
605 defer w.Close()
606
607 var wg sync.WaitGroup
608 defer wg.Wait()
609
610 go io.Copy(w, rand.New(rand.NewSource(0)))
611
612 r.SetReadDeadline(time.Now().Add(time.Millisecond))
613 for i := 0; i < 10; i++ {
614 wg.Add(1)
615 go func() {
616 defer wg.Done()
617
618 b1 := make([]byte, 1024)
619 b2 := make([]byte, 1024)
620 for j := 0; j < 100; j++ {
621 _, err := r.Read(b1)
622 copy(b1, b2)
623 if err != nil {
624 if !isDeadlineExceeded(err) {
625 t.Error(err)
626 }
627 r.SetReadDeadline(time.Now().Add(time.Millisecond))
628 }
629 }
630 }()
631 }
632 }
633
634
635
636 func TestRacyWrite(t *testing.T) {
637 t.Parallel()
638
639 r, w, err := os.Pipe()
640 if err != nil {
641 t.Fatal(err)
642 }
643 defer r.Close()
644 defer w.Close()
645
646 var wg sync.WaitGroup
647 defer wg.Wait()
648
649 go io.Copy(io.Discard, r)
650
651 w.SetWriteDeadline(time.Now().Add(time.Millisecond))
652 for i := 0; i < 10; i++ {
653 wg.Add(1)
654 go func() {
655 defer wg.Done()
656
657 b1 := make([]byte, 1024)
658 b2 := make([]byte, 1024)
659 for j := 0; j < 100; j++ {
660 _, err := w.Write(b1)
661 copy(b1, b2)
662 if err != nil {
663 if !isDeadlineExceeded(err) {
664 t.Error(err)
665 }
666 w.SetWriteDeadline(time.Now().Add(time.Millisecond))
667 }
668 }
669 }()
670 }
671 }
672
673
674 func TestTTYClose(t *testing.T) {
675
676 signal.Ignore(syscall.SIGTTIN)
677 defer signal.Reset(syscall.SIGTTIN)
678
679 f, err := os.Open("/dev/tty")
680 if err != nil {
681 t.Skipf("skipping because opening /dev/tty failed: %v", err)
682 }
683
684 go func() {
685 var buf [1]byte
686 f.Read(buf[:])
687 }()
688
689
690
691
692 time.Sleep(time.Millisecond)
693
694 c := make(chan bool)
695 go func() {
696 defer close(c)
697 f.Close()
698 }()
699
700 select {
701 case <-c:
702 case <-time.After(time.Second):
703 t.Error("timed out waiting for close")
704 }
705
706
707
708 }
709
View as plain text