################################################## # SPYCE - Python-based HTML Scripting # Copyright (c) 2002 Rimon Barr. # # Refer to spyce.py ################################################## import os __doc__ = 'Spyce locking-related functions' class dummyLock: def acquire(self, block=True): return True def release(self): pass try: import threading except ImportError: threadLock = dummyLock else: threadLock = threading.RLock ################################################## # File locking # # Adapted from portalocker.py, written by Jonathan Feinberg # Used in rimap (http://rimap.sourceforge.net) before Spyce # Methods: # file_lock(file, flags) # file_unlock(file) # Constants: LOCK_EX, LOCK_SH, LOCK_NB # -- RB # TODO dumb down to just provide "lock" and "lock_nb"; win32 code # doesn't work, and the msvcrt code that DOES work doesn't map well # to the "flags" approach here try: if os.name=='nt': import win32con, win32file, pywintypes LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK LOCK_SH = 0 # the default LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY # is there any reason not to reuse the following structure? __overlapped = pywintypes.OVERLAPPED() def file_lock(file, flags): hfile = win32file._get_osfhandle(file.fileno()) win32file.LockFileEx(hfile, flags, 0, -0x10000, __overlapped) def file_unlock(file): hfile = win32file._get_osfhandle(file.fileno()) win32file.UnlockFileEx(hfile, 0, -0x10000, __overlapped) elif os.name == 'posix': import fcntl LOCK_EX = fcntl.LOCK_EX LOCK_SH = fcntl.LOCK_SH LOCK_NB = fcntl.LOCK_NB def file_lock(file, flags): fcntl.flock(file.fileno(), flags) def file_unlock(file): fcntl.flock(file.fileno(), fcntl.LOCK_UN) else: raise 'locking not supported on this platform' except: LOCK_EX = 0 LOCK_SH = 0 LOCK_NB = 0 # bring on the race conditions! :) def file_lock(file, flags): pass def file_unlock(file): pass class fileLock: f=name=None def __init__(self, name): self.name=name+'.lock' def acquire(self, block=1): self.f=open(self.name, 'w') if block: file_lock(self.f, LOCK_EX) else: file_lock(self.f, LOCK_EX | LOCK_NB) def release(self): try: if not self.f: return file_unlock(self.f) self.f.close() os.unlink(self.name) self.f=None except: pass class MultiLock: """ A lock that reduces contention by maintaining multiple locks internally and mapping requests in a consistent manner to these. """ def __init__(self, locks, lock_generator): self.locks = [] for i in xrange(locks): self.locks.append(lock_generator(i)) def _lock(self, obj): return self.locks[hash(obj) % len(self.locks)] def acquire(self, obj, *args, **kwargs): lock = self._lock(obj) return lock.acquire(*args, **kwargs) def release(self, obj, *args, **kwargs): lock = self._lock(obj) return lock.release(*args, **kwargs) def locked(self, obj, *args, **kwargs): lock = self._lock(obj) return lock.locked(*args, **kwargs)