package aa
import (
"sync"
"sync/atomic"
_ "unsafe"
)
const rwmutexMaxReaders = 1 << 30
type RWMutex struct {
w sync.Mutex // held if there are pending writers
writerSem uint32 // semaphore for writers to wait for completing readers
readerSem uint32 // semaphore for readers to wait for completing writers
readerCount atomic.Int32 // number of pending readers
readerWait atomic.Int32 // number of departing readers
}
func (rw *RWMutex) RLock() {
if rw.readerCount.Add(1) < 0 {
// A writer is pending, wait for it.
runtime_SemacquireRWMutexR(&rw.readerSem, false, 0)
}
}
func (rw *RWMutex) RUnlock() {
if r := rw.readerCount.Add(-1); r < 0 {
if r+1 == 0 || r+1 == -rwmutexMaxReaders {
panic("sync: RUnlock of unlocked RWMutex")
}
// A writer is pending.
if rw.readerWait.Add(-1) == 0 {
// The last reader unblocks the writer.
runtime_Semrelease(&rw.writerSem, false, 1)
}
}
}
func (rw *RWMutex) WLock() {
// First, resolve competition with other writers.
rw.w.Lock()
// Announce to readers there is a pending writer.
r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders
// Wait for active readers.
if r != 0 && rw.readerWait.Add(r) != 0 {
runtime_SemacquireRWMutex(&rw.writerSem, false, 0)
}
}
func (rw *RWMutex) WUnlock() {
// Announce to readers there is no active writer.
r := rw.readerCount.Add(rwmutexMaxReaders)
if r >= rwmutexMaxReaders {
panic("sync: Unlock of unlocked RWMutex")
}
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
runtime_Semrelease(&rw.readerSem, false, 0)
}
// Allow other writers to proceed.
rw.w.Unlock()
}
//go:linkname runtime_SemacquireRWMutexR sync.runtime_SemacquireRWMutexR
func runtime_SemacquireRWMutexR(s *uint32, lifo bool, skipframes int)
//go:linkname runtime_SemacquireRWMutex sync.runtime_SemacquireRWMutex
func runtime_SemacquireRWMutex(s *uint32, lifo bool, skipframes int)
//go:linkname runtime_Semrelease sync.runtime_Semrelease
func runtime_Semrelease(s *uint32, handoff bool, skipframes int)
func TestName22(t *testing.T) {
m := new(RWMutex)
m.RLock()
m.RLock()
go func() {
m.WLock()
fmt.Println("w acquired")
m.WUnlock()
}()
time.Sleep(1 * time.Second)
m.RUnlock()
m.RUnlock()
}
package aa
import (
"sync"
"sync/atomic"
)
const rwmutexMaxReaders = 1 << 30
type RWMutex struct {
w, writerSem, readerSem sync.Mutex // held if there are pending writers
readerCount atomic.Int32 // number of pending readers
readerWait atomic.Int32 // number of departing readers
}
func NewRWMutex() *RWMutex {
r := new(RWMutex)
r.writerSem.Lock()
r.readerSem.Lock()
return r
}
func (rw *RWMutex) RLock() {
if rw.readerCount.Add(1) < 0 {
// A writer is pending, wait for it.
rw.readerSem.Lock()
}
}
func (rw *RWMutex) RUnlock() {
if r := rw.readerCount.Add(-1); r < 0 {
if r+1 == 0 || r+1 == -rwmutexMaxReaders {
panic("sync: RUnlock of unlocked RWMutex")
}
// A writer is pending.
if rw.readerWait.Add(-1) == 0 {
// The last reader unblocks the writer.
rw.writerSem.Unlock()
}
}
}
func (rw *RWMutex) WLock() {
// First, resolve competition with other writers.
rw.w.Lock()
// Announce to readers there is a pending writer.
r := rw.readerCount.Add(-rwmutexMaxReaders) + rwmutexMaxReaders
// Wait for active readers.
if r != 0 && rw.readerWait.Add(r) != 0 {
rw.writerSem.Lock()
}
}
func (rw *RWMutex) WUnlock() {
// Announce to readers there is no active writer.
r := rw.readerCount.Add(rwmutexMaxReaders)
if r >= rwmutexMaxReaders {
panic("sync: Unlock of unlocked RWMutex")
}
// Unblock blocked readers, if any.
for i := 0; i < int(r); i++ {
rw.readerSem.Unlock()
}
// Allow other writers to proceed.
rw.w.Unlock()
}