##################################################
# 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 <jdf@pobox.com>
# 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)
|