aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/rwmutex.go
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-06-15 16:42:08 -0700
committerIan Lance Taylor <iant@golang.org>2017-06-19 17:40:38 +0000
commit09ebbf408530b82f1a817e2f648e1c5618eeb1ab (patch)
tree52a58a8e584a8f1d9a90605e1db41d6e725df626 /src/runtime/rwmutex.go
parent6c2458e72d85dd0d388e4d27b6b361899084d526 (diff)
downloadgo-09ebbf408530b82f1a817e2f648e1c5618eeb1ab.tar.gz
go-09ebbf408530b82f1a817e2f648e1c5618eeb1ab.zip
runtime: add read/write mutex type
This is a runtime version of sync.RWMutex that can be used by code in the runtime package. The type is not quite the same, in that the zero value is not valid. For future use by CL 43713. Updates #19546 Change-Id: I431eb3688add16ce1274dab97285f555b72735bf Reviewed-on: https://go-review.googlesource.com/45991 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/rwmutex.go')
-rw-r--r--src/runtime/rwmutex.go80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/runtime/rwmutex.go b/src/runtime/rwmutex.go
new file mode 100644
index 0000000000..7b32769915
--- /dev/null
+++ b/src/runtime/rwmutex.go
@@ -0,0 +1,80 @@
+// Copyright 2017 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 runtime
+
+import (
+ "runtime/internal/atomic"
+)
+
+// This is a copy of sync/rwmutex.go rewritten to work in the runtime.
+
+// An rwmutex is a reader/writer mutual exclusion lock.
+// The lock can be held by an arbitrary number of readers or a single writer.
+// This is a variant of sync.RWMutex, for the runtime package.
+// This is less convenient than sync.RWMutex, because it must be
+// initialized before use. Sorry.
+type rwmutex struct {
+ w uint32 // semaphore for pending writers
+ writerSem uint32 // semaphore for writers to wait for completing readers
+ readerSem uint32 // semaphore for readers to wait for completing writers
+ readerCount uint32 // number of pending readers
+ readerWait uint32 // number of departing readers
+}
+
+const rwmutexMaxReaders = 1 << 30
+
+// init initializes rw. This must be called before any other methods.
+func (rw *rwmutex) init() {
+ rw.w = 1
+}
+
+// rlock locks rw for reading.
+func (rw *rwmutex) rlock() {
+ if int32(atomic.Xadd(&rw.readerCount, 1)) < 0 {
+ // A writer is pending.
+ semacquire(&rw.readerSem)
+ }
+}
+
+// runlock undoes a single rlock call on rw.
+func (rw *rwmutex) runlock() {
+ if r := int32(atomic.Xadd(&rw.readerCount, -1)); r < 0 {
+ if r+1 == 0 || r+1 == -rwmutexMaxReaders {
+ throw("runlock of unlocked rwmutex")
+ }
+ // A writer is pending.
+ if atomic.Xadd(&rw.readerWait, -1) == 0 {
+ // The last reader unblocks the writer.
+ semrelease(&rw.writerSem)
+ }
+ }
+}
+
+// lock locks rw for writing.
+func (rw *rwmutex) lock() {
+ // Resolve competition with other writers.
+ semacquire(&rw.w)
+ // Announce that there is a pending writer.
+ r := int32(atomic.Xadd(&rw.readerCount, -rwmutexMaxReaders)) + rwmutexMaxReaders
+ // Wait for any active readers to complete.
+ if r != 0 && atomic.Xadd(&rw.readerWait, r) != 0 {
+ semacquire(&rw.writerSem)
+ }
+}
+
+// unlock unlocks rw for writing.
+func (rw *rwmutex) unlock() {
+ // Announce to readers that there is no active writer.
+ r := int32(atomic.Xadd(&rw.readerCount, rwmutexMaxReaders))
+ if r >= rwmutexMaxReaders {
+ throw("unlock of unlocked rwmutex")
+ }
+ // Unblock blocked readers, if any.
+ for i := int32(0); i < r; i++ {
+ semrelease(&rw.readerSem)
+ }
+ // Allow other writers to proceed.
+ semrelease(&rw.w)
+}