github.com/AbhinandanKurakure/podman/v3@v3.4.10/libpod/lock/in_memory_locks.go (about)

     1  package lock
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/pkg/errors"
     7  )
     8  
     9  // Mutex holds a single mutex and whether it has been allocated.
    10  type Mutex struct {
    11  	id        uint32
    12  	lock      sync.Mutex
    13  	allocated bool
    14  }
    15  
    16  // ID retrieves the ID of the mutex
    17  func (m *Mutex) ID() uint32 {
    18  	return m.id
    19  }
    20  
    21  // Lock locks the mutex
    22  func (m *Mutex) Lock() {
    23  	m.lock.Lock()
    24  }
    25  
    26  // Unlock unlocks the mutex
    27  func (m *Mutex) Unlock() {
    28  	m.lock.Unlock()
    29  }
    30  
    31  // Free deallocates the mutex to allow its reuse
    32  func (m *Mutex) Free() error {
    33  	m.allocated = false
    34  
    35  	return nil
    36  }
    37  
    38  // InMemoryManager is a lock manager that allocates and retrieves local-only
    39  // locks - that is, they are not multiprocess. This lock manager is intended
    40  // purely for unit and integration testing and should not be used in production
    41  // deployments.
    42  type InMemoryManager struct {
    43  	locks     []*Mutex
    44  	numLocks  uint32
    45  	localLock sync.Mutex
    46  }
    47  
    48  // NewInMemoryManager creates a new in-memory lock manager with the given number
    49  // of locks.
    50  func NewInMemoryManager(numLocks uint32) (Manager, error) {
    51  	if numLocks == 0 {
    52  		return nil, errors.Errorf("must provide a non-zero number of locks!")
    53  	}
    54  
    55  	manager := new(InMemoryManager)
    56  	manager.numLocks = numLocks
    57  	manager.locks = make([]*Mutex, numLocks)
    58  
    59  	var i uint32
    60  	for i = 0; i < numLocks; i++ {
    61  		lock := new(Mutex)
    62  		lock.id = i
    63  		manager.locks[i] = lock
    64  	}
    65  
    66  	return manager, nil
    67  }
    68  
    69  // AllocateLock allocates a lock from the manager.
    70  func (m *InMemoryManager) AllocateLock() (Locker, error) {
    71  	m.localLock.Lock()
    72  	defer m.localLock.Unlock()
    73  
    74  	for _, lock := range m.locks {
    75  		if !lock.allocated {
    76  			lock.allocated = true
    77  			return lock, nil
    78  		}
    79  	}
    80  
    81  	return nil, errors.Errorf("all locks have been allocated")
    82  }
    83  
    84  // RetrieveLock retrieves a lock from the manager.
    85  func (m *InMemoryManager) RetrieveLock(id uint32) (Locker, error) {
    86  	if id >= m.numLocks {
    87  		return nil, errors.Errorf("given lock ID %d is too large - this manager only supports lock indexes up to %d", id, m.numLocks-1)
    88  	}
    89  
    90  	return m.locks[id], nil
    91  }
    92  
    93  // AllocateAndRetrieveLock allocates a lock with the given ID (if not already in
    94  // use) and returns it.
    95  func (m *InMemoryManager) AllocateAndRetrieveLock(id uint32) (Locker, error) {
    96  	if id >= m.numLocks {
    97  		return nil, errors.Errorf("given lock ID %d is too large - this manager only supports lock indexes up to %d", id, m.numLocks)
    98  	}
    99  
   100  	if m.locks[id].allocated {
   101  		return nil, errors.Errorf("given lock ID %d is already in use, cannot reallocate", id)
   102  	}
   103  
   104  	m.locks[id].allocated = true
   105  
   106  	return m.locks[id], nil
   107  }
   108  
   109  // FreeAllLocks frees all locks.
   110  // This function is DANGEROUS. Please read the full comment in locks.go before
   111  // trying to use it.
   112  func (m *InMemoryManager) FreeAllLocks() error {
   113  	for _, lock := range m.locks {
   114  		lock.allocated = false
   115  	}
   116  
   117  	return nil
   118  }