github.com/riscv/riscv-go@v0.0.0-20200123204226-124ebd6fcc8e/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 }