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