lin
2025-06-05 ed3dd9d3e7519a82bb871d5eedb24a2fa0c91f47
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
 
// Futex is only available on DragonFly BSD, FreeBSD and Linux.
// The race detector emits calls to split stack functions so it breaks
// the test.
 
// +build dragonfly freebsd linux
// +build !race
 
package runtime_test
 
import (
   "runtime"
   "sync"
   "sync/atomic"
   "testing"
   "time"
)
 
type futexsleepTest struct {
   mtx uint32
   ns  int64
   msg string
   ch  chan *futexsleepTest
}
 
var futexsleepTests = []futexsleepTest{
   beforeY2038: {mtx: 0, ns: 86400 * 1e9, msg: "before the year 2038"},
   afterY2038:  {mtx: 0, ns: (1<<31 + 100) * 1e9, msg: "after the year 2038"},
}
 
const (
   beforeY2038 = iota
   afterY2038
)
 
func TestFutexsleep(t *testing.T) {
   if runtime.GOMAXPROCS(0) > 1 {
       // futexsleep doesn't handle EINTR or other signals,
       // so spurious wakeups may happen.
       t.Skip("skipping; GOMAXPROCS>1")
   }
 
   start := time.Now()
   var wg sync.WaitGroup
   for i := range futexsleepTests {
       tt := &futexsleepTests[i]
       tt.mtx = 0
       tt.ch = make(chan *futexsleepTest, 1)
       wg.Add(1)
       go func(tt *futexsleepTest) {
           runtime.Entersyscall()
           runtime.Futexsleep(&tt.mtx, 0, tt.ns)
           runtime.Exitsyscall()
           tt.ch <- tt
           wg.Done()
       }(tt)
   }
loop:
   for {
       select {
       case tt := <-futexsleepTests[beforeY2038].ch:
           t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
           break loop
       case tt := <-futexsleepTests[afterY2038].ch:
           // Looks like FreeBSD 10 kernel has changed
           // the semantics of timedwait on userspace
           // mutex to make broken stuff look broken.
           switch {
           case runtime.GOOS == "freebsd" && runtime.GOARCH == "386":
               t.Log("freebsd/386 may not work correctly after the year 2038, see golang.org/issue/7194")
           default:
               t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
               break loop
           }
       case <-time.After(time.Second):
           break loop
       }
   }
   for i := range futexsleepTests {
       tt := &futexsleepTests[i]
       atomic.StoreUint32(&tt.mtx, 1)
       runtime.Futexwakeup(&tt.mtx, 1)
   }
   wg.Wait()
}