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() }