URL
                    https://opencores.org/ocsvn/openrisc/openrisc/trunk
                
            Subversion Repositories openrisc
[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [sync/] [cond.go] - Rev 747
Compare with Previous | Blame | View Log
// 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 syncimport "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 conditionm Mutex // held to avoid internal races// We must be careful to make sure that when Signal// releases a semaphore, the corresponding acquire is// executed by a goroutine that was already waiting at// the time of the call to Signal, not one that arrived later.// To ensure this, we segment waiting goroutines into// generations punctuated by calls to Signal. Each call to// Signal begins another generation if there are no goroutines// left in older generations for it to wake. Because of this// optimization (only begin another generation if there// are no older goroutines left), we only need to keep track// of the two most recent generations, which we call old// and new.oldWaiters int // number of waiters in old generation...oldSema *uint32 // ... waiting on this semaphorenewWaiters int // number of waiters in new generation...newSema *uint32 // ... waiting on this semaphore}// 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.newSema == nil {c.newSema = new(uint32)}s := c.newSemac.newWaiters++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.oldWaiters == 0 && c.newWaiters > 0 {// Retire old generation; rename new to old.c.oldWaiters = c.newWaitersc.oldSema = c.newSemac.newWaiters = 0c.newSema = nil}if c.oldWaiters > 0 {c.oldWaiters--runtime.Semrelease(c.oldSema)}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()// Wake both generations.if c.oldWaiters > 0 {for i := 0; i < c.oldWaiters; i++ {runtime.Semrelease(c.oldSema)}c.oldWaiters = 0}if c.newWaiters > 0 {for i := 0; i < c.newWaiters; i++ {runtime.Semrelease(c.newSema)}c.newWaiters = 0c.newSema = nil}c.m.Unlock()}
