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