1
0
mirror of https://github.com/golang/go synced 2024-11-12 08:50:22 -07:00

race: sync changes

This is a part of a bigger change that adds data race detection feature:
https://golang.org/cl/6456044

R=rsc, minux.ma
CC=gobot, golang-dev
https://golang.org/cl/6529053
This commit is contained in:
Dmitriy Vyukov 2012-10-07 22:07:03 +04:00
parent 2f6cbc74f1
commit 53390c8fc7
7 changed files with 159 additions and 4 deletions

View File

@ -30,7 +30,7 @@ var pkgDeps = map[string][]string{
"errors": {},
"io": {"errors", "sync"},
"runtime": {"unsafe"},
"sync": {"sync/atomic"},
"sync": {"sync/atomic", "unsafe"},
"sync/atomic": {"unsafe"},
"unsafe": {},

View File

@ -56,6 +56,9 @@ func NewCond(l Locker) *Cond {
// c.L.Unlock()
//
func (c *Cond) Wait() {
if raceenabled {
raceDisable()
}
c.m.Lock()
if c.newSema == nil {
c.newSema = new(uint32)
@ -63,6 +66,9 @@ func (c *Cond) Wait() {
s := c.newSema
c.newWaiters++
c.m.Unlock()
if raceenabled {
raceEnable()
}
c.L.Unlock()
runtime_Semacquire(s)
c.L.Lock()
@ -73,6 +79,9 @@ func (c *Cond) Wait() {
// It is allowed but not required for the caller to hold c.L
// during the call.
func (c *Cond) Signal() {
if raceenabled {
raceDisable()
}
c.m.Lock()
if c.oldWaiters == 0 && c.newWaiters > 0 {
// Retire old generation; rename new to old.
@ -86,6 +95,9 @@ func (c *Cond) Signal() {
runtime_Semrelease(c.oldSema)
}
c.m.Unlock()
if raceenabled {
raceEnable()
}
}
// Broadcast wakes all goroutines waiting on c.
@ -93,6 +105,9 @@ func (c *Cond) Signal() {
// It is allowed but not required for the caller to hold c.L
// during the call.
func (c *Cond) Broadcast() {
if raceenabled {
raceDisable()
}
c.m.Lock()
// Wake both generations.
if c.oldWaiters > 0 {
@ -109,4 +124,7 @@ func (c *Cond) Broadcast() {
c.newSema = nil
}
c.m.Unlock()
if raceenabled {
raceEnable()
}
}

View File

@ -10,7 +10,10 @@
// Values containing the types defined in this package should not be copied.
package sync
import "sync/atomic"
import (
"sync/atomic"
"unsafe"
)
// A Mutex is a mutual exclusion lock.
// Mutexes can be created as part of other structures;
@ -38,6 +41,9 @@ const (
func (m *Mutex) Lock() {
// Fast path: grab unlocked mutex.
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
if raceenabled {
raceAcquire(unsafe.Pointer(m))
}
return
}
@ -61,6 +67,10 @@ func (m *Mutex) Lock() {
awoke = true
}
}
if raceenabled {
raceAcquire(unsafe.Pointer(m))
}
}
// Unlock unlocks m.
@ -70,6 +80,10 @@ func (m *Mutex) Lock() {
// It is allowed for one goroutine to lock a Mutex and then
// arrange for another goroutine to unlock it.
func (m *Mutex) Unlock() {
if raceenabled {
raceRelease(unsafe.Pointer(m))
}
// Fast path: drop lock bit.
new := atomic.AddInt32(&m.state, -mutexLocked)
if (new+mutexLocked)&mutexLocked == 0 {

34
src/pkg/sync/race.go Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2012 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.
// +build race
package sync
import (
"runtime"
"unsafe"
)
const raceenabled = true
func raceAcquire(addr unsafe.Pointer) {
runtime.RaceAcquire(addr)
}
func raceRelease(addr unsafe.Pointer) {
runtime.RaceRelease(addr)
}
func raceReleaseMerge(addr unsafe.Pointer) {
runtime.RaceReleaseMerge(addr)
}
func raceDisable() {
runtime.RaceDisable()
}
func raceEnable() {
runtime.RaceEnable()
}

28
src/pkg/sync/race0.go Normal file
View File

@ -0,0 +1,28 @@
// Copyright 2012 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.
// +build !race
package sync
import (
"unsafe"
)
const raceenabled = false
func raceAcquire(addr unsafe.Pointer) {
}
func raceRelease(addr unsafe.Pointer) {
}
func raceReleaseMerge(addr unsafe.Pointer) {
}
func raceDisable() {
}
func raceEnable() {
}

View File

@ -4,7 +4,10 @@
package sync
import "sync/atomic"
import (
"sync/atomic"
"unsafe"
)
// An RWMutex is a reader/writer mutual exclusion lock.
// The lock can be held by an arbitrary number of readers
@ -24,10 +27,17 @@ const rwmutexMaxReaders = 1 << 30
// RLock locks rw for reading.
func (rw *RWMutex) RLock() {
if raceenabled {
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;
@ -35,6 +45,10 @@ func (rw *RWMutex) RLock() {
// It is a run-time error if rw is not locked for reading
// on entry to RUnlock.
func (rw *RWMutex) RUnlock() {
if raceenabled {
raceReleaseMerge(unsafe.Pointer(&rw.writerSem))
raceDisable()
}
if atomic.AddInt32(&rw.readerCount, -1) < 0 {
// A writer is pending.
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
@ -42,6 +56,9 @@ func (rw *RWMutex) RUnlock() {
runtime_Semrelease(&rw.writerSem)
}
}
if raceenabled {
raceEnable()
}
}
// Lock locks rw for writing.
@ -51,6 +68,9 @@ func (rw *RWMutex) RUnlock() {
// a blocked Lock call excludes new readers from acquiring
// the lock.
func (rw *RWMutex) Lock() {
if raceenabled {
raceDisable()
}
// First, resolve competition with other writers.
rw.w.Lock()
// Announce to readers there is a pending writer.
@ -59,6 +79,11 @@ func (rw *RWMutex) Lock() {
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
@ -68,6 +93,12 @@ func (rw *RWMutex) Lock() {
// goroutine. One goroutine may RLock (Lock) an RWMutex and then
// arrange for another goroutine to RUnlock (Unlock) it.
func (rw *RWMutex) Unlock() {
if raceenabled {
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)
// Unblock blocked readers, if any.
@ -76,6 +107,9 @@ func (rw *RWMutex) Unlock() {
}
// Allow other writers to proceed.
rw.w.Unlock()
if raceenabled {
raceEnable()
}
}
// RLocker returns a Locker interface that implements

View File

@ -4,7 +4,10 @@
package sync
import "sync/atomic"
import (
"sync/atomic"
"unsafe"
)
// A WaitGroup waits for a collection of goroutines to finish.
// The main goroutine calls Add to set the number of
@ -34,6 +37,11 @@ type WaitGroup struct {
// If the counter becomes zero, all goroutines blocked on Wait() are released.
// If the counter goes negative, Add panics.
func (wg *WaitGroup) Add(delta int) {
if raceenabled {
raceReleaseMerge(unsafe.Pointer(wg))
raceDisable()
defer raceEnable()
}
v := atomic.AddInt32(&wg.counter, int32(delta))
if v < 0 {
panic("sync: negative WaitGroup counter")
@ -57,7 +65,14 @@ func (wg *WaitGroup) Done() {
// Wait blocks until the WaitGroup counter is zero.
func (wg *WaitGroup) Wait() {
if raceenabled {
raceDisable()
}
if atomic.LoadInt32(&wg.counter) == 0 {
if raceenabled {
raceEnable()
raceAcquire(unsafe.Pointer(wg))
}
return
}
wg.m.Lock()
@ -68,7 +83,15 @@ func (wg *WaitGroup) Wait() {
// to avoid missing an Add.
if atomic.LoadInt32(&wg.counter) == 0 {
atomic.AddInt32(&wg.waiters, -1)
if raceenabled {
raceEnable()
raceAcquire(unsafe.Pointer(wg))
raceDisable()
}
wg.m.Unlock()
if raceenabled {
raceEnable()
}
return
}
if wg.sema == nil {
@ -77,4 +100,8 @@ func (wg *WaitGroup) Wait() {
s := wg.sema
wg.m.Unlock()
runtime_Semacquire(s)
if raceenabled {
raceEnable()
raceAcquire(unsafe.Pointer(wg))
}
}