1
# Copyright (c) 2005 Divmod, Inc.
2
# Copyright (c) Twisted Matrix Laboratories.
3
# Copyright (c) 2013 The Spyder Development Team
4
# Twisted is distributed under the MIT license.
7
Filesystem-based interprocess mutex.
9
Changes by the Spyder Team to the original Twisted file:
10
-. Rewrite kill Windows function to make it more reliable
17
from time import time as _uniquefloat
20
return str(long(_uniquefloat() * 1000))
23
if not os.name == 'nt':
25
from os import symlink
26
from os import readlink
27
from os import remove as rmlink
34
from ctypes import wintypes
37
kill = None #analysis:ignore
39
# GetExitCodeProcess uses a special exit code to indicate that the
40
# process is still running.
43
def _is_pid_running(pid):
44
"""Taken from http://www.madebuild.org/blog/?p=30"""
45
kernel32 = ctypes.windll.kernel32
46
handle = kernel32.OpenProcess(win32con.PROCESS_QUERY_INFORMATION, 0,
51
# If the process exited recently, a pid may still exist for the
52
# handle. So, check if we can get the exit code.
53
exit_code = wintypes.DWORD()
54
retval = kernel32.GetExitCodeProcess(handle,
55
ctypes.byref(exit_code))
56
is_running = (retval == 0)
57
kernel32.CloseHandle(handle)
59
# See if we couldn't get the exit code or the exit code indicates
60
# that the process is still running.
61
return is_running or exit_code.value == STILL_ACTIVE
63
def kill(pid, signal):
64
if not _is_pid_running(pid):
65
raise OSError(errno.ESRCH, None)
71
# XXX Implement an atomic thingamajig for win32
72
def symlink(value, filename): #analysis:ignore
73
newlinkname = filename+"."+unique()+'.newlink'
74
newvalname = os.path.join(newlinkname,"symlink")
76
f = _open(newvalname,'wcb')
81
rename(newlinkname, filename)
87
def readlink(filename): #analysis:ignore
89
fObj = _open(os.path.join(filename,'symlink'), 'rb')
91
if e.errno == errno.ENOENT or e.errno == errno.EIO:
92
raise OSError(e.errno, None)
99
def rmlink(filename): #analysis:ignore
100
os.remove(os.path.join(filename, 'symlink'))
105
class FilesystemLock:
109
This relies on the filesystem property that creating
110
a symlink is an atomic operation and that it will
111
fail if the symlink already exists. Deleting the
112
symlink will release the lock.
114
@ivar name: The name of the file associated with this lock.
116
@ivar clean: Indicates whether this lock was released cleanly by its
117
last owner. Only meaningful after C{lock} has been called and
120
@ivar locked: Indicates whether the lock is currently held by this
127
def __init__(self, name):
136
@return: True if the lock is acquired, false otherwise.
138
@raise: Any exception os.symlink() may raise, other than
144
symlink(str(os.getpid()), self.name)
146
if _windows and e.errno in (errno.EACCES, errno.EIO):
147
# The lock is in the middle of being deleted because we're
148
# on Windows where lock removal isn't atomic. Give up, we
149
# don't know how long this is going to take.
151
if e.errno == errno.EEXIST:
153
pid = readlink(self.name)
155
if e.errno == errno.ENOENT:
156
# The lock has vanished, try to claim it in the
157
# next iteration through the loop.
161
if _windows and e.errno == errno.EACCES:
162
# The lock is in the middle of being
163
# deleted because we're on Windows where
164
# lock removal isn't atomic. Give up, we
165
# don't know how long this is going to
173
if e.errno == errno.ESRCH:
174
# The owner has vanished, try to claim it in the next
175
# iteration through the loop.
179
if e.errno == errno.ENOENT:
180
# Another process cleaned up the lock.
181
# Race them to acquire it in the next
182
# iteration through the loop.
199
This deletes the directory with the given name.
201
@raise: Any exception os.readlink() may raise, or
202
ValueError if the lock is not owned by this process.
204
pid = readlink(self.name)
205
if int(pid) != os.getpid():
206
raise ValueError("Lock %r not owned by this process" % (self.name,))
212
"""Determine if the lock of the given name is held or not.
215
@param name: The filesystem path to the lock to test
218
@return: True if the lock is held, False otherwise.
220
l = FilesystemLock(name)
230
__all__ = ['FilesystemLock', 'isLocked']