| |
| |
| |
| |
| |
| |
| |
| |
|
|
| #pragma once |
|
|
| #include "detail/common.h" |
|
|
| #include <cassert> |
|
|
| #if defined(WITH_THREAD) && !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) |
| # include "detail/internals.h" |
| #endif |
|
|
| PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) |
|
|
| PYBIND11_NAMESPACE_BEGIN(detail) |
|
|
| |
| PyThreadState *get_thread_state_unchecked(); |
|
|
| PYBIND11_NAMESPACE_END(detail) |
|
|
| #if defined(WITH_THREAD) |
|
|
| # if !defined(PYBIND11_SIMPLE_GIL_MANAGEMENT) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| class gil_scoped_acquire { |
| public: |
| PYBIND11_NOINLINE gil_scoped_acquire() { |
| auto &internals = detail::get_internals(); |
| tstate = (PyThreadState *) PYBIND11_TLS_GET_VALUE(internals.tstate); |
|
|
| if (!tstate) { |
| |
| |
| |
| |
| |
| tstate = PyGILState_GetThisThreadState(); |
| } |
|
|
| if (!tstate) { |
| tstate = PyThreadState_New(internals.istate); |
| # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) |
| if (!tstate) { |
| pybind11_fail("scoped_acquire: could not create thread state!"); |
| } |
| # endif |
| tstate->gilstate_counter = 0; |
| PYBIND11_TLS_REPLACE_VALUE(internals.tstate, tstate); |
| } else { |
| release = detail::get_thread_state_unchecked() != tstate; |
| } |
|
|
| if (release) { |
| PyEval_AcquireThread(tstate); |
| } |
|
|
| inc_ref(); |
| } |
|
|
| gil_scoped_acquire(const gil_scoped_acquire &) = delete; |
| gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; |
|
|
| void inc_ref() { ++tstate->gilstate_counter; } |
|
|
| PYBIND11_NOINLINE void dec_ref() { |
| --tstate->gilstate_counter; |
| # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) |
| if (detail::get_thread_state_unchecked() != tstate) { |
| pybind11_fail("scoped_acquire::dec_ref(): thread state must be current!"); |
| } |
| if (tstate->gilstate_counter < 0) { |
| pybind11_fail("scoped_acquire::dec_ref(): reference count underflow!"); |
| } |
| # endif |
| if (tstate->gilstate_counter == 0) { |
| # if defined(PYBIND11_DETAILED_ERROR_MESSAGES) |
| if (!release) { |
| pybind11_fail("scoped_acquire::dec_ref(): internal error!"); |
| } |
| # endif |
| PyThreadState_Clear(tstate); |
| if (active) { |
| PyThreadState_DeleteCurrent(); |
| } |
| PYBIND11_TLS_DELETE_VALUE(detail::get_internals().tstate); |
| release = false; |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| PYBIND11_NOINLINE void disarm() { active = false; } |
|
|
| PYBIND11_NOINLINE ~gil_scoped_acquire() { |
| dec_ref(); |
| if (release) { |
| PyEval_SaveThread(); |
| } |
| } |
|
|
| private: |
| PyThreadState *tstate = nullptr; |
| bool release = true; |
| bool active = true; |
| }; |
|
|
| class gil_scoped_release { |
| public: |
| |
| explicit gil_scoped_release(bool disassoc = false) : disassoc(disassoc) { |
| assert(PyGILState_Check()); |
| |
| |
| |
| auto &internals = detail::get_internals(); |
| |
| tstate = PyEval_SaveThread(); |
| if (disassoc) { |
| |
| |
| auto key = internals.tstate; |
| PYBIND11_TLS_DELETE_VALUE(key); |
| } |
| } |
|
|
| gil_scoped_release(const gil_scoped_release &) = delete; |
| gil_scoped_release &operator=(const gil_scoped_release &) = delete; |
|
|
| |
| |
| |
| |
| |
| PYBIND11_NOINLINE void disarm() { active = false; } |
|
|
| ~gil_scoped_release() { |
| if (!tstate) { |
| return; |
| } |
| |
| if (active) { |
| PyEval_RestoreThread(tstate); |
| } |
| if (disassoc) { |
| |
| |
| auto key = detail::get_internals().tstate; |
| PYBIND11_TLS_REPLACE_VALUE(key, tstate); |
| } |
| } |
|
|
| private: |
| PyThreadState *tstate; |
| bool disassoc; |
| bool active = true; |
| }; |
|
|
| # else |
|
|
| class gil_scoped_acquire { |
| PyGILState_STATE state; |
|
|
| public: |
| gil_scoped_acquire() : state{PyGILState_Ensure()} {} |
| gil_scoped_acquire(const gil_scoped_acquire &) = delete; |
| gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; |
| ~gil_scoped_acquire() { PyGILState_Release(state); } |
| void disarm() {} |
| }; |
|
|
| class gil_scoped_release { |
| PyThreadState *state; |
|
|
| public: |
| |
| gil_scoped_release() { |
| assert(PyGILState_Check()); |
| state = PyEval_SaveThread(); |
| } |
| gil_scoped_release(const gil_scoped_release &) = delete; |
| gil_scoped_release &operator=(const gil_scoped_release &) = delete; |
| ~gil_scoped_release() { PyEval_RestoreThread(state); } |
| void disarm() {} |
| }; |
|
|
| # endif |
|
|
| #else |
|
|
| class gil_scoped_acquire { |
| public: |
| gil_scoped_acquire() { |
| |
| (void) (this != (this + 1)); |
| } |
| gil_scoped_acquire(const gil_scoped_acquire &) = delete; |
| gil_scoped_acquire &operator=(const gil_scoped_acquire &) = delete; |
| void disarm() {} |
| }; |
|
|
| class gil_scoped_release { |
| public: |
| gil_scoped_release() { |
| |
| (void) (this != (this + 1)); |
| } |
| gil_scoped_release(const gil_scoped_release &) = delete; |
| gil_scoped_release &operator=(const gil_scoped_release &) = delete; |
| void disarm() {} |
| }; |
|
|
| #endif |
|
|
| PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE) |
|
|