Source File
	rwmutex.go
Belonging Package
	runtime
// 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 runtimeimport ()// This is a copy of sync/rwmutex.go rewritten to work in the runtime.// A 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.// Like mutex, rwmutex blocks the calling M.// It does not interact with the goroutine scheduler.type rwmutex struct {rLock mutex // protects readers, readerPass, writerreaders muintptr // list of pending readersreaderPass uint32 // number of pending readers to skip readers listwLock mutex // serializes writerswriter muintptr // pending writer waiting for completing readersreaderCount atomic.Int32 // number of pending readersreaderWait atomic.Int32 // number of departing readersreadRank lockRank // semantic lock rank for read locking}// Lock ranking an rwmutex has two aspects://// Semantic ranking: this rwmutex represents some higher level lock that// protects some resource (e.g., allocmLock protects creation of new Ms). The// read and write locks of that resource need to be represented in the lock// rank.//// Internal ranking: as an implementation detail, rwmutex uses two mutexes:// rLock and wLock. These have lock order requirements: wLock must be locked// before rLock. This also needs to be represented in the lock rank.//// Semantic ranking is represented by acquiring readRank during read lock and// writeRank during write lock.//// wLock is held for the duration of a write lock, so it uses writeRank// directly, both for semantic and internal ranking. rLock is only held// temporarily inside the rlock/lock methods, so it uses readRankInternal to// represent internal ranking. Semantic ranking is represented by a separate// acquire of readRank for the duration of a read lock.//// The lock ranking must document this ordering:// - readRankInternal is a leaf lock.// - readRank is taken before readRankInternal.// - writeRank is taken before readRankInternal.// - readRank is placed in the lock order wherever a read lock of this rwmutex// belongs.// - writeRank is placed in the lock order wherever a write lock of this// rwmutex belongs.func ( *rwmutex) (, , lockRank) {.readRank =lockInit(&.rLock, )lockInit(&.wLock, )}const rwmutexMaxReaders = 1 << 30// rlock locks rw for reading.func ( *rwmutex) () {// The reader must not be allowed to lose its P or else other// things blocking on the lock may consume all of the Ps and// deadlock (issue #20903). Alternatively, we could drop the P// while sleeping.acquireLockRankAndM(.readRank)lockWithRankMayAcquire(&.rLock, getLockRank(&.rLock))if .readerCount.Add(1) < 0 {// A writer is pending. Park on the reader queue.systemstack(func() {lock(&.rLock)if .readerPass > 0 {// Writer finished..readerPass -= 1unlock(&.rLock)} else {// Queue this reader to be woken by// the writer.:= getg().m.schedlink = .readers.readers.set()unlock(&.rLock)notesleep(&.park)noteclear(&.park)}})}}// runlock undoes a single rlock call on rw.func ( *rwmutex) () {if := .readerCount.Add(-1); < 0 {if +1 == 0 || +1 == -rwmutexMaxReaders {throw("runlock of unlocked rwmutex")}// A writer is pending.if .readerWait.Add(-1) == 0 {// The last reader unblocks the writer.lock(&.rLock):= .writer.ptr()if != nil {notewakeup(&.park)}unlock(&.rLock)}}releaseLockRankAndM(.readRank)}// lock locks rw for writing.func ( *rwmutex) () {// Resolve competition with other writers and stick to our P.lock(&.wLock):= getg().m// Announce that there is a pending writer.:= .readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders// Wait for any active readers to complete.lock(&.rLock)if != 0 && .readerWait.Add() != 0 {// Wait for reader to wake us up.systemstack(func() {.writer.set()unlock(&.rLock)notesleep(&.park)noteclear(&.park)})} else {unlock(&.rLock)}}// unlock unlocks rw for writing.func ( *rwmutex) () {// Announce to readers that there is no active writer.:= .readerCount.Add(rwmutexMaxReaders)if >= rwmutexMaxReaders {throw("unlock of unlocked rwmutex")}// Unblock blocked readers.lock(&.rLock)for .readers.ptr() != nil {:= .readers.ptr().readers = .schedlink.schedlink.set(nil)notewakeup(&.park)-= 1}// If r > 0, there are pending readers that aren't on the// queue. Tell them to skip waiting..readerPass += uint32()unlock(&.rLock)// Allow other writers to proceed.unlock(&.wLock)}
|  | The pages are generated with Golds v0.7.6. (GOOS=linux GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds. |