Replace RWMutex use with custom UpgradeableMutex type, catch failed RW upgrades
Signed-off-by: kim (grufwub) <grufwub@gmail.com>master
parent
3f0ecefef3
commit
c6042419fa
@ -0,0 +1,59 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UpgradeableMutex struct {
|
||||
wLast int64
|
||||
internal sync.RWMutex
|
||||
}
|
||||
|
||||
func (mu *UpgradeableMutex) RLock() {
|
||||
mu.internal.RLock()
|
||||
}
|
||||
|
||||
func (mu *UpgradeableMutex) RUnlock() {
|
||||
mu.internal.RUnlock()
|
||||
}
|
||||
|
||||
func (mu *UpgradeableMutex) Lock() {
|
||||
// Get lock, set last write-lock time
|
||||
mu.internal.Lock()
|
||||
atomic.StoreInt64(&mu.wLast, time.Now().UnixNano())
|
||||
}
|
||||
|
||||
func (mu *UpgradeableMutex) Unlock() {
|
||||
mu.internal.Unlock()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
func (mu *UpgradeableMutex) UpgradeLock() bool {
|
||||
return mu.safeSwap(func() {
|
||||
mu.internal.RUnlock()
|
||||
mu.internal.Lock()
|
||||
})
|
||||
}
|
||||
|
||||
func (mu *UpgradeableMutex) DowngradeLock() bool {
|
||||
return mu.safeSwap(func() {
|
||||
mu.internal.Unlock()
|
||||
mu.internal.RLock()
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue