diff options
author | Ondřej Surý <ondrej@sury.org> | 2011-04-20 15:44:41 +0200 |
---|---|---|
committer | Ondřej Surý <ondrej@sury.org> | 2011-04-20 15:44:41 +0200 |
commit | 50104cc32a498f7517a51c8dc93106c51c7a54b4 (patch) | |
tree | 47af80be259cc7c45d0eaec7d42e61fa38c8e4fb /src/pkg/sync/cond.go | |
parent | c072558b90f1bbedc2022b0f30c8b1ac4712538e (diff) | |
download | golang-upstream/2011.03.07.1.tar.gz |
Imported Upstream version 2011.03.07.1upstream/2011.03.07.1
Diffstat (limited to 'src/pkg/sync/cond.go')
-rw-r--r-- | src/pkg/sync/cond.go | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/src/pkg/sync/cond.go b/src/pkg/sync/cond.go new file mode 100644 index 000000000..ea48f2e7a --- /dev/null +++ b/src/pkg/sync/cond.go @@ -0,0 +1,90 @@ +// 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" + +// Cond implements a condition variable, a rendezvous point +// for goroutines waiting for or announcing the occurrence +// of an event. +// +// Each Cond has an associated Locker L (often a *Mutex or *RWMutex), +// which must be held when changing the condition and +// when calling the Wait method. +type Cond struct { + L Locker // held while observing or changing the condition + m Mutex // held to avoid internal races + waiters int // number of goroutines blocked on Wait + sema *uint32 +} + +// NewCond returns a new Cond with Locker l. +func NewCond(l Locker) *Cond { + return &Cond{L: l} +} + +// Wait atomically unlocks c.L and suspends execution +// of the calling goroutine. After later resuming execution, +// Wait locks c.L before returning. +// +// Because L is not locked when Wait first resumes, the caller +// typically cannot assume that the condition is true when +// Wait returns. Instead, the caller should Wait in a loop: +// +// c.L.Lock() +// for !condition() { +// c.Wait() +// } +// ... make use of condition ... +// c.L.Unlock() +// +func (c *Cond) Wait() { + c.m.Lock() + if c.sema == nil { + c.sema = new(uint32) + } + s := c.sema + c.waiters++ + c.m.Unlock() + c.L.Unlock() + runtime.Semacquire(s) + c.L.Lock() +} + +// Signal wakes one goroutine waiting on c, if there is any. +// +// It is allowed but not required for the caller to hold c.L +// during the call. +func (c *Cond) Signal() { + c.m.Lock() + if c.waiters > 0 { + c.waiters-- + runtime.Semrelease(c.sema) + } + c.m.Unlock() +} + +// Broadcast wakes all goroutines waiting on c. +// +// It is allowed but not required for the caller to hold c.L +// during the call. +func (c *Cond) Broadcast() { + c.m.Lock() + if c.waiters > 0 { + s := c.sema + n := c.waiters + for i := 0; i < n; i++ { + runtime.Semrelease(s) + } + // We just issued n wakeups via the semaphore s. + // To ensure that they wake up the existing waiters + // and not waiters that arrive after Broadcast returns, + // clear c.sema. The next operation will allocate + // a new one. + c.sema = nil + c.waiters = 0 + } + c.m.Unlock() +} |