File indexing completed on 2025-02-16 05:12:16
0001 /* 0002 pybind11/gil.h: RAII helpers for managing the GIL 0003 0004 Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch> 0005 0006 All rights reserved. Use of this source code is governed by a 0007 BSD-style license that can be found in the LICENSE file. 0008 */ 0009 0010 #pragma once 0011 0012 #include "detail/common.h" 0013 #include "detail/internals.h" 0014 0015 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) 0016 0017 0018 PYBIND11_NAMESPACE_BEGIN(detail) 0019 0020 // forward declarations 0021 PyThreadState *get_thread_state_unchecked(); 0022 0023 PYBIND11_NAMESPACE_END(detail) 0024 0025 0026 #if defined(WITH_THREAD) && !defined(PYPY_VERSION) 0027 0028 /* The functions below essentially reproduce the PyGILState_* API using a RAII 0029 * pattern, but there are a few important differences: 0030 * 0031 * 1. When acquiring the GIL from an non-main thread during the finalization 0032 * phase, the GILState API blindly terminates the calling thread, which 0033 * is often not what is wanted. This API does not do this. 0034 * 0035 * 2. The gil_scoped_release function can optionally cut the relationship 0036 * of a PyThreadState and its associated thread, which allows moving it to 0037 * another thread (this is a fairly rare/advanced use case). 0038 * 0039 * 3. The reference count of an acquired thread state can be controlled. This 0040 * can be handy to prevent cases where callbacks issued from an external 0041 * thread would otherwise constantly construct and destroy thread state data 0042 * structures. 0043 * 0044 * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an 0045 * example which uses features 2 and 3 to migrate the Python thread of 0046 * execution to another thread (to run the event loop on the original thread, 0047 * in this case). 0048 */ 0049 0050 class gil_scoped_acquire { 0051 public: 0052 PYBIND11_NOINLINE gil_scoped_acquire() { 0053 auto &internals = detail::get_internals(); 0054 tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate); 0055 0056 if (!tstate) { 0057 /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if 0058 calling from a Python thread). Since we use a different key, this ensures 0059 we don't create a new thread state and deadlock in PyEval_AcquireThread 0060 below. Note we don't save this state with internals.tstate, since we don't 0061 create it we would fail to clear it (its reference count should be > 0). */ 0062 tstate = PyGILState_GetThisThreadState(); 0063 } 0064 0065 if (!tstate) { 0066 tstate = PyThreadState_New(internals.istate); 0067 #if !defined(NDEBUG) 0068 if (!tstate) 0069 pybind11_fail("scoped_acquire: could not create thread state!"); 0070 #endif 0071 tstate->gilstate_counter = 0; 0072 PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); 0073 } else { 0074 release = detail::get_thread_state_unchecked() != tstate; 0075 } 0076 0077 if (release) { 0078 PyEval_AcquireThread(tstate); 0079 } 0080 0081 inc_ref(); 0082 } 0083 0084 void inc_ref() { 0085 ++tstate->gilstate_counter; 0086 } 0087 0088 PYBIND11_NOINLINE void dec_ref() { 0089 --tstate->gilstate_counter; 0090 #if !defined(NDEBUG) 0091 if (detail::get_thread_state_unchecked() != tstate) 0092 pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); 0093 if (tstate->gilstate_counter < 0) 0094 pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); 0095 #endif 0096 if (tstate->gilstate_counter == 0) { 0097 #if !defined(NDEBUG) 0098 if (!release) 0099 pybind11_fail("scoped_acquire::dec_ref(): internal error!"); 0100 #endif 0101 PyThreadState_Clear(tstate); 0102 if (active) 0103 PyThreadState_DeleteCurrent(); 0104 PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate); 0105 release = false; 0106 } 0107 } 0108 0109 /// This method will disable the PyThreadState_DeleteCurrent call and the 0110 /// GIL won't be acquired. This method should be used if the interpreter 0111 /// could be shutting down when this is called, as thread deletion is not 0112 /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and 0113 /// protect subsequent code. 0114 PYBIND11_NOINLINE void disarm() { 0115 active = false; 0116 } 0117 0118 PYBIND11_NOINLINE ~gil_scoped_acquire() { 0119 dec_ref(); 0120 if (release) 0121 PyEval_SaveThread(); 0122 } 0123 private: 0124 PyThreadState *tstate = nullptr; 0125 bool release = true; 0126 bool active = true; 0127 }; 0128 0129 class gil_scoped_release { 0130 public: 0131 explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { 0132 // `get_internals()` must be called here unconditionally in order to initialize 0133 // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an 0134 // initialization race could occur as multiple threads try `gil_scoped_acquire`. 0135 auto &internals = detail::get_internals(); 0136 tstate = PyEval_SaveThread(); 0137 if (disassoc) { 0138 auto key = internals.tstate; 0139 PYBIND11_TLS_DELETE_VALUE(key); 0140 } 0141 } 0142 0143 /// This method will disable the PyThreadState_DeleteCurrent call and the 0144 /// GIL won't be acquired. This method should be used if the interpreter 0145 /// could be shutting down when this is called, as thread deletion is not 0146 /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and 0147 /// protect subsequent code. 0148 PYBIND11_NOINLINE void disarm() { 0149 active = false; 0150 } 0151 0152 ~gil_scoped_release() { 0153 if (!tstate) 0154 return; 0155 // `PyEval_RestoreThread()` should not be called if runtime is finalizing 0156 if (active) 0157 PyEval_RestoreThread(tstate); 0158 if (disassoc) { 0159 auto key = detail::get_internals().tstate; 0160 PYBIND11_TLS_REPLACE_VALUE(key, tstate); 0161 } 0162 } 0163 private: 0164 PyThreadState *tstate; 0165 bool disassoc; 0166 bool active = true; 0167 }; 0168 #elif defined(PYPY_VERSION) 0169 class gil_scoped_acquire { 0170 PyGILState_STATE state; 0171 public: 0172 gil_scoped_acquire() { state = PyGILState_Ensure(); } 0173 ~gil_scoped_acquire() { PyGILState_Release(state); } 0174 void disarm() {} 0175 }; 0176 0177 class gil_scoped_release { 0178 PyThreadState *state; 0179 public: 0180 gil_scoped_release() { state = PyEval_SaveThread(); } 0181 ~gil_scoped_release() { PyEval_RestoreThread(state); } 0182 void disarm() {} 0183 }; 0184 #else 0185 class gil_scoped_acquire { 0186 void disarm() {} 0187 }; 0188 class gil_scoped_release { 0189 void disarm() {} 0190 }; 0191 #endif 0192 0193 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)