Home | History | Annotate | Download | only in runtime
      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