|
|
|||
File indexing completed on 2025-11-19 09:50:41
0001 #ifndef Py_CPYTHON_CRITICAL_SECTION_H 0002 # error "this header file must not be included directly" 0003 #endif 0004 0005 // Python critical sections 0006 // 0007 // Conceptually, critical sections are a deadlock avoidance layer on top of 0008 // per-object locks. These helpers, in combination with those locks, replace 0009 // our usage of the global interpreter lock to provide thread-safety for 0010 // otherwise thread-unsafe objects, such as dict. 0011 // 0012 // NOTE: These APIs are no-ops in non-free-threaded builds. 0013 // 0014 // Straightforward per-object locking could introduce deadlocks that were not 0015 // present when running with the GIL. Threads may hold locks for multiple 0016 // objects simultaneously because Python operations can nest. If threads were 0017 // to acquire the same locks in different orders, they would deadlock. 0018 // 0019 // One way to avoid deadlocks is to allow threads to hold only the lock (or 0020 // locks) for a single operation at a time (typically a single lock, but some 0021 // operations involve two locks). When a thread begins a nested operation it 0022 // could suspend the locks for any outer operation: before beginning the nested 0023 // operation, the locks for the outer operation are released and when the 0024 // nested operation completes, the locks for the outer operation are 0025 // reacquired. 0026 // 0027 // To improve performance, this API uses a variation of the above scheme. 0028 // Instead of immediately suspending locks any time a nested operation begins, 0029 // locks are only suspended if the thread would block. This reduces the number 0030 // of lock acquisitions and releases for nested operations, while still 0031 // avoiding deadlocks. 0032 // 0033 // Additionally, the locks for any active operation are suspended around 0034 // other potentially blocking operations, such as I/O. This is because the 0035 // interaction between locks and blocking operations can lead to deadlocks in 0036 // the same way as the interaction between multiple locks. 0037 // 0038 // Each thread's critical sections and their corresponding locks are tracked in 0039 // a stack in `PyThreadState.critical_section`. When a thread calls 0040 // `_PyThreadState_Detach()`, such as before a blocking I/O operation or when 0041 // waiting to acquire a lock, the thread suspends all of its active critical 0042 // sections, temporarily releasing the associated locks. When the thread calls 0043 // `_PyThreadState_Attach()`, it resumes the top-most (i.e., most recent) 0044 // critical section by reacquiring the associated lock or locks. See 0045 // `_PyCriticalSection_Resume()`. 0046 // 0047 // NOTE: Only the top-most critical section is guaranteed to be active. 0048 // Operations that need to lock two objects at once must use 0049 // `Py_BEGIN_CRITICAL_SECTION2()`. You *CANNOT* use nested critical sections 0050 // to lock more than one object at once, because the inner critical section 0051 // may suspend the outer critical sections. This API does not provide a way 0052 // to lock more than two objects at once (though it could be added later 0053 // if actually needed). 0054 // 0055 // NOTE: Critical sections implicitly behave like reentrant locks because 0056 // attempting to acquire the same lock will suspend any outer (earlier) 0057 // critical sections. However, they are less efficient for this use case than 0058 // purposefully designed reentrant locks. 0059 // 0060 // Example usage: 0061 // Py_BEGIN_CRITICAL_SECTION(op); 0062 // ... 0063 // Py_END_CRITICAL_SECTION(); 0064 // 0065 // To lock two objects at once: 0066 // Py_BEGIN_CRITICAL_SECTION2(op1, op2); 0067 // ... 0068 // Py_END_CRITICAL_SECTION2(); 0069 0070 typedef struct PyCriticalSection PyCriticalSection; 0071 typedef struct PyCriticalSection2 PyCriticalSection2; 0072 0073 PyAPI_FUNC(void) 0074 PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op); 0075 0076 PyAPI_FUNC(void) 0077 PyCriticalSection_End(PyCriticalSection *c); 0078 0079 PyAPI_FUNC(void) 0080 PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b); 0081 0082 PyAPI_FUNC(void) 0083 PyCriticalSection2_End(PyCriticalSection2 *c); 0084 0085 #ifndef Py_GIL_DISABLED 0086 # define Py_BEGIN_CRITICAL_SECTION(op) \ 0087 { 0088 # define Py_END_CRITICAL_SECTION() \ 0089 } 0090 # define Py_BEGIN_CRITICAL_SECTION2(a, b) \ 0091 { 0092 # define Py_END_CRITICAL_SECTION2() \ 0093 } 0094 #else /* !Py_GIL_DISABLED */ 0095 0096 // NOTE: the contents of this struct are private and may change betweeen 0097 // Python releases without a deprecation period. 0098 struct PyCriticalSection { 0099 // Tagged pointer to an outer active critical section (or 0). 0100 uintptr_t _cs_prev; 0101 0102 // Mutex used to protect critical section 0103 PyMutex *_cs_mutex; 0104 }; 0105 0106 // A critical section protected by two mutexes. Use 0107 // Py_BEGIN_CRITICAL_SECTION2 and Py_END_CRITICAL_SECTION2. 0108 // NOTE: the contents of this struct are private and may change betweeen 0109 // Python releases without a deprecation period. 0110 struct PyCriticalSection2 { 0111 PyCriticalSection _cs_base; 0112 0113 PyMutex *_cs_mutex2; 0114 }; 0115 0116 # define Py_BEGIN_CRITICAL_SECTION(op) \ 0117 { \ 0118 PyCriticalSection _py_cs; \ 0119 PyCriticalSection_Begin(&_py_cs, _PyObject_CAST(op)) 0120 0121 # define Py_END_CRITICAL_SECTION() \ 0122 PyCriticalSection_End(&_py_cs); \ 0123 } 0124 0125 # define Py_BEGIN_CRITICAL_SECTION2(a, b) \ 0126 { \ 0127 PyCriticalSection2 _py_cs2; \ 0128 PyCriticalSection2_Begin(&_py_cs2, _PyObject_CAST(a), _PyObject_CAST(b)) 0129 0130 # define Py_END_CRITICAL_SECTION2() \ 0131 PyCriticalSection2_End(&_py_cs2); \ 0132 } 0133 0134 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|