mutex.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. package backable_ringbuffer
  2. // Copied from github.com/smallnest/ringbuffer
  3. import (
  4. "sync"
  5. "sync/atomic"
  6. "unsafe"
  7. )
  8. const (
  9. mutexLocked = 1 << iota // mutex is locked
  10. mutexWoken
  11. mutexStarving
  12. mutexWaiterShift = iota
  13. )
  14. // Mutex is a locker which supports TryLock.
  15. type Mutex struct {
  16. sync.Mutex
  17. }
  18. func (m *Mutex) TryLock() bool {
  19. if atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), 0, mutexLocked) {
  20. return true
  21. }
  22. old := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex)))
  23. if old&(mutexLocked|mutexStarving|mutexWoken) != 0 {
  24. return false
  25. }
  26. new := old | mutexLocked
  27. return atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), old, new)
  28. }
  29. func (m *Mutex) Count() int {
  30. v := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex)))
  31. v = v >> mutexWaiterShift
  32. v = v + (v & mutexLocked)
  33. return int(v)
  34. }
  35. func (m *Mutex) IsLocked() bool {
  36. state := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex)))
  37. return state&mutexLocked == mutexLocked
  38. }
  39. func (m *Mutex) IsWoken() bool {
  40. state := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex)))
  41. return state&mutexWoken == mutexWoken
  42. }
  43. func (m *Mutex) IsStarving() bool {
  44. state := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex)))
  45. return state&mutexStarving == mutexStarving
  46. }