github.com/fisco-bcos/crypto@v0.0.0-20200202032121-bd8ab0b5d4f1/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 FDMutex 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 FDMutex 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) 63 var mu FDMutex 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 FDMutex 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 FDMutex 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) 155 var mu FDMutex 156 var readState [2]uint64 157 var writeState [2]uint64 158 for p := 0; p < P; p++ { 159 go func() { 160 r := rand.New(rand.NewSource(rand.Int63())) 161 for i := 0; i < N; i++ { 162 switch r.Intn(3) { 163 case 0: 164 if !mu.Incref() { 165 t.Error("broken") 166 return 167 } 168 if mu.Decref() { 169 t.Error("broken") 170 return 171 } 172 case 1: 173 if !mu.RWLock(true) { 174 t.Error("broken") 175 return 176 } 177 // Ensure that it provides mutual exclusion for readers. 178 if readState[0] != readState[1] { 179 t.Error("broken") 180 return 181 } 182 readState[0]++ 183 readState[1]++ 184 if mu.RWUnlock(true) { 185 t.Error("broken") 186 return 187 } 188 case 2: 189 if !mu.RWLock(false) { 190 t.Error("broken") 191 return 192 } 193 // Ensure that it provides mutual exclusion for writers. 194 if writeState[0] != writeState[1] { 195 t.Error("broken") 196 return 197 } 198 writeState[0]++ 199 writeState[1]++ 200 if mu.RWUnlock(false) { 201 t.Error("broken") 202 return 203 } 204 } 205 } 206 done <- true 207 }() 208 } 209 for p := 0; p < P; p++ { 210 <-done 211 } 212 if !mu.IncrefAndClose() { 213 t.Fatal("broken") 214 } 215 if !mu.Decref() { 216 t.Fatal("broken") 217 } 218 }