github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/runtime/rwmutex.go (about) 1 // Copyright 2017 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 runtime 6 7 import ( 8 "runtime/internal/atomic" 9 ) 10 11 // This is a copy of sync/rwmutex.go rewritten to work in the runtime. 12 13 // A rwmutex is a reader/writer mutual exclusion lock. 14 // The lock can be held by an arbitrary number of readers or a single writer. 15 // This is a variant of sync.RWMutex, for the runtime package. 16 // Like mutex, rwmutex blocks the calling M. 17 // It does not interact with the goroutine scheduler. 18 // 不与go scheduler交流, 阻塞m 19 type rwmutex struct { 20 rLock mutex // protects readers, readerPass, writer 21 readers muintptr // list of pending readers 22 readerPass uint32 // number of pending readers to skip readers list 23 24 wLock mutex // serializes writers 25 writer muintptr // pending writer waiting for completing readers 26 27 readerCount uint32 // number of pending readers 28 readerWait uint32 // number of departing readers 29 } 30 31 const rwmutexMaxReaders = 1 << 30 32 33 // rlock locks rw for reading. 34 func (rw *rwmutex) rlock() { 35 // The reader must not be allowed to lose its P or else other 36 // things blocking on the lock may consume all of the Ps and 37 // deadlock (issue #20903). Alternatively, we could drop the P 38 // while sleeping. 39 acquirem() 40 if int32(atomic.Xadd(&rw.readerCount, 1)) < 0 { 41 // A writer is pending. Park on the reader queue. 42 systemstack(func() { 43 lock(&rw.rLock) 44 if rw.readerPass > 0 { 45 // Writer finished. 46 rw.readerPass -= 1 47 unlock(&rw.rLock) 48 } else { 49 // Queue this reader to be woken by 50 // the writer. 51 m := getg().m 52 m.schedlink = rw.readers 53 rw.readers.set(m) 54 unlock(&rw.rLock) 55 notesleep(&m.park) 56 noteclear(&m.park) 57 } 58 }) 59 } 60 } 61 62 // runlock undoes a single rlock call on rw. 63 func (rw *rwmutex) runlock() { 64 if r := int32(atomic.Xadd(&rw.readerCount, -1)); r < 0 { 65 if r+1 == 0 || r+1 == -rwmutexMaxReaders { 66 throw("runlock of unlocked rwmutex") 67 } 68 // A writer is pending. 69 if atomic.Xadd(&rw.readerWait, -1) == 0 { 70 // The last reader unblocks the writer. 71 lock(&rw.rLock) 72 w := rw.writer.ptr() 73 if w != nil { 74 notewakeup(&w.park) 75 } 76 unlock(&rw.rLock) 77 } 78 } 79 releasem(getg().m) 80 } 81 82 // lock locks rw for writing. 83 func (rw *rwmutex) lock() { 84 // Resolve competition with other writers and stick to our P. 85 lock(&rw.wLock) 86 m := getg().m 87 // Announce that there is a pending writer. 88 r := int32(atomic.Xadd(&rw.readerCount, -rwmutexMaxReaders)) + rwmutexMaxReaders 89 // Wait for any active readers to complete. 90 lock(&rw.rLock) 91 if r != 0 && atomic.Xadd(&rw.readerWait, r) != 0 { 92 // Wait for reader to wake us up. 93 systemstack(func() { 94 rw.writer.set(m) 95 unlock(&rw.rLock) 96 notesleep(&m.park) 97 noteclear(&m.park) 98 }) 99 } else { 100 unlock(&rw.rLock) 101 } 102 } 103 104 // unlock unlocks rw for writing. 105 func (rw *rwmutex) unlock() { 106 // Announce to readers that there is no active writer. 107 r := int32(atomic.Xadd(&rw.readerCount, rwmutexMaxReaders)) 108 if r >= rwmutexMaxReaders { 109 throw("unlock of unlocked rwmutex") 110 } 111 // Unblock blocked readers. 112 lock(&rw.rLock) 113 for rw.readers.ptr() != nil { 114 reader := rw.readers.ptr() 115 rw.readers = reader.schedlink 116 reader.schedlink.set(nil) 117 notewakeup(&reader.park) 118 r -= 1 119 } 120 // If r > 0, there are pending readers that aren't on the 121 // queue. Tell them to skip waiting. 122 rw.readerPass += uint32(r) 123 unlock(&rw.rLock) 124 // Allow other writers to proceed. 125 unlock(&rw.wLock) 126 }