mutex.go (2309B)
1 package mutexes 2 3 import ( 4 "sync" 5 ) 6 7 // Mutex defines a wrappable mutex. By forcing unlocks 8 // via returned function it makes wrapping much easier 9 type Mutex interface { 10 // Lock performs a mutex lock, returning an unlock function 11 Lock() (unlock func()) 12 } 13 14 // RWMutex defines a wrappable read-write mutex. By forcing 15 // unlocks via returned functions it makes wrapping much easier 16 type RWMutex interface { 17 Mutex 18 19 // RLock performs a mutex read lock, returning an unlock function 20 RLock() (runlock func()) 21 } 22 23 // New returns a new base Mutex implementation 24 func New() Mutex { 25 return &baseMutex{} 26 } 27 28 // NewRW returns a new base RWMutex implementation 29 func NewRW() RWMutex { 30 return &baseRWMutex{} 31 } 32 33 // WithFunc wraps the supplied Mutex to call the provided hooks on lock / unlock 34 func WithFunc(mu Mutex, onLock, onUnlock func()) Mutex { 35 return &fnMutex{mu: mu, lo: onLock, un: onUnlock} 36 } 37 38 // WithFuncRW wrapps the supplied RWMutex to call the provided hooks on lock / rlock / unlock/ runlock 39 func WithFuncRW(mu RWMutex, onLock, onRLock, onUnlock, onRUnlock func()) RWMutex { 40 return &fnRWMutex{mu: mu, lo: onLock, rlo: onRLock, un: onUnlock, run: onRUnlock} 41 } 42 43 // baseMutex simply wraps a sync.Mutex to implement our Mutex interface 44 type baseMutex sync.Mutex 45 46 func (mu *baseMutex) Lock() func() { 47 (*sync.Mutex)(mu).Lock() 48 return (*sync.Mutex)(mu).Unlock 49 } 50 51 // baseRWMutex simply wraps a sync.RWMutex to implement our RWMutex interface 52 type baseRWMutex sync.RWMutex 53 54 func (mu *baseRWMutex) Lock() func() { 55 (*sync.RWMutex)(mu).Lock() 56 return (*sync.RWMutex)(mu).Unlock 57 } 58 59 func (mu *baseRWMutex) RLock() func() { 60 (*sync.RWMutex)(mu).RLock() 61 return (*sync.RWMutex)(mu).RUnlock 62 } 63 64 // fnMutex wraps a Mutex to add hooks for Lock and Unlock 65 type fnMutex struct { 66 mu Mutex 67 lo func() 68 un func() 69 } 70 71 func (mu *fnMutex) Lock() func() { 72 unlock := mu.mu.Lock() 73 mu.lo() 74 return func() { 75 mu.un() 76 unlock() 77 } 78 } 79 80 // fnRWMutex wraps a RWMutex to add hooks for Lock, RLock, Unlock and RUnlock 81 type fnRWMutex struct { 82 mu RWMutex 83 lo func() 84 rlo func() 85 un func() 86 run func() 87 } 88 89 func (mu *fnRWMutex) Lock() func() { 90 unlock := mu.mu.Lock() 91 mu.lo() 92 return func() { 93 mu.un() 94 unlock() 95 } 96 } 97 98 func (mu *fnRWMutex) RLock() func() { 99 unlock := mu.mu.RLock() 100 mu.rlo() 101 return func() { 102 mu.run() 103 unlock() 104 } 105 }