2018-04-27 17:37:02 +00:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
2019-04-29 21:25:05 +00:00
|
|
|
// Copyright 2019 The gVisor Authors.
|
2018-04-27 17:37:02 +00:00
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2019-12-07 07:08:39 +00:00
|
|
|
// +build go1.13
|
2019-10-29 20:17:01 +00:00
|
|
|
// +build !go1.15
|
2019-05-30 19:01:41 +00:00
|
|
|
|
|
|
|
// Check go:linkname function signatures when updating Go version.
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// This is mostly copied from the standard library's sync/rwmutex.go.
|
|
|
|
//
|
|
|
|
// Happens-before relationships indicated to the race detector:
|
|
|
|
// - Unlock -> Lock (via writerSem)
|
|
|
|
// - Unlock -> RLock (via readerSem)
|
|
|
|
// - RUnlock -> Lock (via writerSem)
|
|
|
|
// - DowngradeLock -> RLock (via readerSem)
|
|
|
|
|
2020-01-10 06:00:42 +00:00
|
|
|
package sync
|
2018-04-27 17:37:02 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"sync/atomic"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2019-05-30 19:01:41 +00:00
|
|
|
//go:linkname runtimeSemacquire sync.runtime_Semacquire
|
|
|
|
func runtimeSemacquire(s *uint32)
|
|
|
|
|
2019-12-07 07:08:39 +00:00
|
|
|
//go:linkname runtimeSemrelease sync.runtime_Semrelease
|
|
|
|
func runtimeSemrelease(s *uint32, handoff bool, skipframes int)
|
|
|
|
|
2020-01-22 03:23:26 +00:00
|
|
|
// RWMutex is identical to sync.RWMutex, but adds the DowngradeLock,
|
2020-01-22 02:34:24 +00:00
|
|
|
// TryLock and TryRLock methods.
|
2020-01-22 03:23:26 +00:00
|
|
|
type RWMutex struct {
|
|
|
|
w Mutex // held if there are pending writers
|
2020-01-22 02:34:24 +00:00
|
|
|
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
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const rwmutexMaxReaders = 1 << 30
|
|
|
|
|
2020-01-22 02:34:24 +00:00
|
|
|
// TryRLock locks rw for reading. It returns true if it succeeds and false
|
|
|
|
// otherwise. It does not block.
|
2020-01-22 03:23:26 +00:00
|
|
|
func (rw *RWMutex) TryRLock() bool {
|
2020-01-22 02:34:24 +00:00
|
|
|
if RaceEnabled {
|
|
|
|
RaceDisable()
|
|
|
|
}
|
|
|
|
for {
|
|
|
|
rc := atomic.LoadInt32(&rw.readerCount)
|
|
|
|
if rc < 0 {
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if !atomic.CompareAndSwapInt32(&rw.readerCount, rc, rc+1) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
RaceAcquire(unsafe.Pointer(&rw.readerSem))
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// RLock locks rw for reading.
|
2020-01-22 03:23:26 +00:00
|
|
|
func (rw *RWMutex) RLock() {
|
2018-04-27 17:37:02 +00:00
|
|
|
if RaceEnabled {
|
|
|
|
RaceDisable()
|
|
|
|
}
|
|
|
|
if atomic.AddInt32(&rw.readerCount, 1) < 0 {
|
|
|
|
// A writer is pending, wait for it.
|
|
|
|
runtimeSemacquire(&rw.readerSem)
|
|
|
|
}
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
RaceAcquire(unsafe.Pointer(&rw.readerSem))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RUnlock undoes a single RLock call.
|
2020-01-22 03:23:26 +00:00
|
|
|
func (rw *RWMutex) RUnlock() {
|
2018-04-27 17:37:02 +00:00
|
|
|
if RaceEnabled {
|
|
|
|
RaceReleaseMerge(unsafe.Pointer(&rw.writerSem))
|
|
|
|
RaceDisable()
|
|
|
|
}
|
|
|
|
if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
|
|
|
|
if r+1 == 0 || r+1 == -rwmutexMaxReaders {
|
2020-01-22 03:23:26 +00:00
|
|
|
panic("RUnlock of unlocked RWMutex")
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
// A writer is pending.
|
|
|
|
if atomic.AddInt32(&rw.readerWait, -1) == 0 {
|
|
|
|
// The last reader unblocks the writer.
|
2019-05-30 19:01:41 +00:00
|
|
|
runtimeSemrelease(&rw.writerSem, false, 0)
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-22 02:34:24 +00:00
|
|
|
// TryLock locks rw for writing. It returns true if it succeeds and false
|
|
|
|
// otherwise. It does not block.
|
2020-01-22 03:23:26 +00:00
|
|
|
func (rw *RWMutex) TryLock() bool {
|
2020-01-22 02:34:24 +00:00
|
|
|
if RaceEnabled {
|
|
|
|
RaceDisable()
|
|
|
|
}
|
|
|
|
// First, resolve competition with other writers.
|
|
|
|
if !rw.w.TryLock() {
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
// Only proceed if there are no readers.
|
|
|
|
if !atomic.CompareAndSwapInt32(&rw.readerCount, 0, -rwmutexMaxReaders) {
|
|
|
|
rw.w.Unlock()
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
RaceAcquire(unsafe.Pointer(&rw.writerSem))
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2018-04-27 17:37:02 +00:00
|
|
|
// Lock locks rw for writing.
|
2020-01-22 03:23:26 +00:00
|
|
|
func (rw *RWMutex) Lock() {
|
2018-04-27 17:37:02 +00:00
|
|
|
if RaceEnabled {
|
|
|
|
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 {
|
|
|
|
runtimeSemacquire(&rw.writerSem)
|
|
|
|
}
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
RaceAcquire(unsafe.Pointer(&rw.writerSem))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlock unlocks rw for writing.
|
2020-01-22 03:23:26 +00:00
|
|
|
func (rw *RWMutex) Unlock() {
|
2018-04-27 17:37:02 +00:00
|
|
|
if RaceEnabled {
|
|
|
|
RaceRelease(unsafe.Pointer(&rw.writerSem))
|
|
|
|
RaceRelease(unsafe.Pointer(&rw.readerSem))
|
|
|
|
RaceDisable()
|
|
|
|
}
|
|
|
|
// Announce to readers there is no active writer.
|
|
|
|
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
|
|
|
|
if r >= rwmutexMaxReaders {
|
2020-01-22 03:23:26 +00:00
|
|
|
panic("Unlock of unlocked RWMutex")
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
// Unblock blocked readers, if any.
|
|
|
|
for i := 0; i < int(r); i++ {
|
2019-05-30 19:01:41 +00:00
|
|
|
runtimeSemrelease(&rw.readerSem, false, 0)
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
// Allow other writers to proceed.
|
|
|
|
rw.w.Unlock()
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DowngradeLock atomically unlocks rw for writing and locks it for reading.
|
2020-01-22 03:23:26 +00:00
|
|
|
func (rw *RWMutex) DowngradeLock() {
|
2018-04-27 17:37:02 +00:00
|
|
|
if RaceEnabled {
|
|
|
|
RaceRelease(unsafe.Pointer(&rw.readerSem))
|
|
|
|
RaceDisable()
|
|
|
|
}
|
|
|
|
// Announce to readers there is no active writer and one additional reader.
|
|
|
|
r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders+1)
|
|
|
|
if r >= rwmutexMaxReaders+1 {
|
2020-01-22 03:23:26 +00:00
|
|
|
panic("DowngradeLock of unlocked RWMutex")
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
// Unblock blocked readers, if any. Note that this loop starts as 1 since r
|
|
|
|
// includes this goroutine.
|
|
|
|
for i := 1; i < int(r); i++ {
|
2019-05-30 19:01:41 +00:00
|
|
|
runtimeSemrelease(&rw.readerSem, false, 0)
|
2018-04-27 17:37:02 +00:00
|
|
|
}
|
|
|
|
// Allow other writers to proceed to rw.w.Lock(). Note that they will still
|
|
|
|
// block on rw.writerSem since at least this reader exists, such that
|
|
|
|
// DowngradeLock() is atomic with the previous write lock.
|
|
|
|
rw.w.Unlock()
|
|
|
|
if RaceEnabled {
|
|
|
|
RaceEnable()
|
|
|
|
}
|
|
|
|
}
|