github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/libpod/lock/shm_lock_manager_linux.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package lock
     5  
     6  import (
     7  	"syscall"
     8  
     9  	"github.com/hanks177/podman/v4/libpod/lock/shm"
    10  	"github.com/pkg/errors"
    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, errors.Wrapf(syscall.EINVAL, "lock ID %d is too large - max lock size is %d",
    70  			id, m.locks.GetMaxLocks()-1)
    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, errors.Wrapf(syscall.EINVAL, "lock ID %d is too large - max lock size is %d",
    88  			id, m.locks.GetMaxLocks()-1)
    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  // SHMLock is an individual shared memory lock.
   102  type SHMLock struct {
   103  	lockID  uint32
   104  	manager *SHMLockManager
   105  }
   106  
   107  // ID returns the ID of the lock.
   108  func (l *SHMLock) ID() uint32 {
   109  	return l.lockID
   110  }
   111  
   112  // Lock acquires the lock.
   113  func (l *SHMLock) Lock() {
   114  	if err := l.manager.locks.LockSemaphore(l.lockID); err != nil {
   115  		panic(err.Error())
   116  	}
   117  }
   118  
   119  // Unlock releases the lock.
   120  func (l *SHMLock) Unlock() {
   121  	if err := l.manager.locks.UnlockSemaphore(l.lockID); err != nil {
   122  		panic(err.Error())
   123  	}
   124  }
   125  
   126  // Free releases the lock, allowing it to be reused.
   127  func (l *SHMLock) Free() error {
   128  	return l.manager.locks.DeallocateSemaphore(l.lockID)
   129  }