Skip to content

Commit

Permalink
Leverage PR pybind#5251 to bring back trampoline_self_life_support.h …
Browse files Browse the repository at this point in the history
…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".
  • Loading branch information
Ralf W. Grosse-Kunstleve committed Jul 18, 2024
1 parent 7fa6dd9 commit 9a27e29
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 49 deletions.
47 changes: 1 addition & 46 deletions include/pybind11/detail/type_caster_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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<pybindit::memory::smart_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 {
Expand Down
59 changes: 56 additions & 3 deletions include/pybind11/trampoline_self_life_support.h
Original file line number Diff line number Diff line change
@@ -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<pybindit::memory::smart_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)

0 comments on commit 9a27e29

Please sign in to comment.