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