Welcome, guest | Sign In | My Account | Store | Cart
#### 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} 
) 

History