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 	"sync"
     17 	"sync/atomic"
     18 	"testing"
     19 	"time"
     20 )
     21 
     22 type futexsleepTest struct {
     23 	mtx uint32
     24 	ns  int64
     25 	msg string
     26 	ch  chan *futexsleepTest
     27 }
     28 
     29 var futexsleepTests = []futexsleepTest{
     30 	beforeY2038: {mtx: 0, ns: 86400 * 1e9, msg: "before the year 2038"},
     31 	afterY2038:  {mtx: 0, ns: (1<<31 + 100) * 1e9, msg: "after the year 2038"},
     32 }
     33 
     34 const (
     35 	beforeY2038 = iota
     36 	afterY2038
     37 )
     38 
     39 func TestFutexsleep(t *testing.T) {
     40 	if runtime.GOMAXPROCS(0) > 1 {
     41 		// futexsleep doesn't handle EINTR or other signals,
     42 		// so spurious wakeups may happen.
     43 		t.Skip("skipping; GOMAXPROCS>1")
     44 	}
     45 
     46 	start := time.Now()
     47 	var wg sync.WaitGroup
     48 	for i := range futexsleepTests {
     49 		tt := &futexsleepTests[i]
     50 		tt.mtx = 0
     51 		tt.ch = make(chan *futexsleepTest, 1)
     52 		wg.Add(1)
     53 		go func(tt *futexsleepTest) {
     54 			runtime.Entersyscall(0)
     55 			runtime.Futexsleep(&tt.mtx, 0, tt.ns)
     56 			runtime.Exitsyscall(0)
     57 			tt.ch <- tt
     58 			wg.Done()
     59 		}(tt)
     60 	}
     61 loop:
     62 	for {
     63 		select {
     64 		case tt := <-futexsleepTests[beforeY2038].ch:
     65 			t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
     66 			break loop
     67 		case tt := <-futexsleepTests[afterY2038].ch:
     68 			// Looks like FreeBSD 10 kernel has changed
     69 			// the semantics of timedwait on userspace
     70 			// mutex to make broken stuff look broken.
     71 			switch {
     72 			case runtime.GOOS == "freebsd" && runtime.GOARCH == "386":
     73 				t.Log("freebsd/386 may not work correctly after the year 2038, see golang.org/issue/7194")
     74 			default:
     75 				t.Errorf("futexsleep test %q finished early after %s", tt.msg, time.Since(start))
     76 				break loop
     77 			}
     78 		case <-time.After(time.Second):
     79 			break loop
     80 		}
     81 	}
     82 	for i := range futexsleepTests {
     83 		tt := &futexsleepTests[i]
     84 		atomic.StoreUint32(&tt.mtx, 1)
     85 		runtime.Futexwakeup(&tt.mtx, 1)
     86 	}
     87 	wg.Wait()
     88 }
     89