github.com/AbhinandanKurakure/podman/v3@v3.4.10/libpod/lock/in_memory_locks.go (about) 1 package lock 2 3 import ( 4 "sync" 5 6 "github.com/pkg/errors" 7 ) 8 9 // Mutex holds a single mutex and whether it has been allocated. 10 type Mutex struct { 11 id uint32 12 lock sync.Mutex 13 allocated bool 14 } 15 16 // ID retrieves the ID of the mutex 17 func (m *Mutex) ID() uint32 { 18 return m.id 19 } 20 21 // Lock locks the mutex 22 func (m *Mutex) Lock() { 23 m.lock.Lock() 24 } 25 26 // Unlock unlocks the mutex 27 func (m *Mutex) Unlock() { 28 m.lock.Unlock() 29 } 30 31 // Free deallocates the mutex to allow its reuse 32 func (m *Mutex) Free() error { 33 m.allocated = false 34 35 return nil 36 } 37 38 // InMemoryManager is a lock manager that allocates and retrieves local-only 39 // locks - that is, they are not multiprocess. This lock manager is intended 40 // purely for unit and integration testing and should not be used in production 41 // deployments. 42 type InMemoryManager struct { 43 locks []*Mutex 44 numLocks uint32 45 localLock sync.Mutex 46 } 47 48 // NewInMemoryManager creates a new in-memory lock manager with the given number 49 // of locks. 50 func NewInMemoryManager(numLocks uint32) (Manager, error) { 51 if numLocks == 0 { 52 return nil, errors.Errorf("must provide a non-zero number of locks!") 53 } 54 55 manager := new(InMemoryManager) 56 manager.numLocks = numLocks 57 manager.locks = make([]*Mutex, numLocks) 58 59 var i uint32 60 for i = 0; i < numLocks; i++ { 61 lock := new(Mutex) 62 lock.id = i 63 manager.locks[i] = lock 64 } 65 66 return manager, nil 67 } 68 69 // AllocateLock allocates a lock from the manager. 70 func (m *InMemoryManager) AllocateLock() (Locker, error) { 71 m.localLock.Lock() 72 defer m.localLock.Unlock() 73 74 for _, lock := range m.locks { 75 if !lock.allocated { 76 lock.allocated = true 77 return lock, nil 78 } 79 } 80 81 return nil, errors.Errorf("all locks have been allocated") 82 } 83 84 // RetrieveLock retrieves a lock from the manager. 85 func (m *InMemoryManager) RetrieveLock(id uint32) (Locker, error) { 86 if id >= m.numLocks { 87 return nil, errors.Errorf("given lock ID %d is too large - this manager only supports lock indexes up to %d", id, m.numLocks-1) 88 } 89 90 return m.locks[id], nil 91 } 92 93 // AllocateAndRetrieveLock allocates a lock with the given ID (if not already in 94 // use) and returns it. 95 func (m *InMemoryManager) AllocateAndRetrieveLock(id uint32) (Locker, error) { 96 if id >= m.numLocks { 97 return nil, errors.Errorf("given lock ID %d is too large - this manager only supports lock indexes up to %d", id, m.numLocks) 98 } 99 100 if m.locks[id].allocated { 101 return nil, errors.Errorf("given lock ID %d is already in use, cannot reallocate", id) 102 } 103 104 m.locks[id].allocated = true 105 106 return m.locks[id], nil 107 } 108 109 // FreeAllLocks frees all locks. 110 // This function is DANGEROUS. Please read the full comment in locks.go before 111 // trying to use it. 112 func (m *InMemoryManager) FreeAllLocks() error { 113 for _, lock := range m.locks { 114 lock.allocated = false 115 } 116 117 return nil 118 }