diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-03-16 23:05:44 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2011-03-16 23:05:44 +0000 |
commit | 31c6ec422702226aabab7d082da16663e6c3e72c (patch) | |
tree | 44176975832a3faf1626836e70c97d5edd674122 /libgo/go/sync/waitgroup.go | |
parent | b3145af52cfb7c84d62a8e4ceeb165a7369718da (diff) | |
download | gcc-31c6ec422702226aabab7d082da16663e6c3e72c.tar.gz |
Update to current version of Go library (revision 94d654be2064).
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@171076 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/sync/waitgroup.go')
-rw-r--r-- | libgo/go/sync/waitgroup.go | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/libgo/go/sync/waitgroup.go b/libgo/go/sync/waitgroup.go new file mode 100644 index 00000000000..68e1d509f48 --- /dev/null +++ b/libgo/go/sync/waitgroup.go @@ -0,0 +1,86 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package sync + +import "runtime" + +// A WaitGroup waits for a collection of goroutines to finish. +// The main goroutine calls Add to set the number of +// goroutines to wait for. Then each of the goroutines +// runs and calls Done when finished. At the same time, +// Wait can be used to block until all goroutines have finished. +// +// For example: +// +// for i := 0; i < n; i++ { +// if !condition(i) { +// continue +// } +// wg.Add(1) +// go func() { +// // Do something. +// wg.Done() +// } +// } +// wg.Wait() +// +type WaitGroup struct { + m Mutex + counter int + waiters int + sema *uint32 +} + +// WaitGroup creates a new semaphore each time the old semaphore +// is released. This is to avoid the following race: +// +// G1: Add(1) +// G1: go G2() +// G1: Wait() // Context switch after Unlock() and before Semacquire(). +// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet. +// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block. +// G3: Add(1) // Makes counter == 1, waiters == 0. +// G3: go G4() +// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug. + +// Add adds delta, which may be negative, to the WaitGroup counter. +// If the counter becomes zero, all goroutines blocked on Wait() are released. +func (wg *WaitGroup) Add(delta int) { + wg.m.Lock() + if delta < -wg.counter { + wg.m.Unlock() + panic("sync: negative WaitGroup count") + } + wg.counter += delta + if wg.counter == 0 && wg.waiters > 0 { + for i := 0; i < wg.waiters; i++ { + runtime.Semrelease(wg.sema) + } + wg.waiters = 0 + wg.sema = nil + } + wg.m.Unlock() +} + +// Done decrements the WaitGroup counter. +func (wg *WaitGroup) Done() { + wg.Add(-1) +} + +// Wait blocks until the WaitGroup counter is zero. +func (wg *WaitGroup) Wait() { + wg.m.Lock() + if wg.counter == 0 { + wg.m.Unlock() + return + } + wg.waiters++ + if wg.sema == nil { + wg.sema = new(uint32) + } + s := wg.sema + wg.m.Unlock() + runtime.Semacquire(s) +} |