File: shm_lock_manager_linux.go

package info (click to toggle)
podman 5.4.2%2Bds1-2
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 23,124 kB
  • sloc: sh: 6,119; perl: 2,710; python: 2,258; ansic: 1,556; makefile: 1,022; xml: 121; ruby: 42; awk: 12; csh: 8
file content (142 lines) | stat: -rw-r--r-- 3,372 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
//go:build linux

package lock

import (
	"fmt"
	"syscall"

	"github.com/containers/podman/v5/libpod/lock/shm"
)

// 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
}

// AllocateAndRetrieveLock allocates the lock with the given ID and returns it.
// If the lock is already allocated, error.
func (m *SHMLockManager) AllocateAndRetrieveLock(id uint32) (Locker, error) {
	lock := new(SHMLock)
	lock.lockID = id
	lock.manager = m

	if id >= m.locks.GetMaxLocks() {
		return nil, fmt.Errorf("lock ID %d is too large - max lock size is %d: %w",
			id, m.locks.GetMaxLocks()-1, syscall.EINVAL)
	}

	if err := m.locks.AllocateGivenSemaphore(id); err != nil {
		return nil, err
	}

	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, fmt.Errorf("lock ID %d is too large - max lock size is %d: %w",
			id, m.locks.GetMaxLocks()-1, syscall.EINVAL)
	}

	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()
}

// AvailableLocks returns the number of free locks in the manager.
func (m *SHMLockManager) AvailableLocks() (*uint32, error) {
	avail, err := m.locks.GetFreeLocks()
	if err != nil {
		return nil, err
	}

	return &avail, nil
}

func (m *SHMLockManager) LocksHeld() ([]uint32, error) {
	return m.locks.GetTakenLocks()
}

// 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)
}