Skip to content

Commit 48ad548

Browse files
committed
Use unsigned thread IDs as exposed by Py3.7+.
1 parent f2ae506 commit 48ad548

File tree

3 files changed

+39
-16
lines changed

3 files changed

+39
-16
lines changed

CHANGES.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
fastrlock changelog
33
===================
44

5+
Upcoming release
6+
================
7+
8+
* Adapted for unsigned thread IDs, as used by Py3.7+.
9+
(original patch by Guilherme Dantas)
10+
11+
512
0.6 (2021-03-21)
613
================
714

fastrlock/_lock.pxi

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,29 @@ from cpython cimport pythread
33

44
from fastrlock import LockNotAcquired
55

6+
cdef extern from *:
7+
# Compatibility definitions for Python
8+
"""
9+
#if PY_VERSION_HEX >= 0x030700a2
10+
typedef unsigned long pythread_t;
11+
#else
12+
typedef long pythread_t;
13+
#endif
14+
"""
15+
16+
# Just let Cython understand that pythread_t is
17+
# a long type, but be aware that it is actually
18+
# signed for versions of Python prior to 3.7.0a2 and
19+
# unsigned for later versions
20+
ctypedef unsigned long pythread_t
21+
622

723
cdef struct _LockStatus:
824
pythread.PyThread_type_lock lock
9-
long owner # thread ID of the current lock owner
10-
int entry_count # number of (re-)entries of the owner
11-
int pending_requests # number of pending requests for real lock
12-
bint is_locked # whether the real lock is acquired
25+
pythread_t owner # thread ID of the current lock owner
26+
unsigned int entry_count # number of (re-)entries of the owner
27+
unsigned int pending_requests # number of pending requests for real lock
28+
bint is_locked # whether the real lock is acquired
1329

1430

1531
cdef bint _acquire_lock(_LockStatus *lock, long current_thread,
@@ -34,6 +50,7 @@ cdef bint _acquire_lock(_LockStatus *lock, long current_thread,
3450
if locked:
3551
break
3652
if wait == pythread.NOWAIT_LOCK:
53+
lock.pending_requests -= 1
3754
return False
3855
lock.pending_requests -= 1
3956
#assert not lock.is_locked
@@ -53,7 +70,6 @@ cdef inline void _unlock_lock(_LockStatus *lock) nogil:
5370
#assert lock.entry_count > 0
5471
lock.entry_count -= 1
5572
if lock.entry_count == 0:
56-
lock.owner = -1
5773
if lock.is_locked:
5874
pythread.PyThread_release_lock(lock.lock)
5975
lock.is_locked = False

fastrlock/rlock.pyx

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ cdef class FastRLock:
2020
def __cinit__(self):
2121
self._real_lock = _LockStatus(
2222
lock=pythread.PyThread_allocate_lock(),
23-
owner=-1, is_locked=False, pending_requests=0, entry_count=0)
23+
owner=0, is_locked=False, pending_requests=0, entry_count=0)
2424
if not self._real_lock.lock:
2525
raise MemoryError()
2626

@@ -33,31 +33,30 @@ cdef class FastRLock:
3333

3434
def acquire(self, bint blocking=True):
3535
return _lock_rlock(
36-
&self._real_lock, <long>pythread.PyThread_get_thread_ident(), blocking)
36+
&self._real_lock, pythread.PyThread_get_thread_ident(), blocking)
3737

3838
def release(self):
39-
if self._real_lock.owner == -1:
39+
if self._real_lock.entry_count == 0:
4040
raise RuntimeError("cannot release un-acquired lock")
4141
_unlock_lock(&self._real_lock)
4242

4343
def __enter__(self):
4444
# self.acquire()
4545
if not _lock_rlock(
46-
&self._real_lock, <long>pythread.PyThread_get_thread_ident(),
47-
blocking=True):
46+
&self._real_lock, pythread.PyThread_get_thread_ident(), blocking=True):
4847
raise LockNotAcquired()
4948

5049
def __exit__(self, t, v, tb):
5150
# self.release()
52-
if self._real_lock.owner != <long>pythread.PyThread_get_thread_ident():
51+
if self._real_lock.entry_count == 0 or self._real_lock.owner != pythread.PyThread_get_thread_ident():
5352
raise RuntimeError("cannot release un-acquired lock")
5453
_unlock_lock(&self._real_lock)
5554

5655
def _is_owned(self):
57-
return self._real_lock.owner == <long>pythread.PyThread_get_thread_ident()
56+
return self._real_lock.entry_count > 0 and self._real_lock.owner == pythread.PyThread_get_thread_ident()
5857

5958

60-
cdef inline bint _lock_rlock(_LockStatus *lock, long current_thread,
59+
cdef inline bint _lock_rlock(_LockStatus *lock, pythread_t current_thread,
6160
bint blocking) nogil:
6261
# Note that this function *must* hold the GIL when being called.
6362
# We just use 'nogil' in the signature to make sure that no Python
@@ -90,10 +89,11 @@ cdef create_fastrlock():
9089
cdef bint lock_fastrlock(rlock, long current_thread, bint blocking) except -1:
9190
"""
9291
Public C level entry function for locking a FastRlock instance.
92+
93+
The 'current_thread' argument is deprecated and ignored. Pass -1 for backwards compatibility.
9394
"""
94-
if current_thread == -1:
95-
current_thread = <long>pythread.PyThread_get_thread_ident()
96-
return _lock_rlock(&(<FastRLock?>rlock)._real_lock, current_thread, blocking)
95+
# Note: 'current_thread' used to be set to -1 or the current thread ID, but -1 is signed while "pythread_t" isn't.
96+
return _lock_rlock(&(<FastRLock?>rlock)._real_lock, pythread.PyThread_get_thread_ident(), blocking)
9797

9898

9999
cdef int unlock_fastrlock(rlock) except -1:

0 commit comments

Comments
 (0)