| // 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(0) | |
| runtime.Futexsleep(&tt.mtx, 0, tt.ns) | |
| runtime.Exitsyscall(0) | |
| 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() | |
| } |