f8d9fa9e80
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. From-SVN: r219627
137 lines
3.7 KiB
Go
137 lines
3.7 KiB
Go
// Copyright 2009 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 (
|
|
"sync/atomic"
|
|
"unsafe"
|
|
)
|
|
|
|
// An RWMutex is a reader/writer mutual exclusion lock.
|
|
// The lock can be held by an arbitrary number of readers
|
|
// or a single writer.
|
|
// RWMutexes can be created as part of other
|
|
// structures; the zero value for a RWMutex is
|
|
// an unlocked mutex.
|
|
type RWMutex struct {
|
|
w Mutex // held if there are pending writers
|
|
writerSem uint32 // semaphore for writers to wait for completing readers
|
|
readerSem uint32 // semaphore for readers to wait for completing writers
|
|
readerCount int32 // number of pending readers
|
|
readerWait int32 // number of departing readers
|
|
}
|
|
|
|
const rwmutexMaxReaders = 1 << 30
|
|
|
|
// RLock locks rw for reading.
|
|
func (rw *RWMutex) RLock() {
|
|
if raceenabled {
|
|
_ = rw.w.state
|
|
raceDisable()
|
|
}
|
|
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
|
|
// A writer is pending, wait for it.
|
|
runtime_Semacquire(&rw.readerSem)
|
|
}
|
|
if raceenabled {
|
|
raceEnable()
|
|
raceAcquire(unsafe.Pointer(&rw.readerSem))
|
|
}
|
|
}
|
|
|
|
// RUnlock undoes a single RLock call;
|
|
// it does not affect other simultaneous readers.
|
|
// It is a run-time error if rw is not locked for reading
|
|
// on entry to RUnlock.
|
|
func (rw *RWMutex) RUnlock() {
|
|
if raceenabled {
|
|
_ = rw.w.state
|
|
raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
|
|
raceDisable()
|
|
}
|
|
if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
|
|
if r+1 == 0 || r+1 == -rwmutexMaxReaders {
|
|
raceEnable()
|
|
panic("sync: RUnlock of unlocked RWMutex")
|
|
}
|
|
// A writer is pending.
|
|
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
|
|
// The last reader unblocks the writer.
|
|
runtime_Semrelease(&rw.writerSem)
|
|
}
|
|
}
|
|
if raceenabled {
|
|
raceEnable()
|
|
}
|
|
}
|
|
|
|
// Lock locks rw for writing.
|
|
// If the lock is already locked for reading or writing,
|
|
// Lock blocks until the lock is available.
|
|
// To ensure that the lock eventually becomes available,
|
|
// a blocked Lock call excludes new readers from acquiring
|
|
// the lock.
|
|
func (rw *RWMutex) Lock() {
|
|
if raceenabled {
|
|
_ = rw.w.state
|
|
raceDisable()
|
|
}
|
|
// First, resolve competition with other writers.
|
|
rw.w.Lock()
|
|
// Announce to readers there is a pending writer.
|
|
r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
|
|
// Wait for active readers.
|
|
if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
|
|
runtime_Semacquire(&rw.writerSem)
|
|
}
|
|
if raceenabled {
|
|
raceEnable()
|
|
raceAcquire(unsafe.Pointer(&rw.readerSem))
|
|
raceAcquire(unsafe.Pointer(&rw.writerSem))
|
|
}
|
|
}
|
|
|
|
// Unlock unlocks rw for writing. It is a run-time error if rw is
|
|
// not locked for writing on entry to Unlock.
|
|
//
|
|
// As with Mutexes, a locked RWMutex is not associated with a particular
|
|
// goroutine. One goroutine may RLock (Lock) an RWMutex and then
|
|
// arrange for another goroutine to RUnlock (Unlock) it.
|
|
func (rw *RWMutex) Unlock() {
|
|
if raceenabled {
|
|
_ = rw.w.state
|
|
raceRelease(unsafe.Pointer(&rw.readerSem))
|
|
raceRelease(unsafe.Pointer(&rw.writerSem))
|
|
raceDisable()
|
|
}
|
|
|
|
// Announce to readers there is no active writer.
|
|
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
|
|
if r >= rwmutexMaxReaders {
|
|
raceEnable()
|
|
panic("sync: Unlock of unlocked RWMutex")
|
|
}
|
|
// Unblock blocked readers, if any.
|
|
for i := 0; i < int(r); i++ {
|
|
runtime_Semrelease(&rw.readerSem)
|
|
}
|
|
// Allow other writers to proceed.
|
|
rw.w.Unlock()
|
|
if raceenabled {
|
|
raceEnable()
|
|
}
|
|
}
|
|
|
|
// RLocker returns a Locker interface that implements
|
|
// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
|
|
func (rw *RWMutex) RLocker() Locker {
|
|
return (*rlocker)(rw)
|
|
}
|
|
|
|
type rlocker RWMutex
|
|
|
|
func (r *rlocker) Lock() { (*RWMutex)(r).RLock() }
|
|
func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
|