OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [sync/] [waitgroup.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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
        "runtime"
9
        "sync/atomic"
10
)
11
 
12
// A WaitGroup waits for a collection of goroutines to finish.
13
// The main goroutine calls Add to set the number of
14
// goroutines to wait for.  Then each of the goroutines
15
// runs and calls Done when finished.  At the same time,
16
// Wait can be used to block until all goroutines have finished.
17
//
18
// For example:
19
//
20
//   for i := 0; i < n; i++ {
21
//       if !condition(i) {
22
//           continue
23
//       }
24
//       wg.Add(1)
25
//       go func() {
26
//           // Do something.
27
//           wg.Done()
28
//       }()
29
//   }
30
//   wg.Wait()
31
//
32
type WaitGroup struct {
33
        m       Mutex
34
        counter int32
35
        waiters int32
36
        sema    *uint32
37
}
38
 
39
// WaitGroup creates a new semaphore each time the old semaphore
40
// is released. This is to avoid the following race:
41
//
42
// G1: Add(1)
43
// G1: go G2()
44
// G1: Wait() // Context switch after Unlock() and before Semacquire().
45
// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
46
// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
47
// G3: Add(1) // Makes counter == 1, waiters == 0.
48
// G3: go G4()
49
// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.
50
 
51
// Add adds delta, which may be negative, to the WaitGroup counter.
52
// If the counter becomes zero, all goroutines blocked on Wait() are released.
53
func (wg *WaitGroup) Add(delta int) {
54
        v := atomic.AddInt32(&wg.counter, int32(delta))
55
        if v < 0 {
56
                panic("sync: negative WaitGroup count")
57
        }
58
        if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
59
                return
60
        }
61
        wg.m.Lock()
62
        for i := int32(0); i < wg.waiters; i++ {
63
                runtime.Semrelease(wg.sema)
64
        }
65
        wg.waiters = 0
66
        wg.sema = nil
67
        wg.m.Unlock()
68
}
69
 
70
// Done decrements the WaitGroup counter.
71
func (wg *WaitGroup) Done() {
72
        wg.Add(-1)
73
}
74
 
75
// Wait blocks until the WaitGroup counter is zero.
76
func (wg *WaitGroup) Wait() {
77
        if atomic.LoadInt32(&wg.counter) == 0 {
78
                return
79
        }
80
        wg.m.Lock()
81
        atomic.AddInt32(&wg.waiters, 1)
82
        // This code is racing with the unlocked path in Add above.
83
        // The code above modifies counter and then reads waiters.
84
        // We must modify waiters and then read counter (the opposite order)
85
        // to avoid missing an Add.
86
        if atomic.LoadInt32(&wg.counter) == 0 {
87
                atomic.AddInt32(&wg.waiters, -1)
88
                wg.m.Unlock()
89
                return
90
        }
91
        if wg.sema == nil {
92
                wg.sema = new(uint32)
93
        }
94
        s := wg.sema
95
        wg.m.Unlock()
96
        runtime.Semacquire(s)
97
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.