github.com/containers/libpod@v1.9.4-0.20220419124438-4284fd425507/libpod/lock/shm_lock_manager_linux.go (about) 1 // +build linux 2 3 package lock 4 5 import ( 6 "syscall" 7 8 "github.com/containers/libpod/libpod/lock/shm" 9 "github.com/pkg/errors" 10 ) 11 12 // SHMLockManager manages shared memory locks. 13 type SHMLockManager struct { 14 locks *shm.SHMLocks 15 } 16 17 // NewSHMLockManager makes a new SHMLockManager with the given number of locks. 18 // Due to the underlying implementation, the exact number of locks created may 19 // be greater than the number given here. 20 func NewSHMLockManager(path string, numLocks uint32) (Manager, error) { 21 locks, err := shm.CreateSHMLock(path, numLocks) 22 if err != nil { 23 return nil, err 24 } 25 26 manager := new(SHMLockManager) 27 manager.locks = locks 28 29 return manager, nil 30 } 31 32 // OpenSHMLockManager opens an existing SHMLockManager with the given number of 33 // locks. 34 func OpenSHMLockManager(path string, numLocks uint32) (Manager, error) { 35 locks, err := shm.OpenSHMLock(path, numLocks) 36 if err != nil { 37 return nil, err 38 } 39 40 manager := new(SHMLockManager) 41 manager.locks = locks 42 43 return manager, nil 44 } 45 46 // AllocateLock allocates a new lock from the manager. 47 func (m *SHMLockManager) AllocateLock() (Locker, error) { 48 semIndex, err := m.locks.AllocateSemaphore() 49 if err != nil { 50 return nil, err 51 } 52 53 lock := new(SHMLock) 54 lock.lockID = semIndex 55 lock.manager = m 56 57 return lock, nil 58 } 59 60 // AllocateAndRetrieveLock allocates the lock with the given ID and returns it. 61 // If the lock is already allocated, error. 62 func (m *SHMLockManager) AllocateAndRetrieveLock(id uint32) (Locker, error) { 63 lock := new(SHMLock) 64 lock.lockID = id 65 lock.manager = m 66 67 if id >= m.locks.GetMaxLocks() { 68 return nil, errors.Wrapf(syscall.EINVAL, "lock ID %d is too large - max lock size is %d", 69 id, m.locks.GetMaxLocks()-1) 70 } 71 72 if err := m.locks.AllocateGivenSemaphore(id); err != nil { 73 return nil, err 74 } 75 76 return lock, nil 77 } 78 79 // RetrieveLock retrieves a lock from the manager given its ID. 80 func (m *SHMLockManager) RetrieveLock(id uint32) (Locker, error) { 81 lock := new(SHMLock) 82 lock.lockID = id 83 lock.manager = m 84 85 if id >= m.locks.GetMaxLocks() { 86 return nil, errors.Wrapf(syscall.EINVAL, "lock ID %d is too large - max lock size is %d", 87 id, m.locks.GetMaxLocks()-1) 88 } 89 90 return lock, nil 91 } 92 93 // FreeAllLocks frees all locks in the manager. 94 // This function is DANGEROUS. Please read the full comment in locks.go before 95 // trying to use it. 96 func (m *SHMLockManager) FreeAllLocks() error { 97 return m.locks.DeallocateAllSemaphores() 98 } 99 100 // SHMLock is an individual shared memory lock. 101 type SHMLock struct { 102 lockID uint32 103 manager *SHMLockManager 104 } 105 106 // ID returns the ID of the lock. 107 func (l *SHMLock) ID() uint32 { 108 return l.lockID 109 } 110 111 // Lock acquires the lock. 112 func (l *SHMLock) Lock() { 113 if err := l.manager.locks.LockSemaphore(l.lockID); err != nil { 114 panic(err.Error()) 115 } 116 } 117 118 // Unlock releases the lock. 119 func (l *SHMLock) Unlock() { 120 if err := l.manager.locks.UnlockSemaphore(l.lockID); err != nil { 121 panic(err.Error()) 122 } 123 } 124 125 // Free releases the lock, allowing it to be reused. 126 func (l *SHMLock) Free() error { 127 return l.manager.locks.DeallocateSemaphore(l.lockID) 128 }