github.com/dmmcquay/sia@v1.3.1-0.20180712220038-9f8d535311b9/sync/tryrwmutex_test.go (about) 1 package sync 2 3 import ( 4 "runtime" 5 "sync" 6 "testing" 7 ) 8 9 // TestTryRWMutexBasicMutex verifies that Lock and Unlock work the same as a 10 // normal mutex would. 11 func TestTryRWMutexBasicMutex(t *testing.T) { 12 // Check that two calls to lock will execute in the correct order. 13 var tm TryRWMutex 14 var data int 15 tm.Lock() 16 go func() { 17 data = 15 18 tm.Unlock() 19 }() 20 tm.Lock() 21 if data != 15 { 22 t.Error("Locking did not safely protect the data") 23 } 24 tm.Unlock() 25 } 26 27 // TestTryRWMutexConcurrentLocking checks that doing lots of concurrent locks 28 // is handled as expected. 29 func TestTryRWMutexConcurrentLocking(t *testing.T) { 30 if testing.Short() { 31 t.SkipNow() 32 } 33 34 // Try executing multiple additions concurrently. 35 var tm TryRWMutex 36 var data int 37 var wg sync.WaitGroup 38 for i := 0; i < 250; i++ { 39 wg.Add(1) 40 go func() { 41 tm.Lock() 42 data++ 43 tm.Unlock() 44 wg.Done() 45 }() 46 } 47 wg.Wait() 48 if data != 250 { 49 t.Error("Locking did not safely protect the data") 50 } 51 } 52 53 // TestTryRWMutexBasicTryLock checks that a TryLock will succeed if nobody is 54 // holding a lock, and will fail if the lock is being held. 55 func TestTryRWMutexBasicTryLock(t *testing.T) { 56 // Lock and then TryLock. 57 var tm TryRWMutex 58 tm.Lock() 59 if tm.TryLock() { 60 t.Error("TryLock should have failed") 61 } 62 tm.Unlock() 63 64 tm.Lock() 65 tm.Unlock() 66 67 // TryLock and then TryLock. 68 if !tm.TryLock() { 69 t.Error("Could not get a blank lock") 70 } 71 if tm.TryLock() { 72 t.Error("should not have been able to get the lock") 73 } 74 tm.Unlock() 75 } 76 77 // TestTryRWMutexConcurrentTries attempts to grab locks from many threads, 78 // giving the race detector a chance to detect any issues. 79 func TestTryRWMutexConncurrentTries(t *testing.T) { 80 if testing.Short() { 81 t.SkipNow() 82 } 83 84 // Try executing multiple additions concurrently. 85 var tm TryRWMutex 86 var data int 87 var wg sync.WaitGroup 88 for i := 0; i < 250; i++ { 89 wg.Add(1) 90 go func() { 91 for !tm.TryLock() { 92 } 93 94 data++ 95 tm.Unlock() 96 wg.Done() 97 }() 98 } 99 wg.Wait() 100 if data != 250 { 101 t.Error("Locking did not safely protect the data") 102 } 103 } 104 105 // TestTryRWMutexReadAvailable will try to acquire a read lock on the mutex 106 // when it is supposed to be available. 107 func TestTryRWMutexReadAvailable(t *testing.T) { 108 var tm TryRWMutex 109 if !tm.TryRLock() { 110 t.Fatal("Unable to get readlock on a fresh TryRWMutex") 111 } 112 113 // Grab the lock and increment the data in a goroutine. 114 var data int 115 var wg sync.WaitGroup 116 wg.Add(2) 117 go func() { 118 defer wg.Done() 119 tm.Lock() 120 data++ 121 tm.Unlock() 122 }() 123 runtime.Gosched() 124 go func() { 125 defer wg.Done() 126 tm.Lock() 127 data++ 128 tm.Unlock() 129 }() 130 runtime.Gosched() 131 132 // Read the data, readlock should be held. 133 if data != 0 { 134 t.Fatal("Data should not have changed while under readlock") 135 } 136 137 // Release the lock and wait for the other locks to finish their 138 // modifications. 139 tm.RUnlock() 140 wg.Wait() 141 142 // Try to grab another readlock. It should succeed. The data should have 143 // changed. 144 if !tm.TryRLock() { 145 t.Fatal("Unable to get readlock on available TryRWMutex") 146 } 147 if data != 2 { 148 t.Error("Data does not seem to have been altered correctly") 149 } 150 tm.RUnlock() 151 } 152 153 // TestTryRWMutexReadUnavailable will try to acquire a read lock on the mutex 154 // when it is supposed to be available. 155 func TestTryRWMutexReadUnavailable(t *testing.T) { 156 var tm TryRWMutex 157 if !tm.TryRLock() { 158 t.Fatal("Unable to get readlock on a fresh TryRWMutex") 159 } 160 161 // Grab the lock and increment the data in a goroutine. 162 var data int 163 var wg sync.WaitGroup 164 wg.Add(2) 165 go func() { 166 defer wg.Done() 167 tm.Lock() 168 data++ 169 tm.Unlock() 170 }() 171 runtime.Gosched() 172 go func() { 173 defer wg.Done() 174 tm.Lock() 175 data++ 176 tm.Unlock() 177 }() 178 runtime.Gosched() 179 180 // Read the data, readlock should be held. 181 if data != 0 { 182 t.Fatal("Data should not have changed while under readlock") 183 } 184 185 // Try to grab another readlock. It should not succeed. 186 if tm.TryRLock() { 187 t.Fatal("Able to get readlock on available TryRWMutex") 188 } 189 190 // Release the lock and wait for the other locks to finish their 191 // modifications. 192 tm.RUnlock() 193 wg.Wait() 194 }