github.com/icodeface/tls@v0.0.0-20230910023335-34df9250cd12/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 "math/rand" 9 "runtime" 10 "strings" 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 TestMutexOverflowPanic(t *testing.T) { 125 defer func() { 126 r := recover() 127 if r == nil { 128 t.Fatal("did not panic") 129 } 130 msg, ok := r.(string) 131 if !ok { 132 t.Fatalf("unexpected panic type %T", r) 133 } 134 if !strings.Contains(msg, "too many") || strings.Contains(msg, "inconsistent") { 135 t.Fatalf("wrong panic message %q", msg) 136 } 137 }() 138 139 var mu1 FDMutex 140 for i := 0; i < 1<<21; i++ { 141 mu1.Incref() 142 } 143 } 144 145 func TestMutexStress(t *testing.T) { 146 P := 8 147 N := int(1e6) 148 if testing.Short() { 149 P = 4 150 N = 1e4 151 } 152 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) 153 done := make(chan bool) 154 var mu FDMutex 155 var readState [2]uint64 156 var writeState [2]uint64 157 for p := 0; p < P; p++ { 158 go func() { 159 r := rand.New(rand.NewSource(rand.Int63())) 160 for i := 0; i < N; i++ { 161 switch r.Intn(3) { 162 case 0: 163 if !mu.Incref() { 164 t.Error("broken") 165 return 166 } 167 if mu.Decref() { 168 t.Error("broken") 169 return 170 } 171 case 1: 172 if !mu.RWLock(true) { 173 t.Error("broken") 174 return 175 } 176 // Ensure that it provides mutual exclusion for readers. 177 if readState[0] != readState[1] { 178 t.Error("broken") 179 return 180 } 181 readState[0]++ 182 readState[1]++ 183 if mu.RWUnlock(true) { 184 t.Error("broken") 185 return 186 } 187 case 2: 188 if !mu.RWLock(false) { 189 t.Error("broken") 190 return 191 } 192 // Ensure that it provides mutual exclusion for writers. 193 if writeState[0] != writeState[1] { 194 t.Error("broken") 195 return 196 } 197 writeState[0]++ 198 writeState[1]++ 199 if mu.RWUnlock(false) { 200 t.Error("broken") 201 return 202 } 203 } 204 } 205 done <- true 206 }() 207 } 208 for p := 0; p < P; p++ { 209 <-done 210 } 211 if !mu.IncrefAndClose() { 212 t.Fatal("broken") 213 } 214 if !mu.Decref() { 215 t.Fatal("broken") 216 } 217 }