#### This file is lock.pyx ###
"""This modules natively implements Lock and RLock from the threading module."""
cdef extern from "pythread.h":
ctypedef void* PyThread_type_lock
PyThread_type_lock PyThread_allocate_lock()
void PyThread_free_lock(PyThread_type_lock lock)
int PyThread_acquire_lock(PyThread_type_lock lock, int mode)
void PyThread_release_lock(PyThread_type_lock lock)
long PyThread_get_thread_ident()
cdef extern from "python.h":
ctypedef struct PyThreadState:
# this is a place holder
pass
PyThreadState* PyEval_SaveThread()
void PyEval_RestoreThread(PyThreadState* state)
global WAIT_LOCK
global NO_WAIT_LOCK
WAIT_LOCK = 1
NO_WAIT_LOCK = 0
cdef class Lock:
"""A basic, non-reentrant, Lock."""
cdef PyThread_type_lock lock
cdef int locked
def __new__(self):
self.lock = PyThread_allocate_lock()
self.locked=0
def __dealloc__(self):
PyThread_free_lock(self.lock)
def acquire(self,int mode=1):
"""Lock the lock. Without argument, this blocks if the lock is already
locked (even by the same thread), waiting for another thread to release
the lock, and return None once the lock is acquired.
With an argument, this will only block if the argument is true,
and the return value reflects whether the lock is acquired.
The blocking operation is not interruptible."""
cdef int result
cdef PyThreadState* state
# this is the equivalent of Py_BEGIN_ALLOW_THREADS
state=PyEval_SaveThread()
result = PyThread_acquire_lock(self.lock,mode)
# this is the equivalent of Py_END_ALLOW_THREADS
PyEval_RestoreThread(state)
if result==1:
self.locked = 1
return True
else:
return False
def release(self):
"""Release the lock, allowing another thread that is blocked waiting for
the lock to acquire the lock. The lock must be in the locked state,
but it needn't be locked by the same thread that unlocks it."""
if self.locked == 0:
raise Exception('this lock is not locked')
PyThread_release_lock(self.lock)
self.locked = 0
cdef class RLock(Lock):
"""A reentrant Lock. It can be locked many times by the same thread."""
cdef long locker
def acquire(self,int mode=1):
"""Lock the lock. Without argument, this blocks if the lock is already
locked (even by the same thread), waiting for another thread to release
the lock, and return None once the lock is acquired.
With an argument, this will only block if the argument is true,
and the return value reflects whether the lock is acquired.
The blocking operation is not interruptible."""
cdef long candidate
cdef int result
cdef PyThreadState* state
candidate = PyThread_get_thread_ident()
if self.locked==0 or candidate!=self.locker:
state=PyEval_SaveThread()
result = PyThread_acquire_lock(self.lock,mode)
PyEval_RestoreThread(state)
if result==1:
self.locked = 1
self.locker = candidate
return True
else:
return False
else:
self.locked = self.locked + 1
return True
def release(self):
"""Release the lock, allowing another thread that is blocked waiting for
the lock to acquire the lock. The lock must be in the locked state,
but it needn't be locked by the same thread that unlocks it."""
cdef long candidate
if self.locked==0:
raise Exception('this lock is not locked')
else:
candidate = PyThread_get_thread_ident()
if candidate!=self.locker:
raise Exception('thread %i cannot release lock owned by thread %i'%(candidate,self.locker))
else:
self.locked = self.locked - 1
if self.locked==0:
PyThread_release_lock(self.lock)
### This file is setup.py ###
from distutils.core import setup
from distutils.extension import Extension
from Pyrex.Distutils import build_ext
setup(
name = 'Lock module',
ext_modules=[
Extension("lock", ["lock.pyx"]),
],
cmdclass = {'build_ext': build_ext}
)