codeberg.org/gruf/go-mutexes@v1.5.0/mutex_timeout.go (about) 1 package mutexes 2 3 import ( 4 "time" 5 ) 6 7 // TimeoutMutex defines a Mutex with timeouts on locks 8 type TimeoutMutex interface { 9 Mutex 10 11 // LockFunc is functionally the same as Lock(), but allows setting a custom hook called on timeout 12 LockFunc(func()) func() 13 } 14 15 // TimeoutRWMutex defines a RWMutex with timeouts on locks 16 type TimeoutRWMutex interface { 17 RWMutex 18 19 // LockFunc is functionally the same as Lock(), but allows setting a custom hook called on timeout 20 LockFunc(func()) func() 21 22 // RLockFunc is functionally the same as RLock(), but allows setting a custom hook called on timeout 23 RLockFunc(func()) func() 24 } 25 26 // WithTimeout wraps the supplied Mutex to add a timeout 27 func WithTimeout(mu Mutex, d time.Duration) TimeoutMutex { 28 return &timeoutMutex{mu: mu, d: d} 29 } 30 31 // WithTimeoutRW wraps the supplied RWMutex to add read/write timeouts 32 func WithTimeoutRW(mu RWMutex, rd, wd time.Duration) TimeoutRWMutex { 33 return &timeoutRWMutex{mu: mu, rd: rd, wd: wd} 34 } 35 36 // timeoutMutex wraps a Mutex with timeout 37 type timeoutMutex struct { 38 mu Mutex // mu is the wrapped mutex 39 d time.Duration // d is the timeout duration 40 } 41 42 func (mu *timeoutMutex) Lock() func() { 43 return mu.LockFunc(func() { panic("lock timed out") }) 44 } 45 46 func (mu *timeoutMutex) LockFunc(fn func()) func() { 47 return mutexTimeout(mu.d, mu.mu.Lock(), fn) 48 } 49 50 // TimeoutRWMutex wraps a RWMutex with timeouts 51 type timeoutRWMutex struct { 52 mu RWMutex // mu is the wrapped rwmutex 53 rd time.Duration // rd is the rlock timeout duration 54 wd time.Duration // wd is the lock timeout duration 55 } 56 57 func (mu *timeoutRWMutex) Lock() func() { 58 return mu.LockFunc(func() { panic("lock timed out") }) 59 } 60 61 func (mu *timeoutRWMutex) LockFunc(fn func()) func() { 62 return mutexTimeout(mu.wd, mu.mu.Lock(), fn) 63 } 64 65 func (mu *timeoutRWMutex) RLock() func() { 66 return mu.RLockFunc(func() { panic("rlock timed out") }) 67 } 68 69 func (mu *timeoutRWMutex) RLockFunc(fn func()) func() { 70 return mutexTimeout(mu.rd, mu.mu.RLock(), fn) 71 } 72 73 // mutexTimeout performs a timed unlock, calling supplied fn if timeout is reached 74 func mutexTimeout(d time.Duration, unlock func(), fn func()) func() { 75 if d < 1 { 76 // No timeout, just unlock 77 return unlock 78 } 79 80 // Start timer to call fn. 81 t := time.AfterFunc(d, fn) 82 83 // Wrap unlock to stop mutex timer. 84 return func() { t.Stop(); unlock() } 85 }