1
# -*- test-case-name: twisted.test.test_lockfile -*-
2
# Copyright (c) 2005 Divmod, Inc.
3
# Copyright (c) 2008 Twisted Matrix Laboratories.
4
# See LICENSE for details.
7
Filesystem-based interprocess mutex.
14
from time import time as _uniquefloat
17
return str(long(_uniquefloat() * 1000))
22
from os import symlink
23
from os import readlink
24
from os import remove as rmlink
30
from win32api import OpenProcess
35
ERROR_ACCESS_DENIED = 5
36
ERROR_INVALID_PARAMETER = 87
38
def kill(pid, signal):
40
OpenProcess(0, 0, pid)
41
except pywintypes.error, e:
42
if e.args[0] == ERROR_ACCESS_DENIED:
44
elif e.args[0] == ERROR_INVALID_PARAMETER:
45
raise OSError(errno.ESRCH, None)
48
raise RuntimeError("OpenProcess is required to fail.")
52
# XXX Implement an atomic thingamajig for win32
53
def symlink(value, filename):
54
newlinkname = filename+"."+unique()+'.newlink'
55
newvalname = os.path.join(newlinkname,"symlink")
57
f = _open(newvalname,'wcb')
62
rename(newlinkname, filename)
68
def readlink(filename):
70
fObj = _open(os.path.join(filename,'symlink'), 'rb')
72
if e.errno == errno.ENOENT or e.errno == errno.EIO:
73
raise OSError(e.errno, None)
81
os.remove(os.path.join(filename, 'symlink'))
90
This relies on the filesystem property that creating
91
a symlink is an atomic operation and that it will
92
fail if the symlink already exists. Deleting the
93
symlink will release the lock.
95
@ivar name: The name of the file associated with this lock.
97
@ivar clean: Indicates whether this lock was released cleanly by its
98
last owner. Only meaningful after C{lock} has been called and
101
@ivar locked: Indicates whether the lock is currently held by this
108
def __init__(self, name):
117
@return: True if the lock is acquired, false otherwise.
119
@raise: Any exception os.symlink() may raise, other than
125
symlink(str(os.getpid()), self.name)
127
if _windows and e.errno in (errno.EACCES, errno.EIO):
128
# The lock is in the middle of being deleted because we're
129
# on Windows where lock removal isn't atomic. Give up, we
130
# don't know how long this is going to take.
132
if e.errno == errno.EEXIST:
134
pid = readlink(self.name)
136
if e.errno == errno.ENOENT:
137
# The lock has vanished, try to claim it in the
138
# next iteration through the loop.
142
if _windows and e.errno == errno.EACCES:
143
# The lock is in the middle of being
144
# deleted because we're on Windows where
145
# lock removal isn't atomic. Give up, we
146
# don't know how long this is going to
154
if e.errno == errno.ESRCH:
155
# The owner has vanished, try to claim it in the next
156
# iteration through the loop.
160
if e.errno == errno.ENOENT:
161
# Another process cleaned up the lock.
162
# Race them to acquire it in the next
163
# iteration through the loop.
180
This deletes the directory with the given name.
182
@raise: Any exception os.readlink() may raise, or
183
ValueError if the lock is not owned by this process.
185
pid = readlink(self.name)
186
if int(pid) != os.getpid():
187
raise ValueError("Lock %r not owned by this process" % (self.name,))
193
"""Determine if the lock of the given name is held or not.
196
@param name: The filesystem path to the lock to test
199
@return: True if the lock is held, False otherwise.
201
l = FilesystemLock(name)
211
__all__ = ['FilesystemLock', 'isLocked']