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