github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/sync/cond_test.go (about) 1 package sync_test 2 3 import ( 4 "sync" 5 "sync/atomic" 6 "testing" 7 ) 8 9 // TestCondSignal tests waiting on a Cond and notifying it with Signal. 10 func TestCondSignal(t *testing.T) { 11 // Create a Cond with a normal mutex. 12 cond := sync.Cond{ 13 L: &sync.Mutex{}, 14 } 15 cond.L.Lock() 16 17 // Start a goroutine to signal us once we wait. 18 var signaled uint32 19 go func() { 20 // Wait for the test goroutine to wait. 21 cond.L.Lock() 22 defer cond.L.Unlock() 23 24 // Send a signal to the test goroutine. 25 atomic.StoreUint32(&signaled, 1) 26 cond.Signal() 27 }() 28 29 // Wait for a signal. 30 // This will unlock the mutex, and allow the spawned goroutine to run. 31 cond.Wait() 32 if atomic.LoadUint32(&signaled) == 0 { 33 t.Error("wait returned before a signal was sent") 34 } 35 } 36 37 func TestCondBroadcast(t *testing.T) { 38 // Create a Cond with an RWMutex. 39 var mu sync.RWMutex 40 cond := sync.Cond{ 41 L: mu.RLocker(), 42 } 43 44 // Start goroutines to wait for the broadcast. 45 var wg sync.WaitGroup 46 const n = 5 47 for i := 0; i < n; i++ { 48 wg.Add(1) 49 mu.RLock() 50 go func() { 51 defer wg.Done() 52 53 cond.Wait() 54 }() 55 } 56 57 // Wait for all goroutines to start waiting. 58 mu.Lock() 59 60 // Broadcast to all of the waiting goroutines. 61 cond.Broadcast() 62 63 // Wait for all spawned goroutines to process the broadcast. 64 mu.Unlock() 65 wg.Wait() 66 } 67 68 // TestCondUnlockNotify verifies that a signal is processed even if it happens during the mutex unlock in Wait. 69 func TestCondUnlockNotify(t *testing.T) { 70 // Create a Cond that signals itself when waiting. 71 var cond sync.Cond 72 cond.L = fakeLocker{cond.Signal} 73 74 cond.Wait() 75 } 76 77 // fakeLocker is a fake sync.Locker where unlock calls an arbitrary function. 78 type fakeLocker struct { 79 unlock func() 80 } 81 82 func (l fakeLocker) Lock() {} 83 func (l fakeLocker) Unlock() { l.unlock() }