podman
1//go:build linux
2
3package lock4
5import (6"fmt"7"syscall"8
9"github.com/containers/podman/v5/libpod/lock/shm"10)
11
12// SHMLockManager manages shared memory locks.
13type SHMLockManager struct {14locks *shm.SHMLocks15}
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.
20func NewSHMLockManager(path string, numLocks uint32) (Manager, error) {21locks, err := shm.CreateSHMLock(path, numLocks)22if err != nil {23return nil, err24}25
26manager := new(SHMLockManager)27manager.locks = locks28
29return manager, nil30}
31
32// OpenSHMLockManager opens an existing SHMLockManager with the given number of
33// locks.
34func OpenSHMLockManager(path string, numLocks uint32) (Manager, error) {35locks, err := shm.OpenSHMLock(path, numLocks)36if err != nil {37return nil, err38}39
40manager := new(SHMLockManager)41manager.locks = locks42
43return manager, nil44}
45
46// AllocateLock allocates a new lock from the manager.
47func (m *SHMLockManager) AllocateLock() (Locker, error) {48semIndex, err := m.locks.AllocateSemaphore()49if err != nil {50return nil, err51}52
53lock := new(SHMLock)54lock.lockID = semIndex55lock.manager = m56
57return lock, nil58}
59
60// AllocateAndRetrieveLock allocates the lock with the given ID and returns it.
61// If the lock is already allocated, error.
62func (m *SHMLockManager) AllocateAndRetrieveLock(id uint32) (Locker, error) {63lock := new(SHMLock)64lock.lockID = id65lock.manager = m66
67if id >= m.locks.GetMaxLocks() {68return nil, fmt.Errorf("lock ID %d is too large - max lock size is %d: %w",69id, m.locks.GetMaxLocks()-1, syscall.EINVAL)70}71
72if err := m.locks.AllocateGivenSemaphore(id); err != nil {73return nil, err74}75
76return lock, nil77}
78
79// RetrieveLock retrieves a lock from the manager given its ID.
80func (m *SHMLockManager) RetrieveLock(id uint32) (Locker, error) {81lock := new(SHMLock)82lock.lockID = id83lock.manager = m84
85if id >= m.locks.GetMaxLocks() {86return nil, fmt.Errorf("lock ID %d is too large - max lock size is %d: %w",87id, m.locks.GetMaxLocks()-1, syscall.EINVAL)88}89
90return lock, nil91}
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.
96func (m *SHMLockManager) FreeAllLocks() error {97return m.locks.DeallocateAllSemaphores()98}
99
100// AvailableLocks returns the number of free locks in the manager.
101func (m *SHMLockManager) AvailableLocks() (*uint32, error) {102avail, err := m.locks.GetFreeLocks()103if err != nil {104return nil, err105}106
107return &avail, nil108}
109
110func (m *SHMLockManager) LocksHeld() ([]uint32, error) {111return m.locks.GetTakenLocks()112}
113
114// SHMLock is an individual shared memory lock.
115type SHMLock struct {116lockID uint32117manager *SHMLockManager118}
119
120// ID returns the ID of the lock.
121func (l *SHMLock) ID() uint32 {122return l.lockID123}
124
125// Lock acquires the lock.
126func (l *SHMLock) Lock() {127if err := l.manager.locks.LockSemaphore(l.lockID); err != nil {128panic(err.Error())129}130}
131
132// Unlock releases the lock.
133func (l *SHMLock) Unlock() {134if err := l.manager.locks.UnlockSemaphore(l.lockID); err != nil {135panic(err.Error())136}137}
138
139// Free releases the lock, allowing it to be reused.
140func (l *SHMLock) Free() error {141return l.manager.locks.DeallocateSemaphore(l.lockID)142}
143