Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:17:47

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 #if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
0015 #    include "detail/internals.h"
0016 #endif
0017 
0018 PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
0019 
0020 PYBIND11_NAMESPACE_BEGIN(detail)
0021 
0022 // forward declarations
0023 PyThreadState *get_thread_state_unchecked();
0024 
0025 PYBIND11_NAMESPACE_END(detail)
0026 
0027 #if defined(WITH_THREAD)
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     explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) {
0141         // `get_internals()` must be called here unconditionally in order to initialize
0142         // `internals.tstate` for subsequent `gil_scoped_acquire` calls. Otherwise, an
0143         // initialization race could occur as multiple threads try `gil_scoped_acquire`.
0144         auto &internals = detail::get_internals();
0145         // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
0146         tstate = PyEval_SaveThread();
0147         if (disassoc) {
0148             // Python >= 3.7 can remove this, it's an int before 3.7
0149             // NOLINTNEXTLINE(readability-qualified-auto)
0150             auto key = internals.tstate;
0151             PYBIND11_TLS_DELETE_VALUE(key);
0152         }
0153     }
0154 
0155     gil_scoped_release(const gil_scoped_acquire &) = delete;
0156     gil_scoped_release &operator=(const gil_scoped_acquire &) = delete;
0157 
0158     /// This method will disable the PyThreadState_DeleteCurrent call and the
0159     /// GIL won't be acquired. This method should be used if the interpreter
0160     /// could be shutting down when this is called, as thread deletion is not
0161     /// allowed during shutdown. Check _Py_IsFinalizing() on Python 3.7+, and
0162     /// protect subsequent code.
0163     PYBIND11_NOINLINE void disarm() { active = false; }
0164 
0165     ~gil_scoped_release() {
0166         if (!tstate) {
0167             return;
0168         }
0169         // `PyEval_RestoreThread()` should not be called if runtime is finalizing
0170         if (active) {
0171             PyEval_RestoreThread(tstate);
0172         }
0173         if (disassoc) {
0174             // Python >= 3.7 can remove this, it's an int before 3.7
0175             // NOLINTNEXTLINE(readability-qualified-auto)
0176             auto key = detail::get_internals().tstate;
0177             PYBIND11_TLS_REPLACE_VALUE(key, tstate);
0178         }
0179     }
0180 
0181 private:
0182     PyThreadState *tstate;
0183     bool disassoc;
0184     bool active = true;
0185 };
0186 
0187 #    else // PYBIND11_SIMPLE_GIL_MANAGEMENT
0188 
0189 class gil_scoped_acquire {
0190     PyGILState_STATE state;
0191 
0192 public:
0193     gil_scoped_acquire() : state{PyGILState_Ensure()} {}
0194     gil_scoped_acquire(const gil_scoped_acquire &) = delete;
0195     gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
0196     ~gil_scoped_acquire() { PyGILState_Release(state); }
0197     void disarm() {}
0198 };
0199 
0200 class gil_scoped_release {
0201     PyThreadState *state;
0202 
0203 public:
0204     gil_scoped_release() : state{PyEval_SaveThread()} {}
0205     gil_scoped_release(const gil_scoped_release &) = delete;
0206     gil_scoped_release &operator=(const gil_scoped_acquire &) = delete;
0207     ~gil_scoped_release() { PyEval_RestoreThread(state); }
0208     void disarm() {}
0209 };
0210 
0211 #    endif // PYBIND11_SIMPLE_GIL_MANAGEMENT
0212 
0213 #else // WITH_THREAD
0214 
0215 class gil_scoped_acquire {
0216 public:
0217     gil_scoped_acquire() {
0218         // Trick to suppress `unused variable` error messages (at call sites).
0219         (void) (this != (this + 1));
0220     }
0221     gil_scoped_acquire(const gil_scoped_acquire &) = delete;
0222     gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete;
0223     void disarm() {}
0224 };
0225 
0226 class gil_scoped_release {
0227 public:
0228     gil_scoped_release() {
0229         // Trick to suppress `unused variable` error messages (at call sites).
0230         (void) (this != (this + 1));
0231     }
0232     gil_scoped_release(const gil_scoped_release &) = delete;
0233     gil_scoped_release &operator=(const gil_scoped_acquire &) = delete;
0234     void disarm() {}
0235 };
0236 
0237 #endif // WITH_THREAD
0238 
0239 PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)