mirror of
https://github.com/containers/podman.git
synced 2025-05-28 21:46:51 +08:00

the results of a code cleanup performed by the goland IDE. Signed-off-by: baude <bbaude@redhat.com>
253 lines
7.5 KiB
Go
253 lines
7.5 KiB
Go
// +build linux,cgo
|
|
|
|
package shm
|
|
|
|
// #cgo LDFLAGS: -lrt -lpthread
|
|
// #cgo CFLAGS: -Wall -Werror
|
|
// #include <stdlib.h>
|
|
// #include "shm_lock.h"
|
|
// const uint32_t bitmap_size_c = BITMAP_SIZE;
|
|
import "C"
|
|
|
|
import (
|
|
"runtime"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"github.com/pkg/errors"
|
|
"github.com/sirupsen/logrus"
|
|
)
|
|
|
|
var (
|
|
// BitmapSize is the size of the bitmap used when managing SHM locks.
|
|
// an SHM lock manager's max locks will be rounded up to a multiple of
|
|
// this number.
|
|
BitmapSize = uint32(C.bitmap_size_c)
|
|
)
|
|
|
|
// SHMLocks is a struct enabling POSIX semaphore locking in a shared memory
|
|
// segment.
|
|
type SHMLocks struct { // nolint
|
|
lockStruct *C.shm_struct_t
|
|
maxLocks uint32
|
|
valid bool
|
|
}
|
|
|
|
// CreateSHMLock sets up a shared-memory segment holding a given number of POSIX
|
|
// semaphores, and returns a struct that can be used to operate on those locks.
|
|
// numLocks must not be 0, and may be rounded up to a multiple of the bitmap
|
|
// size used by the underlying implementation.
|
|
func CreateSHMLock(path string, numLocks uint32) (*SHMLocks, error) {
|
|
if numLocks == 0 {
|
|
return nil, errors.Wrapf(syscall.EINVAL, "number of locks must be greater than 0")
|
|
}
|
|
|
|
locks := new(SHMLocks)
|
|
|
|
cPath := C.CString(path)
|
|
defer C.free(unsafe.Pointer(cPath))
|
|
|
|
var errCode C.int
|
|
lockStruct := C.setup_lock_shm(cPath, C.uint32_t(numLocks), &errCode)
|
|
if lockStruct == nil {
|
|
// We got a null pointer, so something errored
|
|
return nil, errors.Wrapf(syscall.Errno(-1*errCode), "failed to create %d locks in %s", numLocks, path)
|
|
}
|
|
|
|
locks.lockStruct = lockStruct
|
|
locks.maxLocks = uint32(lockStruct.num_locks)
|
|
locks.valid = true
|
|
|
|
logrus.Debugf("Initialized SHM lock manager at path %s", path)
|
|
|
|
return locks, nil
|
|
}
|
|
|
|
// OpenSHMLock opens an existing shared-memory segment holding a given number of
|
|
// POSIX semaphores. numLocks must match the number of locks the shared memory
|
|
// segment was created with.
|
|
func OpenSHMLock(path string, numLocks uint32) (*SHMLocks, error) {
|
|
if numLocks == 0 {
|
|
return nil, errors.Wrapf(syscall.EINVAL, "number of locks must be greater than 0")
|
|
}
|
|
|
|
locks := new(SHMLocks)
|
|
|
|
cPath := C.CString(path)
|
|
defer C.free(unsafe.Pointer(cPath))
|
|
|
|
var errCode C.int
|
|
lockStruct := C.open_lock_shm(cPath, C.uint32_t(numLocks), &errCode)
|
|
if lockStruct == nil {
|
|
// We got a null pointer, so something errored
|
|
return nil, errors.Wrapf(syscall.Errno(-1*errCode), "failed to open %d locks in %s", numLocks, path)
|
|
}
|
|
|
|
locks.lockStruct = lockStruct
|
|
locks.maxLocks = numLocks
|
|
locks.valid = true
|
|
|
|
return locks, nil
|
|
}
|
|
|
|
// GetMaxLocks returns the maximum number of locks in the SHM
|
|
func (locks *SHMLocks) GetMaxLocks() uint32 {
|
|
return locks.maxLocks
|
|
}
|
|
|
|
// Close closes an existing shared-memory segment.
|
|
// The segment will be rendered unusable after closing.
|
|
// WARNING: If you Close() while there are still locks locked, these locks may
|
|
// fail to release, causing a program freeze.
|
|
// Close() is only intended to be used while testing the locks.
|
|
func (locks *SHMLocks) Close() error {
|
|
if !locks.valid {
|
|
return errors.Wrapf(syscall.EINVAL, "locks have already been closed")
|
|
}
|
|
|
|
locks.valid = false
|
|
|
|
retCode := C.close_lock_shm(locks.lockStruct)
|
|
if retCode < 0 {
|
|
// Negative errno returned
|
|
return syscall.Errno(-1 * retCode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// AllocateSemaphore allocates a semaphore from a shared-memory segment for use
|
|
// by a container or pod.
|
|
// Returns the index of the semaphore that was allocated.
|
|
// Allocations past the maximum number of locks given when the SHM segment was
|
|
// created will result in an error, and no semaphore will be allocated.
|
|
func (locks *SHMLocks) AllocateSemaphore() (uint32, error) {
|
|
if !locks.valid {
|
|
return 0, errors.Wrapf(syscall.EINVAL, "locks have already been closed")
|
|
}
|
|
|
|
// This returns a U64, so we have the full u32 range available for
|
|
// semaphore indexes, and can still return error codes.
|
|
retCode := C.allocate_semaphore(locks.lockStruct)
|
|
if retCode < 0 {
|
|
// Negative errno returned
|
|
return 0, syscall.Errno(-1 * retCode)
|
|
}
|
|
|
|
return uint32(retCode), nil
|
|
}
|
|
|
|
// AllocateGivenSemaphore allocates the given semaphore from the shared-memory
|
|
// segment for use by a container or pod.
|
|
// If the semaphore is already in use or the index is invalid an error will be
|
|
// returned.
|
|
func (locks *SHMLocks) AllocateGivenSemaphore(sem uint32) error {
|
|
if !locks.valid {
|
|
return errors.Wrapf(syscall.EINVAL, "locks have already been closed")
|
|
}
|
|
|
|
retCode := C.allocate_given_semaphore(locks.lockStruct, C.uint32_t(sem))
|
|
if retCode < 0 {
|
|
return syscall.Errno(-1 * retCode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeallocateSemaphore frees a semaphore in a shared-memory segment so it can be
|
|
// reallocated to another container or pod.
|
|
// The given semaphore must be already allocated, or an error will be returned.
|
|
func (locks *SHMLocks) DeallocateSemaphore(sem uint32) error {
|
|
if !locks.valid {
|
|
return errors.Wrapf(syscall.EINVAL, "locks have already been closed")
|
|
}
|
|
|
|
if sem > locks.maxLocks {
|
|
return errors.Wrapf(syscall.EINVAL, "given semaphore %d is higher than maximum locks count %d", sem, locks.maxLocks)
|
|
}
|
|
|
|
retCode := C.deallocate_semaphore(locks.lockStruct, C.uint32_t(sem))
|
|
if retCode < 0 {
|
|
// Negative errno returned
|
|
return syscall.Errno(-1 * retCode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// DeallocateAllSemaphores frees all semaphores so they can be reallocated to
|
|
// other containers and pods.
|
|
func (locks *SHMLocks) DeallocateAllSemaphores() error {
|
|
if !locks.valid {
|
|
return errors.Wrapf(syscall.EINVAL, "locks have already been closed")
|
|
}
|
|
|
|
retCode := C.deallocate_all_semaphores(locks.lockStruct)
|
|
if retCode < 0 {
|
|
// Negative errno return from C
|
|
return syscall.Errno(-1 * retCode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// LockSemaphore locks the given semaphore.
|
|
// If the semaphore is already locked, LockSemaphore will block until the lock
|
|
// can be acquired.
|
|
// There is no requirement that the given semaphore be allocated.
|
|
// This ensures that attempts to lock a container after it has been deleted,
|
|
// but before the caller has queried the database to determine this, will
|
|
// succeed.
|
|
func (locks *SHMLocks) LockSemaphore(sem uint32) error {
|
|
if !locks.valid {
|
|
return errors.Wrapf(syscall.EINVAL, "locks have already been closed")
|
|
}
|
|
|
|
if sem > locks.maxLocks {
|
|
return errors.Wrapf(syscall.EINVAL, "given semaphore %d is higher than maximum locks count %d", sem, locks.maxLocks)
|
|
}
|
|
|
|
// For pthread mutexes, we have to guarantee lock and unlock happen in
|
|
// the same thread.
|
|
runtime.LockOSThread()
|
|
|
|
retCode := C.lock_semaphore(locks.lockStruct, C.uint32_t(sem))
|
|
if retCode < 0 {
|
|
// Negative errno returned
|
|
return syscall.Errno(-1 * retCode)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// UnlockSemaphore unlocks the given semaphore.
|
|
// Unlocking a semaphore that is already unlocked with return EBUSY.
|
|
// There is no requirement that the given semaphore be allocated.
|
|
// This ensures that attempts to lock a container after it has been deleted,
|
|
// but before the caller has queried the database to determine this, will
|
|
// succeed.
|
|
func (locks *SHMLocks) UnlockSemaphore(sem uint32) error {
|
|
if !locks.valid {
|
|
return errors.Wrapf(syscall.EINVAL, "locks have already been closed")
|
|
}
|
|
|
|
if sem > locks.maxLocks {
|
|
return errors.Wrapf(syscall.EINVAL, "given semaphore %d is higher than maximum locks count %d", sem, locks.maxLocks)
|
|
}
|
|
|
|
retCode := C.unlock_semaphore(locks.lockStruct, C.uint32_t(sem))
|
|
if retCode < 0 {
|
|
// Negative errno returned
|
|
return syscall.Errno(-1 * retCode)
|
|
}
|
|
|
|
// For pthread mutexes, we have to guarantee lock and unlock happen in
|
|
// the same thread.
|
|
// OK if we take multiple locks - UnlockOSThread() won't actually unlock
|
|
// until the number of calls equals the number of calls to
|
|
// LockOSThread()
|
|
runtime.UnlockOSThread()
|
|
|
|
return nil
|
|
}
|