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