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 readers}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.acquirem()if .readerCount.Add(1) < 0 {// A writer is pending. Park on the reader queue.systemstack(func() {lockWithRank(&.rLock, lockRankRwmutexR)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.lockWithRank(&.rLock, lockRankRwmutexR):= .writer.ptr()if != nil {notewakeup(&.park)}unlock(&.rLock)}}releasem(getg().m)}// lock locks rw for writing.func ( *rwmutex) () {// Resolve competition with other writers and stick to our P.lockWithRank(&.wLock, lockRankRwmutexW):= getg().m// Announce that there is a pending writer.:= .readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders// Wait for any active readers to complete.lockWithRank(&.rLock, lockRankRwmutexR)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.lockWithRank(&.rLock, lockRankRwmutexR)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.6.7. (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 @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |