Files
podman/libpod/lock/shm_lock_manager_linux.go
Matthew Heon d2b77f8b33 Do not make renumber shut down the runtime
The original intent behind the requirement was to ensure that, if
two SHM lock structs were open at the same time, we should not
make such a runtime available to the user, and should clean it up
instead.

It turns out that we don't even need to open a second SHM lock
struct - if we get an error mapping the first one due to a lock
count mismatch, we can just delete it, and it cleans itself up
when it errors. So there's no reason not to return a valid
runtime.

Signed-off-by: Matthew Heon <matthew.heon@pm.me>
2019-02-21 10:51:42 -05:00

110 lines
2.5 KiB
Go

// +build linux
package lock
import (
"syscall"
"github.com/containers/libpod/libpod/lock/shm"
"github.com/pkg/errors"
)
// SHMLockManager manages shared memory locks.
type SHMLockManager struct {
locks *shm.SHMLocks
}
// NewSHMLockManager makes a new SHMLockManager with the given number of locks.
// Due to the underlying implementation, the exact number of locks created may
// be greater than the number given here.
func NewSHMLockManager(path string, numLocks uint32) (Manager, error) {
locks, err := shm.CreateSHMLock(path, numLocks)
if err != nil {
return nil, err
}
manager := new(SHMLockManager)
manager.locks = locks
return manager, nil
}
// OpenSHMLockManager opens an existing SHMLockManager with the given number of
// locks.
func OpenSHMLockManager(path string, numLocks uint32) (Manager, error) {
locks, err := shm.OpenSHMLock(path, numLocks)
if err != nil {
return nil, err
}
manager := new(SHMLockManager)
manager.locks = locks
return manager, nil
}
// AllocateLock allocates a new lock from the manager.
func (m *SHMLockManager) AllocateLock() (Locker, error) {
semIndex, err := m.locks.AllocateSemaphore()
if err != nil {
return nil, err
}
lock := new(SHMLock)
lock.lockID = semIndex
lock.manager = m
return lock, nil
}
// RetrieveLock retrieves a lock from the manager given its ID.
func (m *SHMLockManager) RetrieveLock(id uint32) (Locker, error) {
lock := new(SHMLock)
lock.lockID = id
lock.manager = m
if id >= m.locks.GetMaxLocks() {
return nil, errors.Wrapf(syscall.EINVAL, "lock ID %d is too large - max lock size is %d",
id, m.locks.GetMaxLocks()-1)
}
return lock, nil
}
// FreeAllLocks frees all locks in the manager.
// This function is DANGEROUS. Please read the full comment in locks.go before
// trying to use it.
func (m *SHMLockManager) FreeAllLocks() error {
return m.locks.DeallocateAllSemaphores()
}
// SHMLock is an individual shared memory lock.
type SHMLock struct {
lockID uint32
manager *SHMLockManager
}
// ID returns the ID of the lock.
func (l *SHMLock) ID() uint32 {
return l.lockID
}
// Lock acquires the lock.
func (l *SHMLock) Lock() {
if err := l.manager.locks.LockSemaphore(l.lockID); err != nil {
panic(err.Error())
}
}
// Unlock releases the lock.
func (l *SHMLock) Unlock() {
if err := l.manager.locks.UnlockSemaphore(l.lockID); err != nil {
panic(err.Error())
}
}
// Free releases the lock, allowing it to be reused.
func (l *SHMLock) Free() error {
return l.manager.locks.DeallocateSemaphore(l.lockID)
}