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