Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 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. |
Robert Griesemer | 9fc0f15 | 2011-02-23 10:12:38 -0800 | [diff] [blame] | 4 | |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 5 | package sync |
| 6 | |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 7 | // Cond implements a condition variable, a rendezvous point |
| 8 | // for goroutines waiting for or announcing the occurrence |
| 9 | // of an event. |
| 10 | // |
| 11 | // Each Cond has an associated Locker L (often a *Mutex or *RWMutex), |
| 12 | // which must be held when changing the condition and |
| 13 | // when calling the Wait method. |
| 14 | type Cond struct { |
Gustavo Niemeyer | 17bfa32 | 2011-06-01 20:30:42 -0300 | [diff] [blame] | 15 | L Locker // held while observing or changing the condition |
| 16 | m Mutex // held to avoid internal races |
| 17 | |
| 18 | // We must be careful to make sure that when Signal |
| 19 | // releases a semaphore, the corresponding acquire is |
| 20 | // executed by a goroutine that was already waiting at |
| 21 | // the time of the call to Signal, not one that arrived later. |
| 22 | // To ensure this, we segment waiting goroutines into |
| 23 | // generations punctuated by calls to Signal. Each call to |
| 24 | // Signal begins another generation if there are no goroutines |
| 25 | // left in older generations for it to wake. Because of this |
| 26 | // optimization (only begin another generation if there |
| 27 | // are no older goroutines left), we only need to keep track |
| 28 | // of the two most recent generations, which we call old |
| 29 | // and new. |
| 30 | oldWaiters int // number of waiters in old generation... |
| 31 | oldSema *uint32 // ... waiting on this semaphore |
| 32 | |
| 33 | newWaiters int // number of waiters in new generation... |
| 34 | newSema *uint32 // ... waiting on this semaphore |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 35 | } |
| 36 | |
| 37 | // NewCond returns a new Cond with Locker l. |
| 38 | func NewCond(l Locker) *Cond { |
| 39 | return &Cond{L: l} |
| 40 | } |
| 41 | |
| 42 | // Wait atomically unlocks c.L and suspends execution |
| 43 | // of the calling goroutine. After later resuming execution, |
Dmitriy Vyukov | 76eb911 | 2012-02-17 13:20:11 +0400 | [diff] [blame] | 44 | // Wait locks c.L before returning. Unlike in other systems, |
| 45 | // Wait cannot return unless awoken by Broadcast or Signal. |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 46 | // |
Dmitriy Vyukov | 76eb911 | 2012-02-17 13:20:11 +0400 | [diff] [blame] | 47 | // Because c.L is not locked when Wait first resumes, the caller |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 48 | // typically cannot assume that the condition is true when |
| 49 | // Wait returns. Instead, the caller should Wait in a loop: |
| 50 | // |
| 51 | // c.L.Lock() |
| 52 | // for !condition() { |
| 53 | // c.Wait() |
| 54 | // } |
| 55 | // ... make use of condition ... |
| 56 | // c.L.Unlock() |
| 57 | // |
| 58 | func (c *Cond) Wait() { |
| 59 | c.m.Lock() |
Gustavo Niemeyer | 17bfa32 | 2011-06-01 20:30:42 -0300 | [diff] [blame] | 60 | if c.newSema == nil { |
| 61 | c.newSema = new(uint32) |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 62 | } |
Gustavo Niemeyer | 17bfa32 | 2011-06-01 20:30:42 -0300 | [diff] [blame] | 63 | s := c.newSema |
| 64 | c.newWaiters++ |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 65 | c.m.Unlock() |
| 66 | c.L.Unlock() |
Russ Cox | 03f2289 | 2012-02-19 00:11:44 -0500 | [diff] [blame] | 67 | runtime_Semacquire(s) |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 68 | c.L.Lock() |
| 69 | } |
| 70 | |
| 71 | // Signal wakes one goroutine waiting on c, if there is any. |
| 72 | // |
| 73 | // It is allowed but not required for the caller to hold c.L |
| 74 | // during the call. |
| 75 | func (c *Cond) Signal() { |
| 76 | c.m.Lock() |
Gustavo Niemeyer | 17bfa32 | 2011-06-01 20:30:42 -0300 | [diff] [blame] | 77 | if c.oldWaiters == 0 && c.newWaiters > 0 { |
| 78 | // Retire old generation; rename new to old. |
| 79 | c.oldWaiters = c.newWaiters |
| 80 | c.oldSema = c.newSema |
| 81 | c.newWaiters = 0 |
| 82 | c.newSema = nil |
| 83 | } |
| 84 | if c.oldWaiters > 0 { |
| 85 | c.oldWaiters-- |
Russ Cox | 03f2289 | 2012-02-19 00:11:44 -0500 | [diff] [blame] | 86 | runtime_Semrelease(c.oldSema) |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 87 | } |
| 88 | c.m.Unlock() |
| 89 | } |
| 90 | |
| 91 | // Broadcast wakes all goroutines waiting on c. |
| 92 | // |
| 93 | // It is allowed but not required for the caller to hold c.L |
| 94 | // during the call. |
| 95 | func (c *Cond) Broadcast() { |
| 96 | c.m.Lock() |
Gustavo Niemeyer | 17bfa32 | 2011-06-01 20:30:42 -0300 | [diff] [blame] | 97 | // Wake both generations. |
| 98 | if c.oldWaiters > 0 { |
| 99 | for i := 0; i < c.oldWaiters; i++ { |
Russ Cox | 03f2289 | 2012-02-19 00:11:44 -0500 | [diff] [blame] | 100 | runtime_Semrelease(c.oldSema) |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 101 | } |
Gustavo Niemeyer | 17bfa32 | 2011-06-01 20:30:42 -0300 | [diff] [blame] | 102 | c.oldWaiters = 0 |
| 103 | } |
| 104 | if c.newWaiters > 0 { |
| 105 | for i := 0; i < c.newWaiters; i++ { |
Russ Cox | 03f2289 | 2012-02-19 00:11:44 -0500 | [diff] [blame] | 106 | runtime_Semrelease(c.newSema) |
Gustavo Niemeyer | 17bfa32 | 2011-06-01 20:30:42 -0300 | [diff] [blame] | 107 | } |
| 108 | c.newWaiters = 0 |
| 109 | c.newSema = nil |
Gustavo Niemeyer | 05b1dbd | 2011-02-16 14:11:07 -0500 | [diff] [blame] | 110 | } |
| 111 | c.m.Unlock() |
| 112 | } |