OSDN Git Service

Update Go compiler, library, and testsuite on gcc 4.7 branch.
[pf3gnuchains/gcc-fork.git] / libgo / go / sync / cond.go
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 // 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 {
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
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,
44 // Wait locks c.L before returning.  Unlike in other systems,
45 // Wait cannot return unless awoken by Broadcast or Signal.
46 //
47 // Because c.L is not locked when Wait first resumes, the caller
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()
60         if c.newSema == nil {
61                 c.newSema = new(uint32)
62         }
63         s := c.newSema
64         c.newWaiters++
65         c.m.Unlock()
66         c.L.Unlock()
67         runtime_Semacquire(s)
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()
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--
86                 runtime_Semrelease(c.oldSema)
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()
97         // Wake both generations.
98         if c.oldWaiters > 0 {
99                 for i := 0; i < c.oldWaiters; i++ {
100                         runtime_Semrelease(c.oldSema)
101                 }
102                 c.oldWaiters = 0
103         }
104         if c.newWaiters > 0 {
105                 for i := 0; i < c.newWaiters; i++ {
106                         runtime_Semrelease(c.newSema)
107                 }
108                 c.newWaiters = 0
109                 c.newSema = nil
110         }
111         c.m.Unlock()
112 }