Skip to content

gh-131876: extract _hashlib helpers into a separate directory [WIP] #135341

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Prev Previous commit
Next Next commit
post-merge
  • Loading branch information
picnixz committed Jul 14, 2025
commit e0d2e784d49d06164b5ed493cdda3e34d60617e7
96 changes: 58 additions & 38 deletions Modules/_hashlib/hashlib_mutex.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,78 @@
#include "pycore_lock.h" // PyMutex

/*
* Maximum number of bytes for a message for which the GIL is held
* when performing incremental hashing.
* Message length above which the GIL is to be released
* when performing hashing operations.
*/
#define HASHLIB_GIL_MINSIZE 2048

/*
* Helper code to synchronize access to the hash object when the GIL is
* released around a CPU consuming hashlib operation. All code paths that
* access a mutable part of obj must be enclosed in an ENTER_HASHLIB /
* LEAVE_HASHLIB block or explicitly acquire and release the lock inside
* a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for
* an operation.
* released around a CPU consuming hashlib operation.
*
* These only drop the GIL if the lock acquisition itself is likely to
* block. Thus the non-blocking acquire gating the GIL release for a
* blocking lock acquisition. The intent of these macros is to surround
* the assumed always "fast" operations that you aren't releasing the
* GIL around. Otherwise use code similar to what you see in hash
* function update() methods.
* Code accessing a mutable part of the hash object must be enclosed in
* an HASHLIB_{ACQUIRE,RELEASE}_LOCK block or explicitly acquire and release
* the mutex inside a Py_BEGIN_ALLOW_THREADS -- Py_END_ALLOW_THREADS block if
* they wish to release the GIL for an operation.
*/

/* Prevent undefined behaviors via multiple threads entering the C API. */
#define HASHLIB_LOCK_HEAD \
bool use_mutex; \
#define HASHLIB_OBJECT_HEAD \
PyObject_HEAD \
/* Guard against race conditions during incremental update(). */ \
PyMutex mutex;

#ifdef Py_GIL_DISABLED
#define HASHLIB_INIT_MUTEX(OBJ) \
do { \
(OBJ)->mutex = (PyMutex){0}; \
(OBJ)->use_mutex = true; \
#define HASHLIB_INIT_MUTEX(OBJ) \
do { \
(OBJ)->mutex = (PyMutex){0}; \
} while (0)
#else
#define HASHLIB_INIT_MUTEX(OBJ) \
do { \
(OBJ)->mutex = (PyMutex){0}; \
(OBJ)->use_mutex = false; \
} while (0)
#endif

#define ENTER_HASHLIB(OBJ) \
do { \
if ((OBJ)->use_mutex) { \
PyMutex_Lock(&(OBJ)->mutex); \
} \
#define HASHLIB_ACQUIRE_LOCK(OBJ) PyMutex_Lock(&(OBJ)->mutex)
#define HASHLIB_RELEASE_LOCK(OBJ) PyMutex_Unlock(&(OBJ)->mutex)

// Macros for executing code while conditionally holding the GIL.
//
// These only drop the GIL if the lock acquisition itself is likely to
// block. Thus the non-blocking acquire gating the GIL release for a
// blocking lock acquisition. The intent of these macros is to surround
// the assumed always "fast" operations that you aren't releasing the
// GIL around.

/*
* Execute a suite of C statements 'STATEMENTS'.
*
* The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold.
*/
#define HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(SIZE, STATEMENTS) \
do { \
if ((SIZE) > HASHLIB_GIL_MINSIZE) { \
Py_BEGIN_ALLOW_THREADS \
STATEMENTS; \
Py_END_ALLOW_THREADS \
} \
else { \
STATEMENTS; \
} \
} while (0)

#define LEAVE_HASHLIB(OBJ) \
do { \
if ((OBJ)->use_mutex) { \
PyMutex_Unlock(&(OBJ)->mutex); \
} \
/*
* Lock 'OBJ' and execute a suite of C statements 'STATEMENTS'.
*
* The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold.
*/
#define HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(OBJ, SIZE, STATEMENTS) \
do { \
if ((SIZE) > HASHLIB_GIL_MINSIZE) { \
Py_BEGIN_ALLOW_THREADS \
HASHLIB_ACQUIRE_LOCK(OBJ); \
STATEMENTS; \
HASHLIB_RELEASE_LOCK(OBJ); \
Py_END_ALLOW_THREADS \
} \
else { \
HASHLIB_ACQUIRE_LOCK(OBJ); \
STATEMENTS; \
HASHLIB_RELEASE_LOCK(OBJ); \
} \
} while (0)

#endif // !_HASHLIB_HASHLIB_MUTEX_H
Loading
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy