|
5 | 5 | #include "pycore_lock.h" // PyMutex |
6 | 6 |
|
7 | 7 | /* |
8 | | - * Maximum number of bytes for a message for which the GIL is held |
9 | | - * when performing incremental hashing. |
| 8 | + * Message length above which the GIL is to be released |
| 9 | + * when performing hashing operations. |
10 | 10 | */ |
11 | 11 | #define HASHLIB_GIL_MINSIZE 2048 |
12 | 12 |
|
13 | 13 | /* |
14 | 14 | * Helper code to synchronize access to the hash object when the GIL is |
15 | | - * released around a CPU consuming hashlib operation. All code paths that |
16 | | - * access a mutable part of obj must be enclosed in an ENTER_HASHLIB / |
17 | | - * LEAVE_HASHLIB block or explicitly acquire and release the lock inside |
18 | | - * a PY_BEGIN / END_ALLOW_THREADS block if they wish to release the GIL for |
19 | | - * an operation. |
| 15 | + * released around a CPU consuming hashlib operation. |
20 | 16 | * |
21 | | - * These only drop the GIL if the lock acquisition itself is likely to |
22 | | - * block. Thus the non-blocking acquire gating the GIL release for a |
23 | | - * blocking lock acquisition. The intent of these macros is to surround |
24 | | - * the assumed always "fast" operations that you aren't releasing the |
25 | | - * GIL around. Otherwise use code similar to what you see in hash |
26 | | - * function update() methods. |
| 17 | + * Code accessing a mutable part of the hash object must be enclosed in |
| 18 | + * an HASHLIB_{ACQUIRE,RELEASE}_LOCK block or explicitly acquire and release |
| 19 | + * the mutex inside a Py_BEGIN_ALLOW_THREADS -- Py_END_ALLOW_THREADS block if |
| 20 | + * they wish to release the GIL for an operation. |
27 | 21 | */ |
28 | 22 |
|
29 | | -/* Prevent undefined behaviors via multiple threads entering the C API. */ |
30 | | -#define HASHLIB_LOCK_HEAD \ |
31 | | - bool use_mutex; \ |
| 23 | +#define HASHLIB_OBJECT_HEAD \ |
| 24 | + PyObject_HEAD \ |
| 25 | + /* Guard against race conditions during incremental update(). */ \ |
32 | 26 | PyMutex mutex; |
33 | 27 |
|
34 | | -#ifdef Py_GIL_DISABLED |
35 | | -#define HASHLIB_INIT_MUTEX(OBJ) \ |
36 | | - do { \ |
37 | | - (OBJ)->mutex = (PyMutex){0}; \ |
38 | | - (OBJ)->use_mutex = true; \ |
| 28 | +#define HASHLIB_INIT_MUTEX(OBJ) \ |
| 29 | + do { \ |
| 30 | + (OBJ)->mutex = (PyMutex){0}; \ |
39 | 31 | } while (0) |
40 | | -#else |
41 | | -#define HASHLIB_INIT_MUTEX(OBJ) \ |
42 | | - do { \ |
43 | | - (OBJ)->mutex = (PyMutex){0}; \ |
44 | | - (OBJ)->use_mutex = false; \ |
45 | | - } while (0) |
46 | | -#endif |
47 | 32 |
|
48 | | -#define ENTER_HASHLIB(OBJ) \ |
49 | | - do { \ |
50 | | - if ((OBJ)->use_mutex) { \ |
51 | | - PyMutex_Lock(&(OBJ)->mutex); \ |
52 | | - } \ |
| 33 | +#define HASHLIB_ACQUIRE_LOCK(OBJ) PyMutex_Lock(&(OBJ)->mutex) |
| 34 | +#define HASHLIB_RELEASE_LOCK(OBJ) PyMutex_Unlock(&(OBJ)->mutex) |
| 35 | + |
| 36 | +// Macros for executing code while conditionally holding the GIL. |
| 37 | +// |
| 38 | +// These only drop the GIL if the lock acquisition itself is likely to |
| 39 | +// block. Thus the non-blocking acquire gating the GIL release for a |
| 40 | +// blocking lock acquisition. The intent of these macros is to surround |
| 41 | +// the assumed always "fast" operations that you aren't releasing the |
| 42 | +// GIL around. |
| 43 | + |
| 44 | +/* |
| 45 | + * Execute a suite of C statements 'STATEMENTS'. |
| 46 | + * |
| 47 | + * The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold. |
| 48 | + */ |
| 49 | +#define HASHLIB_EXTERNAL_INSTRUCTIONS_UNLOCKED(SIZE, STATEMENTS) \ |
| 50 | + do { \ |
| 51 | + if ((SIZE) > HASHLIB_GIL_MINSIZE) { \ |
| 52 | + Py_BEGIN_ALLOW_THREADS \ |
| 53 | + STATEMENTS; \ |
| 54 | + Py_END_ALLOW_THREADS \ |
| 55 | + } \ |
| 56 | + else { \ |
| 57 | + STATEMENTS; \ |
| 58 | + } \ |
53 | 59 | } while (0) |
54 | 60 |
|
55 | | -#define LEAVE_HASHLIB(OBJ) \ |
56 | | - do { \ |
57 | | - if ((OBJ)->use_mutex) { \ |
58 | | - PyMutex_Unlock(&(OBJ)->mutex); \ |
59 | | - } \ |
| 61 | +/* |
| 62 | + * Lock 'OBJ' and execute a suite of C statements 'STATEMENTS'. |
| 63 | + * |
| 64 | + * The GIL is held if 'SIZE' is below the HASHLIB_GIL_MINSIZE threshold. |
| 65 | + */ |
| 66 | +#define HASHLIB_EXTERNAL_INSTRUCTIONS_LOCKED(OBJ, SIZE, STATEMENTS) \ |
| 67 | + do { \ |
| 68 | + if ((SIZE) > HASHLIB_GIL_MINSIZE) { \ |
| 69 | + Py_BEGIN_ALLOW_THREADS \ |
| 70 | + HASHLIB_ACQUIRE_LOCK(OBJ); \ |
| 71 | + STATEMENTS; \ |
| 72 | + HASHLIB_RELEASE_LOCK(OBJ); \ |
| 73 | + Py_END_ALLOW_THREADS \ |
| 74 | + } \ |
| 75 | + else { \ |
| 76 | + HASHLIB_ACQUIRE_LOCK(OBJ); \ |
| 77 | + STATEMENTS; \ |
| 78 | + HASHLIB_RELEASE_LOCK(OBJ); \ |
| 79 | + } \ |
60 | 80 | } while (0) |
61 | 81 |
|
62 | 82 | #endif // !_HASHLIB_HASHLIB_MUTEX_H |
0 commit comments