From 9a27e29ebd883df12435bb5b29b025ac46cfbd34 Mon Sep 17 00:00:00 2001 From: "Ralf W. Grosse-Kunstleve" Date: Thu, 18 Jul 2024 01:10:48 -0700 Subject: [PATCH] Leverage PR #5251 to bring back trampoline_self_life_support.h from smart_holder branch almost as-is. This ensures IWYU correctness in client code. The only change in trampoline_self_life_support.h is to replace `#include "detail/type_caster_base.h"` with "#include detail/value_and_holder.h". --- include/pybind11/detail/type_caster_base.h | 47 +-------------- .../pybind11/trampoline_self_life_support.h | 59 ++++++++++++++++++- 2 files changed, 57 insertions(+), 49 deletions(-) diff --git a/include/pybind11/detail/type_caster_base.h b/include/pybind11/detail/type_caster_base.h index 9979421ad..c8b2b4f01 100644 --- a/include/pybind11/detail/type_caster_base.h +++ b/include/pybind11/detail/type_caster_base.h @@ -11,6 +11,7 @@ #include "../gil.h" #include "../pytypes.h" +#include "../trampoline_self_life_support.h" #include "common.h" #include "descr.h" #include "dynamic_raw_ptr_cast_if_possible.h" @@ -474,52 +475,6 @@ inline PyObject *make_new_instance(PyTypeObject *type); // SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); -PYBIND11_NAMESPACE_END(detail) - -// The original core idea for this struct goes back to PyCLIF: -// https://github.com/google/clif/blob/07f95d7e69dca2fcf7022978a55ef3acff506c19/clif/python/runtime.cc#L37 -// URL provided here mainly to give proper credit. To fully explain the `HoldPyObj` feature, more -// context is needed (SMART_HOLDER_WIP). -struct trampoline_self_life_support { - detail::value_and_holder v_h; - - trampoline_self_life_support() = default; - - void activate_life_support(const detail::value_and_holder &v_h_) { - Py_INCREF((PyObject *) v_h_.inst); - v_h = v_h_; - } - - void deactivate_life_support() { - Py_DECREF((PyObject *) v_h.inst); - v_h = detail::value_and_holder(); - } - - ~trampoline_self_life_support() { - if (v_h.inst != nullptr && v_h.vh != nullptr) { - void *value_void_ptr = v_h.value_ptr(); - if (value_void_ptr != nullptr) { - PyGILState_STATE threadstate = PyGILState_Ensure(); - v_h.value_ptr() = nullptr; - v_h.holder().release_disowned(); - detail::deregister_instance(v_h.inst, value_void_ptr, v_h.type); - Py_DECREF((PyObject *) v_h.inst); // Must be after deregister. - PyGILState_Release(threadstate); - } - } - } - - // For the next two, the default implementations generate undefined behavior (ASAN failures - // manually verified). The reason is that v_h needs to be kept default-initialized. - trampoline_self_life_support(const trampoline_self_life_support &) {} - trampoline_self_life_support(trampoline_self_life_support &&) noexcept {} - - // These should never be needed (please provide test cases if you think they are). - trampoline_self_life_support &operator=(const trampoline_self_life_support &) = delete; - trampoline_self_life_support &operator=(trampoline_self_life_support &&) = delete; -}; - -PYBIND11_NAMESPACE_BEGIN(detail) PYBIND11_NAMESPACE_BEGIN(smart_holder_type_caster_support) struct value_and_holder_helper { diff --git a/include/pybind11/trampoline_self_life_support.h b/include/pybind11/trampoline_self_life_support.h index ee809b9c5..47f623953 100644 --- a/include/pybind11/trampoline_self_life_support.h +++ b/include/pybind11/trampoline_self_life_support.h @@ -1,8 +1,61 @@ -// Copyright (c) 2024 The Pybind Development Team. +// Copyright (c) 2021 The Pybind Development Team. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. #pragma once -// BAKEIN_WIP: Needs refactoring of existing pybind11 code. -#include "detail/type_caster_base.h" +#include "detail/common.h" +#include "detail/smart_holder_poc.h" +#include "detail/value_and_holder.h" + +PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) + +PYBIND11_NAMESPACE_BEGIN(detail) +// SMART_HOLDER_WIP: Needs refactoring of existing pybind11 code. +inline bool deregister_instance(instance *self, void *valptr, const type_info *tinfo); +PYBIND11_NAMESPACE_END(detail) + +// The original core idea for this struct goes back to PyCLIF: +// https://github.com/google/clif/blob/07f95d7e69dca2fcf7022978a55ef3acff506c19/clif/python/runtime.cc#L37 +// URL provided here mainly to give proper credit. To fully explain the `HoldPyObj` feature, more +// context is needed (SMART_HOLDER_WIP). +struct trampoline_self_life_support { + detail::value_and_holder v_h; + + trampoline_self_life_support() = default; + + void activate_life_support(const detail::value_and_holder &v_h_) { + Py_INCREF((PyObject *) v_h_.inst); + v_h = v_h_; + } + + void deactivate_life_support() { + Py_DECREF((PyObject *) v_h.inst); + v_h = detail::value_and_holder(); + } + + ~trampoline_self_life_support() { + if (v_h.inst != nullptr && v_h.vh != nullptr) { + void *value_void_ptr = v_h.value_ptr(); + if (value_void_ptr != nullptr) { + PyGILState_STATE threadstate = PyGILState_Ensure(); + v_h.value_ptr() = nullptr; + v_h.holder().release_disowned(); + detail::deregister_instance(v_h.inst, value_void_ptr, v_h.type); + Py_DECREF((PyObject *) v_h.inst); // Must be after deregister. + PyGILState_Release(threadstate); + } + } + } + + // For the next two, the default implementations generate undefined behavior (ASAN failures + // manually verified). The reason is that v_h needs to be kept default-initialized. + trampoline_self_life_support(const trampoline_self_life_support &) {} + trampoline_self_life_support(trampoline_self_life_support &&) noexcept {} + + // These should never be needed (please provide test cases if you think they are). + trampoline_self_life_support &operator=(const trampoline_self_life_support &) = delete; + trampoline_self_life_support &operator=(trampoline_self_life_support &&) = delete; +}; + +PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)