Skip to content

Commit 4443f28

Browse files
committed
refactor: align lock design with CPython 3.15's HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED
Two changes: 1. Simplify lock macros to match 3.15's unconditional acquire/release: - PyMutex path (3.13+): retain only FIELD/INIT/FINI/ACQUIRE/RELEASE; remove IS_ACTIVE, MAYBE_INIT, ACQUIRE_BLOCKING (no longer needed) - PyThread_type_lock path (3.9-3.12): ACQUIRE/RELEASE are now unconditional blocking calls (no NULL guards, no try-then-block), matching 3.15's HASHLIB_ACQUIRE_LOCK - Non-lock path: keep only mandatory macros 2. Simplify _do_update to 3.15's pattern: - Both large and small data paths use the SAME XXHASH_LOCK_ACQUIRE - Size threshold (XXHASH_GIL_MINSIZE) only controls GIL release, NOT whether locking happens - Matches 3.15's HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED exactly
1 parent ed60cd1 commit 4443f28

1 file changed

Lines changed: 8 additions & 42 deletions

File tree

src/_xxhash.c

Lines changed: 8 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -39,60 +39,26 @@
3939
# if PY_VERSION_HEX >= 0x030d0000 /* Python 3.13+: always-on PyMutex (3.15+ style) */
4040
# define XXHASH_LOCK_FIELD PyMutex mutex;
4141
# define XXHASH_LOCK_INIT(o) ((void)((o)->mutex = (PyMutex){0}))
42-
# define XXHASH_LOCK_IS_ACTIVE(o) 1
43-
# define XXHASH_LOCK_MAYBE_INIT(o, len) ((void)0)
4442
# define XXHASH_LOCK_FINI(o) ((void)0)
4543
# define XXHASH_LOCK_ACQUIRE(o) PyMutex_Lock(&(o)->mutex)
46-
# define XXHASH_LOCK_ACQUIRE_BLOCKING(o) XXHASH_LOCK_ACQUIRE(o)
4744
# define XXHASH_LOCK_RELEASE(o) PyMutex_Unlock(&(o)->mutex)
48-
# else /* Python 3.9-3.12: PyThread_type_lock (always-on, no lazy init) */
45+
# else /* Python 3.9-3.12: PyThread_type_lock (always-on) */
4946
# define XXHASH_LOCK_FIELD PyThread_type_lock lock;
5047
# define XXHASH_LOCK_INIT(o) ((o)->lock = PyThread_allocate_lock())
51-
/* Always-on: lock is allocated in __init__, matching hashlib's approach.
52-
* NULL is only possible if memory allocation fails; guards are defensive. */
53-
# define XXHASH_LOCK_IS_ACTIVE(o) ((o)->lock != NULL)
54-
/* Lazy init removed: lock is always allocated. Safety check retained. */
55-
# define XXHASH_LOCK_MAYBE_INIT(o, len) ((void)0)
5648
# define XXHASH_LOCK_FINI(o) do { if ((o)->lock) \
5749
PyThread_free_lock((o)->lock); \
5850
} while (0)
59-
/* Acquire lock when GIL is already released — simple blocking acquire. */
60-
# define XXHASH_LOCK_ACQUIRE_BLOCKING(o) \
61-
do { \
62-
if ((o)->lock) { \
63-
PyThread_acquire_lock((o)->lock, WAIT_LOCK); \
64-
} \
65-
} while (0)
66-
67-
/* Acquire lock with the GIL held — non-blocking try first, then release
68-
* GIL and block if contested (matches hashlib's ENTER_HASHLIB in 3.9-3.12). */
69-
# define XXHASH_LOCK_ACQUIRE(o) \
70-
do { \
71-
if ((o)->lock) { \
72-
if (!PyThread_acquire_lock((o)->lock, NOWAIT_LOCK)) { \
73-
/* Lock contested — release GIL while waiting. */ \
74-
Py_BEGIN_ALLOW_THREADS \
75-
PyThread_acquire_lock((o)->lock, WAIT_LOCK); \
76-
Py_END_ALLOW_THREADS \
77-
} \
78-
} \
79-
} while (0)
80-
81-
# define XXHASH_LOCK_RELEASE(o) \
82-
do { \
83-
if ((o)->lock) { \
84-
PyThread_release_lock((o)->lock); \
85-
} \
86-
} while (0)
51+
/* Unconditional blocking acquire, matching 3.15's HASHLIB_ACQUIRE_LOCK.
52+
* Under GIL: if lock contended, the holder has released GIL (large data path),
53+
* so we block here without risking deadlock. */
54+
# define XXHASH_LOCK_ACQUIRE(o) PyThread_acquire_lock((o)->lock, WAIT_LOCK)
55+
# define XXHASH_LOCK_RELEASE(o) PyThread_release_lock((o)->lock)
8756
# endif
8857
#else /* !XXHASH_WITH_LOCK */
8958
# define XXHASH_LOCK_FIELD
9059
# define XXHASH_LOCK_INIT(o) ((void)0)
91-
# define XXHASH_LOCK_IS_ACTIVE(o) 0
92-
# define XXHASH_LOCK_MAYBE_INIT(o, len) ((void)0)
9360
# define XXHASH_LOCK_FINI(o) ((void)0)
9461
# define XXHASH_LOCK_ACQUIRE(o) ((void)0)
95-
# define XXHASH_LOCK_ACQUIRE_BLOCKING(o) ((void)0)
9662
# define XXHASH_LOCK_RELEASE(o) ((void)0)
9763
#endif
9864

@@ -644,12 +610,12 @@ PY##type##_do_update(PY##type##Object *self, Py_buffer *buf) \
644610
if (buf->len > XXHASH_GIL_MINSIZE) { \
645611
/* Release GIL first, then acquire lock. */ \
646612
Py_BEGIN_ALLOW_THREADS \
647-
XXHASH_LOCK_ACQUIRE_BLOCKING(self); \
613+
XXHASH_LOCK_ACQUIRE(self); \
648614
update_fn(self->xxhash_state, buf->buf, buf->len); \
649615
XXHASH_LOCK_RELEASE(self); \
650616
Py_END_ALLOW_THREADS \
651617
} else { \
652-
/* Acquire lock with GIL held (try-then-block if contested). */ \
618+
/* Acquire lock with GIL held. */ \
653619
XXHASH_LOCK_ACQUIRE(self); \
654620
update_fn(self->xxhash_state, buf->buf, buf->len); \
655621
XXHASH_LOCK_RELEASE(self); \

0 commit comments

Comments
 (0)