aa00189ee4
Signed-off-by: kim (grufwub) <grufwub@gmail.com>
69 lines
1.7 KiB
Go
69 lines
1.7 KiB
Go
package core
|
|
|
|
import (
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
// UpgradeableMutex wraps a RWMutex and provides safe upgrading / downgrading
|
|
// by informing you whether a write lock was achieved in the brief swap time
|
|
type UpgradeableMutex struct {
|
|
wLast int64
|
|
internal sync.RWMutex
|
|
}
|
|
|
|
// RLock exactly wraps the internal RWMutex
|
|
func (mu *UpgradeableMutex) RLock() {
|
|
mu.internal.RLock()
|
|
}
|
|
|
|
// RUnlock exactly wraps the internal RWMutex
|
|
func (mu *UpgradeableMutex) RUnlock() {
|
|
mu.internal.RUnlock()
|
|
}
|
|
|
|
// Lock wraps the internal RWMutex, atomically storing the last write-lock time
|
|
func (mu *UpgradeableMutex) Lock() {
|
|
mu.internal.Lock()
|
|
atomic.StoreInt64(&mu.wLast, time.Now().UnixNano())
|
|
}
|
|
|
|
// Unlock exactly wraps the internal RWMutex
|
|
func (mu *UpgradeableMutex) Unlock() {
|
|
mu.internal.Unlock()
|
|
}
|
|
|
|
// safeSwap stores the current time, performs the swap function and checks if
|
|
// any write locks were achieved during the swap function
|
|
func (mu *UpgradeableMutex) safeSwap(swapFn func()) bool {
|
|
// Get the 'now' time
|
|
now := time.Now().UnixNano()
|
|
|
|
// Store now time
|
|
atomic.StoreInt64(&mu.wLast, now)
|
|
|
|
// Perform the swap
|
|
swapFn()
|
|
|
|
// Successful swap determined by if last write-lock
|
|
// is still equal to 'now'
|
|
return atomic.LoadInt64(&mu.wLast) == now
|
|
}
|
|
|
|
// UpgradeLock upgrades a read to a write lock, returning success state as a bool
|
|
func (mu *UpgradeableMutex) UpgradeLock() bool {
|
|
return mu.safeSwap(func() {
|
|
mu.internal.RUnlock()
|
|
mu.internal.Lock()
|
|
})
|
|
}
|
|
|
|
// DowngradeLock downgrades a write to a read lock, returning success state as a bool
|
|
func (mu *UpgradeableMutex) DowngradeLock() bool {
|
|
return mu.safeSwap(func() {
|
|
mu.internal.Unlock()
|
|
mu.internal.RLock()
|
|
})
|
|
}
|