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  }