github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/sync/cond.go (about)

     1  // Copyright 2011 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 sync
     6  
     7  import (
     8  	"sync/atomic"
     9  	"unsafe"
    10  )
    11  
    12  // Cond implements a condition variable, a rendezvous point
    13  // for goroutines waiting for or announcing the occurrence
    14  // of an event.
    15  //
    16  // Each Cond has an associated Locker L (often a *Mutex or *RWMutex),
    17  // which must be held when changing the condition and
    18  // when calling the Wait method.
    19  //
    20  // A Cond must not be copied after first use.
    21  type Cond struct {
    22  	noCopy noCopy
    23  
    24  	// L is held while observing or changing the condition
    25  	L Locker
    26  
    27  	notify  notifyList
    28  	checker copyChecker
    29  }
    30  
    31  // NewCond returns a new Cond with Locker l.
    32  func NewCond(l Locker) *Cond {
    33  	return &Cond{L: l}
    34  }
    35  
    36  // Wait atomically unlocks c.L and suspends execution
    37  // of the calling goroutine. After later resuming execution,
    38  // Wait locks c.L before returning. Unlike in other systems,
    39  // Wait cannot return unless awoken by Broadcast or Signal.
    40  //
    41  // Because c.L is not locked when Wait first resumes, the caller
    42  // typically cannot assume that the condition is true when
    43  // Wait returns. Instead, the caller should Wait in a loop:
    44  //
    45  //    c.L.Lock()
    46  //    for !condition() {
    47  //        c.Wait()
    48  //    }
    49  //    ... make use of condition ...
    50  //    c.L.Unlock()
    51  //
    52  func (c *Cond) Wait() {
    53  	c.checker.check()
    54  	t := runtime_notifyListAdd(&c.notify)
    55  	c.L.Unlock()
    56  	runtime_notifyListWait(&c.notify, t)
    57  	c.L.Lock()
    58  }
    59  
    60  // Signal wakes one goroutine waiting on c, if there is any.
    61  //
    62  // It is allowed but not required for the caller to hold c.L
    63  // during the call.
    64  func (c *Cond) Signal() {
    65  	c.checker.check()
    66  	runtime_notifyListNotifyOne(&c.notify)
    67  }
    68  
    69  // Broadcast wakes all goroutines waiting on c.
    70  //
    71  // It is allowed but not required for the caller to hold c.L
    72  // during the call.
    73  func (c *Cond) Broadcast() {
    74  	c.checker.check()
    75  	runtime_notifyListNotifyAll(&c.notify)
    76  }
    77  
    78  // copyChecker holds back pointer to itself to detect object copying.
    79  type copyChecker uintptr
    80  
    81  func (c *copyChecker) check() {
    82  	if uintptr(*c) != uintptr(unsafe.Pointer(c)) &&
    83  		!atomic.CompareAndSwapUintptr((*uintptr)(c), 0, uintptr(unsafe.Pointer(c))) &&
    84  		uintptr(*c) != uintptr(unsafe.Pointer(c)) {
    85  		panic("sync.Cond is copied")
    86  	}
    87  }
    88  
    89  // noCopy may be embedded into structs which must not be copied
    90  // after the first use.
    91  //
    92  // See https://golang.org/issues/8005#issuecomment-190753527
    93  // for details.
    94  type noCopy struct{}
    95  
    96  // Lock is a no-op used by -copylocks checker from `go vet`.
    97  func (*noCopy) Lock() {}