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
|
package lock
// Manager provides an interface for allocating multiprocess locks.
// Locks returned by Manager MUST be multiprocess - allocating a lock in
// process A and retrieving that lock's ID in process B must return handles for
// the same lock, and locking the lock in A should exclude B from the lock until
// it is unlocked in A.
// All locks must be identified by a UUID (retrieved with Locker's ID() method).
// All locks with a given UUID must refer to the same underlying lock, and it
// must be possible to retrieve the lock given its UUID.
// Each UUID should refer to a unique underlying lock.
// Calls to AllocateLock() must return a unique, unallocated UUID.
// AllocateLock() must fail once all available locks have been allocated.
// Locks are returned to use by calls to Free(), and can subsequently be
// reallocated.
type Manager interface {
// AllocateLock returns an unallocated lock.
// It is guaranteed that the same lock will not be returned again by
// AllocateLock until the returned lock has Free() called on it.
// If all available locks are allocated, AllocateLock will return an
// error.
AllocateLock() (Locker, error)
// RetrieveLock retrieves a lock given its UUID.
// The underlying lock MUST be the same as another other lock with the
// same UUID.
RetrieveLock(id uint32) (Locker, error)
// PLEASE READ FULL DESCRIPTION BEFORE USING.
// FreeAllLocks frees all allocated locks, in preparation for lock
// reallocation.
// As this deallocates all presently-held locks, this can be very
// dangerous - if there are other processes running that might be
// attempting to allocate new locks and free existing locks, we may
// encounter races leading to an inconsistent state.
// (This is in addition to the fact that FreeAllLocks instantly makes
// the state inconsistent simply by using it, and requires a full
// lock renumbering to restore consistency!).
// In short, this should only be used as part of unit tests, or lock
// renumbering, where reasonable guarantees about other processes can be
// made.
FreeAllLocks() error
}
// Locker is similar to sync.Locker, but provides a method for freeing the lock
// to allow its reuse.
// All Locker implementations must maintain mutex semantics - the lock only
// allows one caller in the critical section at a time.
// All locks with the same ID must refer to the same underlying lock, even
// if they are within multiple processes.
type Locker interface {
// ID retrieves the lock's ID.
// ID is guaranteed to uniquely identify the lock within the
// Manager - that is, calling RetrieveLock with this ID will return
// another instance of the same lock.
ID() uint32
// Lock locks the lock.
// This call MUST block until it successfully acquires the lock or
// encounters a fatal error.
// All errors must be handled internally, as they are not returned. For
// the most part, panicking should be appropriate.
// Some lock implementations may require that Lock() and Unlock() occur
// within the same goroutine (SHM locking, for example). The usual Go
// Lock()/defer Unlock() pattern will still work fine in these cases.
Lock()
// Unlock unlocks the lock.
// All errors must be handled internally, as they are not returned. For
// the most part, panicking should be appropriate.
// This includes unlocking locks which are already unlocked.
Unlock()
// Free deallocates the underlying lock, allowing its reuse by other
// pods and containers.
// The lock MUST still be usable after a Free() - some libpod instances
// may still retain Container structs with the old lock. This simply
// advises the manager that the lock may be reallocated.
Free() error
}
|