pkg/sync/rwmutex.go (38 lines of code) (raw):
package sync
import (
"sync"
"sync/atomic"
)
// CountingRWMutex is a RWMutex that keeps track of the number of goroutines waiting for the lock.
type CountingRWMutex struct {
mu sync.RWMutex
waiting int64
limit int64
}
func NewCountingRWMutex(limit int) *CountingRWMutex {
return &CountingRWMutex{limit: int64(limit)}
}
// RLock locks rw for reading.
func (rw *CountingRWMutex) RLock() {
atomic.AddInt64(&rw.waiting, 1)
rw.mu.RLock()
}
// RUnlock undoes a single RLock call; it does not affect other simultaneous readers.
func (rw *CountingRWMutex) RUnlock() {
atomic.AddInt64(&rw.waiting, -1)
rw.mu.RUnlock()
}
// Lock locks rw for writing.
func (rw *CountingRWMutex) Lock() {
atomic.AddInt64(&rw.waiting, 1)
rw.mu.Lock()
}
// Unlock undoes a single Lock call; it does not affect other simultaneous readers.
func (rw *CountingRWMutex) Unlock() {
atomic.AddInt64(&rw.waiting, -1)
rw.mu.Unlock()
}
// TryLock tries to lock rw for writing if the pending waitinger is less than the limit.
func (rw *CountingRWMutex) TryLock() bool {
if atomic.LoadInt64(&rw.waiting) > rw.limit {
return false
}
return rw.mu.TryLock()
}
// Waiters returns the number of goroutines waiting for the lock.
func (rw *CountingRWMutex) Waiters() int64 {
return atomic.LoadInt64(&rw.waiting)
}