github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/internal/poll/fd_mutex_test.go (about)

     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  package poll_test
     6  
     7  import (
     8  	. "internal/poll"
     9  	"math/rand"
    10  	"runtime"
    11  	"testing"
    12  	"time"
    13  )
    14  
    15  func TestMutexLock(t *testing.T) {
    16  	var mu FDMutex
    17  
    18  	if !mu.Incref() {
    19  		t.Fatal("broken")
    20  	}
    21  	if mu.Decref() {
    22  		t.Fatal("broken")
    23  	}
    24  
    25  	if !mu.RWLock(true) {
    26  		t.Fatal("broken")
    27  	}
    28  	if mu.RWUnlock(true) {
    29  		t.Fatal("broken")
    30  	}
    31  
    32  	if !mu.RWLock(false) {
    33  		t.Fatal("broken")
    34  	}
    35  	if mu.RWUnlock(false) {
    36  		t.Fatal("broken")
    37  	}
    38  }
    39  
    40  func TestMutexClose(t *testing.T) {
    41  	var mu FDMutex
    42  	if !mu.IncrefAndClose() {
    43  		t.Fatal("broken")
    44  	}
    45  
    46  	if mu.Incref() {
    47  		t.Fatal("broken")
    48  	}
    49  	if mu.RWLock(true) {
    50  		t.Fatal("broken")
    51  	}
    52  	if mu.RWLock(false) {
    53  		t.Fatal("broken")
    54  	}
    55  	if mu.IncrefAndClose() {
    56  		t.Fatal("broken")
    57  	}
    58  }
    59  
    60  func TestMutexCloseUnblock(t *testing.T) {
    61  	c := make(chan bool)
    62  	var mu FDMutex
    63  	mu.RWLock(true)
    64  	for i := 0; i < 4; i++ {
    65  		go func() {
    66  			if mu.RWLock(true) {
    67  				t.Error("broken")
    68  				return
    69  			}
    70  			c <- true
    71  		}()
    72  	}
    73  	// Concurrent goroutines must not be able to read lock the mutex.
    74  	time.Sleep(time.Millisecond)
    75  	select {
    76  	case <-c:
    77  		t.Fatal("broken")
    78  	default:
    79  	}
    80  	mu.IncrefAndClose() // Must unblock the readers.
    81  	for i := 0; i < 4; i++ {
    82  		select {
    83  		case <-c:
    84  		case <-time.After(10 * time.Second):
    85  			t.Fatal("broken")
    86  		}
    87  	}
    88  	if mu.Decref() {
    89  		t.Fatal("broken")
    90  	}
    91  	if !mu.RWUnlock(true) {
    92  		t.Fatal("broken")
    93  	}
    94  }
    95  
    96  func TestMutexPanic(t *testing.T) {
    97  	ensurePanics := func(f func()) {
    98  		defer func() {
    99  			if recover() == nil {
   100  				t.Fatal("does not panic")
   101  			}
   102  		}()
   103  		f()
   104  	}
   105  
   106  	var mu FDMutex
   107  	ensurePanics(func() { mu.Decref() })
   108  	ensurePanics(func() { mu.RWUnlock(true) })
   109  	ensurePanics(func() { mu.RWUnlock(false) })
   110  
   111  	ensurePanics(func() { mu.Incref(); mu.Decref(); mu.Decref() })
   112  	ensurePanics(func() { mu.RWLock(true); mu.RWUnlock(true); mu.RWUnlock(true) })
   113  	ensurePanics(func() { mu.RWLock(false); mu.RWUnlock(false); mu.RWUnlock(false) })
   114  
   115  	// ensure that it's still not broken
   116  	mu.Incref()
   117  	mu.Decref()
   118  	mu.RWLock(true)
   119  	mu.RWUnlock(true)
   120  	mu.RWLock(false)
   121  	mu.RWUnlock(false)
   122  }
   123  
   124  func TestMutexStress(t *testing.T) {
   125  	P := 8
   126  	N := int(1e6)
   127  	if testing.Short() {
   128  		P = 4
   129  		N = 1e4
   130  	}
   131  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
   132  	done := make(chan bool)
   133  	var mu FDMutex
   134  	var readState [2]uint64
   135  	var writeState [2]uint64
   136  	for p := 0; p < P; p++ {
   137  		go func() {
   138  			r := rand.New(rand.NewSource(rand.Int63()))
   139  			for i := 0; i < N; i++ {
   140  				switch r.Intn(3) {
   141  				case 0:
   142  					if !mu.Incref() {
   143  						t.Error("broken")
   144  						return
   145  					}
   146  					if mu.Decref() {
   147  						t.Error("broken")
   148  						return
   149  					}
   150  				case 1:
   151  					if !mu.RWLock(true) {
   152  						t.Error("broken")
   153  						return
   154  					}
   155  					// Ensure that it provides mutual exclusion for readers.
   156  					if readState[0] != readState[1] {
   157  						t.Error("broken")
   158  						return
   159  					}
   160  					readState[0]++
   161  					readState[1]++
   162  					if mu.RWUnlock(true) {
   163  						t.Error("broken")
   164  						return
   165  					}
   166  				case 2:
   167  					if !mu.RWLock(false) {
   168  						t.Error("broken")
   169  						return
   170  					}
   171  					// Ensure that it provides mutual exclusion for writers.
   172  					if writeState[0] != writeState[1] {
   173  						t.Error("broken")
   174  						return
   175  					}
   176  					writeState[0]++
   177  					writeState[1]++
   178  					if mu.RWUnlock(false) {
   179  						t.Error("broken")
   180  						return
   181  					}
   182  				}
   183  			}
   184  			done <- true
   185  		}()
   186  	}
   187  	for p := 0; p < P; p++ {
   188  		<-done
   189  	}
   190  	if !mu.IncrefAndClose() {
   191  		t.Fatal("broken")
   192  	}
   193  	if !mu.Decref() {
   194  		t.Fatal("broken")
   195  	}
   196  }