1
# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
2
# GNU Affero General Public License version 3 (see the file LICENSE).
23
def __init__(self, filename):
24
self._lock_filename = filename
26
self._lock_inode = None
27
self._lock_kind = LOCK_UN
32
os.close(self._lock_fd)
36
def acquired(self, write=False):
38
return self._lock_kind == LOCK_EX
40
return self._lock_kind != LOCK_UN
42
def acquire(self, write=False, block=True):
43
"""Acquire the lock for reading or writing.
45
:param write: If true, the path is acquired for writing.
46
:param block: If false, the call will return immediately on failure.
48
This method is reentrant, but not thread-safe. To use instances
49
of this class concurrently across threads, some instructions
50
will have to be protected to make it thread-safe.
52
if (self._lock_kind == LOCK_EX or
53
self._lock_kind == LOCK_SH and not write):
59
if self._lock_fd is None:
60
self._lock_fd = os.open(
61
self._lock_filename, os.O_RDWR | os.O_CREAT, 0644)
62
flags = fcntl.fcntl(self._lock_fd, fcntl.F_GETFD, 0)
63
flags |= fcntl.FD_CLOEXEC
64
fcntl.fcntl(self._lock_fd, fcntl.F_SETFD, flags)
65
self._lock_inode = os.fstat(self._lock_fd).st_ino
67
flags = kind = LOCK_EX
69
flags = kind = LOCK_SH
73
# Locks threads and local system, bad network behavior.
74
fcntl.flock(self._lock_fd, flags)
76
# Someone else has the lock and we're not blocking.
80
# Locks local system and network, bad thread behavior.
81
fcntl.lockf(self._lock_fd, flags)
83
# Someone else has the lock and we're not blocking.
84
fcntl.flock(self._lock_fd, LOCK_UN)
88
lock_inode = os.stat(self._lock_filename).st_ino
89
if lock_inode != self._lock_inode:
92
# Oops.. someone removed the filename while
93
# holding the lock. Let's continue and try
94
# to acquire the new lock.
95
os.close(self._lock_fd)
101
if write or self._lock_kind == LOCK_UN:
102
self._lock_kind = kind
112
This method is reentrant, but not thread safe. To use instances
113
of this class concurrently across threads, some instructions
114
will have to be protected to make it thread-safe.
116
if self._lock_count == 0:
117
raise RuntimeError("Lock not acquired")
119
self._lock_count -= 1
121
if self._lock_count == 0:
122
os.close(self._lock_fd)
123
os.unlink(self._lock_filename)
125
self._lock_kind = LOCK_UN