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 }