Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-03-30 08:26:40

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