Source file src/pkg/sync/rwmutex.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package sync
6
7 import "sync/atomic"
8
9 // An RWMutex is a reader/writer mutual exclusion lock.
10 // The lock can be held by an arbitrary number of readers
11 // or a single writer.
12 // RWMutexes can be created as part of other
13 // structures; the zero value for a RWMutex is
14 // an unlocked mutex.
15 type RWMutex struct {
16 w Mutex // held if there are pending writers
17 writerSem uint32 // semaphore for writers to wait for completing readers
18 readerSem uint32 // semaphore for readers to wait for completing writers
19 readerCount int32 // number of pending readers
20 readerWait int32 // number of departing readers
21 }
22
23 const rwmutexMaxReaders = 1 << 30
24
25 // RLock locks rw for reading.
26 func (rw *RWMutex) RLock() {
27 if atomic.AddInt32(&rw.readerCount, 1) < 0 {
28 // A writer is pending, wait for it.
29 runtime_Semacquire(&rw.readerSem)
30 }
31 }
32
33 // RUnlock undoes a single RLock call;
34 // it does not affect other simultaneous readers.
35 // It is a run-time error if rw is not locked for reading
36 // on entry to RUnlock.
37 func (rw *RWMutex) RUnlock() {
38 if atomic.AddInt32(&rw.readerCount, -1) < 0 {
39 // A writer is pending.
40 if atomic.AddInt32(&rw.readerWait, -1) == 0 {
41 // The last reader unblocks the writer.
42 runtime_Semrelease(&rw.writerSem)
43 }
44 }
45 }
46
47 // Lock locks rw for writing.
48 // If the lock is already locked for reading or writing,
49 // Lock blocks until the lock is available.
50 // To ensure that the lock eventually becomes available,
51 // a blocked Lock call excludes new readers from acquiring
52 // the lock.
53 func (rw *RWMutex) Lock() {
54 // First, resolve competition with other writers.
55 rw.w.Lock()
56 // Announce to readers there is a pending writer.
57 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders
58 // Wait for active readers.
59 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 {
60 runtime_Semacquire(&rw.writerSem)
61 }
62 }
63
64 // Unlock unlocks rw for writing. It is a run-time error if rw is
65 // not locked for writing on entry to Unlock.
66 //
67 // As with Mutexes, a locked RWMutex is not associated with a particular
68 // goroutine. One goroutine may RLock (Lock) an RWMutex and then
69 // arrange for another goroutine to RUnlock (Unlock) it.
70 func (rw *RWMutex) Unlock() {
71 // Announce to readers there is no active writer.
72 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
73 // Unblock blocked readers, if any.
74 for i := 0; i < int(r); i++ {
75 runtime_Semrelease(&rw.readerSem)
76 }
77 // Allow other writers to proceed.
78 rw.w.Unlock()
79 }
80
81 // RLocker returns a Locker interface that implements
82 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
83 func (rw *RWMutex) RLocker() Locker {
84 return (*rlocker)(rw)
85 }
86
87 type rlocker RWMutex
88
89 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() }
90 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }