aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Modules/hashlib.h
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/hashlib.h')
-rw-r--r--Modules/hashlib.h99
1 files changed, 65 insertions, 34 deletions
diff --git a/Modules/hashlib.h b/Modules/hashlib.h
index e82ec92be25..9a7e72f34a7 100644
--- a/Modules/hashlib.h
+++ b/Modules/hashlib.h
@@ -34,47 +34,78 @@
/*
* 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.
*/
-#include "pythread.h"
-#define ENTER_HASHLIB(obj) \
- if ((obj)->use_mutex) { \
- PyMutex_Lock(&(obj)->mutex); \
- }
-#define LEAVE_HASHLIB(obj) \
- if ((obj)->use_mutex) { \
- PyMutex_Unlock(&(obj)->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; \
+
+#define HASHLIB_ACQUIRE_LOCK(OBJ) PyMutex_Lock(&(OBJ)->mutex)
+#define HASHLIB_RELEASE_LOCK(OBJ) PyMutex_Unlock(&(OBJ)->mutex)
+
+/*
+ * Message length above which the GIL is to be released
+ * when performing hashing operations.
+ */
+#define HASHLIB_GIL_MINSIZE 2048
+
+// 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)
-#endif
-/* TODO(gpshead): We should make this a module or class attribute
- * to allow the user to optimize based on the platform they're using. */
-#define HASHLIB_GIL_MINSIZE 2048
+/*
+ * 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)
static inline int
_Py_hashlib_data_argument(PyObject **res, PyObject *data, PyObject *string)