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