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)