Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:06:14

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 
0014 #include <cassert>
0015 
0016 #if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
0017 #    include "detail/internals.h"
0018 #endif
0019 
0020 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0021 
0022 PYBIND11_NAMESPACE_BEGIN(detail)
0023 
0024 // forward declarations
0025 PyThreadState *get_thread_state_unchecked();
0026 
0027 PYBIND11_NAMESPACE_END(detail)
0028 
0029 #if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
0030 
0031 /* The functions below essentially reproduce the PyGILState_* API using a RAII
0032  * pattern, but there are a few important differences:
0033  *
0034  * 1. When acquiring the GIL from an non-main thread during the finalization
0035  *    phase, the GILState API blindly terminates the calling thread, which
0036  *    is often not what is wanted. This API does not do this.
0037  *
0038  * 2. The gil_scoped_release function can optionally cut the relationship
0039  *    of a PyThreadState and its associated thread, which allows moving it to
0040  *    another thread (this is a fairly rare/advanced use case).
0041  *
0042  * 3. The reference count of an acquired thread state can be controlled. This
0043  *    can be handy to prevent cases where callbacks issued from an external
0044  *    thread would otherwise constantly construct and destroy thread state data
0045  *    structures.
0046  *
0047  * See the Python bindings of NanoGUI (http://github.com/wjakob/nanogui) for an
0048  * example which uses features 2 and 3 to migrate the Python thread of
0049  * execution to another thread (to run the event loop on the original thread,
0050  * in this case).
0051  */
0052 
0053 class gil_scoped_acquire {
0054 public:
0055     PYBIND11_NOINLINE gil_scoped_acquire() {
0056         auto &internals = detail::get_internals();
0057         tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate);
0058 
0059         if (!tstate) {
0060             /* Check if the GIL was acquired using the PyGILState_* API instead (e.g. if
0061                calling from a Python thread). Since we use a different key, this ensures
0062                we don't create a new thread state and deadlock in PyEval_AcquireThread
0063                below. Note we don't save this state with internals.tstate, since we don't
0064                create it we would fail to clear it (its reference count should be > 0). */
0065             tstate = PyGILState_GetThisThreadState();
0066         }
0067 
0068         if (!tstate) {
0069             tstate = PyThreadState_New(internals.istate);
0070 #    if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
0071             if (!tstate) {
0072                 pybind11_fail("scoped_acquire: could not create thread state!");
0073             }
0074 #    endif
0075             tstate->gilstate_counter = 0;
0076             PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate);
0077         } else {
0078             release = detail::get_thread_state_unchecked() != tstate;
0079         }
0080 
0081         if (release) {
0082             PyEval_AcquireThread(tstate);
0083         }
0084 
0085         inc_ref();
0086     }
0087 
0088     gil_scoped_acquire(const gil_scoped_acquire &) = delete;
0089     gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
0090 
0091     void inc_ref() { ++tstate->gilstate_counter; }
0092 
0093     PYBIND11_NOINLINE void dec_ref() {
0094         --tstate->gilstate_counter;
0095 #    if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
0096         if (detail::get_thread_state_unchecked() != tstate) {
0097             pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!");
0098         }
0099         if (tstate->gilstate_counter < 0) {
0100             pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!");
0101         }
0102 #    endif
0103         if (tstate->gilstate_counter == 0) {
0104 #    if defined(PYBIND11_DETAILED_ERROR_MESSAGES)
0105             if (!release) {
0106                 pybind11_fail("scoped_acquire::dec_ref(): internal error!");
0107             }
0108 #    endif
0109             PyThreadState_Clear(tstate);
0110             if (active) {
0111                 PyThreadState_DeleteCurrent();
0112             }
0113             PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate);
0114             release = false;
0115         }
0116     }
0117 
0118     /// This method will disable the PyThreadState_DeleteCurrent call and the
0119     /// GIL won't be acquired. This method should be used if the interpreter
0120     /// could be shutting down when this is called, as thread deletion is not
0121     /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
0122     /// protect subsequent code.
0123     PYBIND11_NOINLINE void disarm() { active = false; }
0124 
0125     PYBIND11_NOINLINE ~gil_scoped_acquire() {
0126         dec_ref();
0127         if (release) {
0128             PyEval_SaveThread();
0129         }
0130     }
0131 
0132 private:
0133     PyThreadState *tstate = nullptr;
0134     bool release = true;
0135     bool active = true;
0136 };
0137 
0138 class gil_scoped_release {
0139 public:
0140     // PRECONDITION: The GIL must be held when this constructor is called.
0141     explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
0142         assert(PyGILState_Check());
0143         // `get_internals()` must be called here unconditionally in order to initialize
0144         // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
0145         // initialization race could occur as multiple threads try `gil_scoped_acquire`.
0146         auto &internals = detail::get_internals();
0147         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
0148         tstate = PyEval_SaveThread();
0149         if (disassoc) {
0150             // Python >= 3.7 can remove this, it's an int before 3.7
0151             // NOLINTNEXTLINE(readability-qualified-auto)
0152             auto key = internals.tstate;
0153             PYBIND11_TLS_DELETE_VALUE(key);
0154         }
0155     }
0156 
0157     gil_scoped_release(const gil_scoped_release &) = delete;
0158     gil_scoped_release &operator=(const gil_scoped_release &) = delete;
0159 
0160     /// This method will disable the PyThreadState_DeleteCurrent call and the
0161     /// GIL won't be acquired. This method should be used if the interpreter
0162     /// could be shutting down when this is called, as thread deletion is not
0163     /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
0164     /// protect subsequent code.
0165     PYBIND11_NOINLINE void disarm() { active = false; }
0166 
0167     ~gil_scoped_release() {
0168         if (!tstate) {
0169             return;
0170         }
0171         // `PyEval_RestoreThread()` should not be called if runtime is finalizing
0172         if (active) {
0173             PyEval_RestoreThread(tstate);
0174         }
0175         if (disassoc) {
0176             // Python >= 3.7 can remove this, it's an int before 3.7
0177             // NOLINTNEXTLINE(readability-qualified-auto)
0178             auto key = detail::get_internals().tstate;
0179             PYBIND11_TLS_REPLACE_VALUE(key, tstate);
0180         }
0181     }
0182 
0183 private:
0184     PyThreadState *tstate;
0185     bool disassoc;
0186     bool active = true;
0187 };
0188 
0189 #else // PYBIND11_SIMPLE_GIL_MANAGEMENT
0190 
0191 class gil_scoped_acquire {
0192     PyGILState_STATE state;
0193 
0194 public:
0195     gil_scoped_acquire() : state{PyGILState_Ensure()} {}
0196     gil_scoped_acquire(const gil_scoped_acquire &) = delete;
0197     gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
0198     ~gil_scoped_acquire() { PyGILState_Release(state); }
0199     void disarm() {}
0200 };
0201 
0202 class gil_scoped_release {
0203     PyThreadState *state;
0204 
0205 public:
0206     // PRECONDITION: The GIL must be held when this constructor is called.
0207     gil_scoped_release() {
0208         assert(PyGILState_Check());
0209         state = PyEval_SaveThread();
0210     }
0211     gil_scoped_release(const gil_scoped_release &) = delete;
0212     gil_scoped_release &operator=(const gil_scoped_release &) = delete;
0213     ~gil_scoped_release() { PyEval_RestoreThread(state); }
0214     void disarm() {}
0215 };
0216 
0217 #endif // PYBIND11_SIMPLE_GIL_MANAGEMENT
0218 
0219 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)