Skip to content

Add detail/cross_extension_shared_state.h #30008

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 22 commits into from
Mar 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
04557ca
Transfer PR #4329 from master to smart_holder branch, STEP 1.
rwgk Nov 19, 2022
a45bb61
Make `smart_holder` code compatible with `type_caster_enum_type`
rwgk Nov 20, 2022
3ec457a
Fix `if` condition guarding `Unable to cast native enum type to refer…
rwgk Nov 20, 2022
9e940e7
WIP native_enum_add_to_parent
rwgk Nov 20, 2022
f344bfa
PYBIND11_SILENCE_MSVC_C4127
rwgk Nov 21, 2022
41cf4ce
Merge branch 'smart_holder' into native_enum_sh
rwgk Dec 5, 2022
b5f8cde
Merge branch 'smart_holder' into native_enum_sh
rwgk Dec 6, 2022
78bfc94
Merge branch 'smart_holder' into native_enum_sh
rwgk Jan 4, 2023
10253a1
Transfer upstream.yml/python312.yml changes from PR #4397
rwgk Jan 4, 2023
8690a88
clang-tidy (clang 15) auto-fix
rwgk Jan 4, 2023
613b46e
Merge branch 'smart_holder' into native_enum_sh
rwgk Feb 17, 2023
822f988
Remove python312.yml: this is handled separately under PR #30006
rwgk Mar 9, 2023
5f23bee
Merge branch 'google_pywrapcc_main' into native_enum_pywrapcc
rwgk Mar 9, 2023
38559c3
Fixes for ruff
rwgk Mar 9, 2023
630ba5f
Merge branch 'google_pywrapcc_main' into native_enum_pywrapcc
rwgk Mar 9, 2023
3104a35
Replace `PyEval_GetBuiltins()` in `finalize_interpreter()` with `get_…
rwgk Mar 14, 2023
498c1d2
Bug fix: Ensure `state_dict` is destroyed before `Py_Finalize()`
rwgk Mar 14, 2023
4f5a125
Restore tests/test_embed/test_interpreter.cpp from google_pywrapcc_main
rwgk Mar 15, 2023
0a59ad2
Restore include/pybind11/embed.h from google_pywrapcc_main
rwgk Mar 15, 2023
4312d6e
Merge branch 'google_pywrapcc_main' into native_enum_pywrapcc_wrk
rwgk Mar 15, 2023
ce4872d
Back out all native_enum changes, leaving only the cross_extension_sh…
rwgk Mar 15, 2023
1574078
Undo unrelated one-line change (from `auto` to `internals`).
rwgk Mar 15, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions include/pybind11/detail/abi_platform_id.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) 2022 The pybind Community.
// 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

#include "common.h"

/// On MSVC, debug and release builds are not ABI-compatible!
#if defined(_MSC_VER) && defined(_DEBUG)
# define PYBIND11_BUILD_TYPE "_debug"
#else
# define PYBIND11_BUILD_TYPE ""
#endif

/// Let's assume that different compilers are ABI-incompatible.
/// A user can manually set this string if they know their
/// compiler is compatible.
#ifndef PYBIND11_COMPILER_TYPE
# if defined(_MSC_VER)
# define PYBIND11_COMPILER_TYPE "_msvc"
# elif defined(__INTEL_COMPILER)
# define PYBIND11_COMPILER_TYPE "_icc"
# elif defined(__clang__)
# define PYBIND11_COMPILER_TYPE "_clang"
# elif defined(__PGI)
# define PYBIND11_COMPILER_TYPE "_pgi"
# elif defined(__MINGW32__)
# define PYBIND11_COMPILER_TYPE "_mingw"
# elif defined(__CYGWIN__)
# define PYBIND11_COMPILER_TYPE "_gcc_cygwin"
# elif defined(__GNUC__)
# define PYBIND11_COMPILER_TYPE "_gcc"
# else
# define PYBIND11_COMPILER_TYPE "_unknown"
# endif
#endif

/// Also standard libs
#ifndef PYBIND11_STDLIB
# if defined(_LIBCPP_VERSION)
# define PYBIND11_STDLIB "_libcpp"
# elif defined(__GLIBCXX__) || defined(__GLIBCPP__)
# define PYBIND11_STDLIB "_libstdcpp"
# else
# define PYBIND11_STDLIB ""
# endif
#endif

/// On Linux/OSX, changes in __GXX_ABI_VERSION__ indicate ABI incompatibility.
#ifndef PYBIND11_BUILD_ABI
# if defined(__GXX_ABI_VERSION)
# define PYBIND11_BUILD_ABI "_cxxabi" PYBIND11_TOSTRING(__GXX_ABI_VERSION)
# else
# define PYBIND11_BUILD_ABI ""
# endif
#endif

#ifndef PYBIND11_INTERNALS_KIND
# if defined(WITH_THREAD)
# define PYBIND11_INTERNALS_KIND ""
# else
# define PYBIND11_INTERNALS_KIND "_without_thread"
# endif
#endif

/// See README_smart_holder.rst:
/// Classic / Conservative / Progressive cross-module compatibility
#ifndef PYBIND11_INTERNALS_SH_DEF
# if defined(PYBIND11_USE_SMART_HOLDER_AS_DEFAULT)
# define PYBIND11_INTERNALS_SH_DEF ""
# else
# define PYBIND11_INTERNALS_SH_DEF "_sh_def"
# endif
#endif

/* NOTE - ATTENTION - WARNING - EXTREME CAUTION
Changing this will break compatibility with `PYBIND11_INTERNALS_VERSION 4`
See pybind11/detail/type_map.h for more information.
*/
#define PYBIND11_PLATFORM_ABI_ID_V4 \
PYBIND11_INTERNALS_KIND PYBIND11_COMPILER_TYPE PYBIND11_STDLIB PYBIND11_BUILD_ABI \
PYBIND11_BUILD_TYPE PYBIND11_INTERNALS_SH_DEF

/// LEGACY "ABI-breaking" APPROACH, ORIGINAL COMMENT
/// ------------------------------------------------
/// Tracks the `internals` and `type_info` ABI version independent of the main library version.
///
/// Some portions of the code use an ABI that is conditional depending on this
/// version number. That allows ABI-breaking changes to be "pre-implemented".
/// Once the default version number is incremented, the conditional logic that
/// no longer applies can be removed. Additionally, users that need not
/// maintain ABI compatibility can increase the version number in order to take
/// advantage of any functionality/efficiency improvements that depend on the
/// newer ABI.
///
/// WARNING: If you choose to manually increase the ABI version, note that
/// pybind11 may not be tested as thoroughly with a non-default ABI version, and
/// further ABI-incompatible changes may be made before the ABI is officially
/// changed to the new version.
#ifndef PYBIND11_INTERNALS_VERSION
# define PYBIND11_INTERNALS_VERSION 4
#endif
142 changes: 142 additions & 0 deletions include/pybind11/detail/cross_extension_shared_state.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright (c) 2022 The pybind Community.
// 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

#include "common.h"

#if defined(WITH_THREAD) && defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
# include "../gil.h"
#endif

#include "../pytypes.h"
#include "abi_platform_id.h"

#include <string>

PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
PYBIND11_NAMESPACE_BEGIN(detail)

inline object get_python_state_dict() {
object state_dict;
#if (PYBIND11_INTERNALS_VERSION <= 4 && PY_VERSION_HEX < 0x030C0000) \
|| PY_VERSION_HEX < 0x03080000 || defined(PYPY_VERSION)
state_dict = reinterpret_borrow<object>(PyEval_GetBuiltins());
#else
# if PY_VERSION_HEX < 0x03090000
PyInterpreterState *istate = _PyInterpreterState_Get();
# else
PyInterpreterState *istate = PyInterpreterState_Get();
# endif
if (istate) {
state_dict = reinterpret_borrow<object>(PyInterpreterState_GetDict(istate));
}
#endif
if (!state_dict) {
raise_from(PyExc_SystemError, "pybind11::detail::get_python_state_dict() FAILED");
}
return state_dict;
}

#if defined(WITH_THREAD)
# if defined(PYBIND11_SIMPLE_GIL_MANAGEMENT)
using gil_scoped_acquire_simple = gil_scoped_acquire;
# else
// Cannot use py::gil_scoped_acquire here since that constructor calls get_internals.
struct gil_scoped_acquire_simple {
gil_scoped_acquire_simple() : state(PyGILState_Ensure()) {}
gil_scoped_acquire_simple(const gil_scoped_acquire_simple &) = delete;
gil_scoped_acquire_simple &operator=(const gil_scoped_acquire_simple &) = delete;
~gil_scoped_acquire_simple() { PyGILState_Release(state); }
const PyGILState_STATE state;
};
# endif
#endif

/* NOTE: struct cross_extension_shared_state is in
namespace pybind11::detail
but all types using this struct are meant to live in
namespace pybind11::cross_extension_shared_states
to make them easy to discover and reason about.
*/
template <typename AdapterType>
struct cross_extension_shared_state {
static constexpr const char *abi_id() { return AdapterType::abi_id(); }

using payload_type = typename AdapterType::payload_type;

static payload_type **&payload_pp() {
// The reason for the double-indirection is documented here:
// https://github.com/pybind/pybind11/pull/1092
static payload_type **pp;
return pp;
}

static payload_type *get_existing() {
if (payload_pp() && *payload_pp()) {
return *payload_pp();
}

gil_scoped_acquire_simple gil;
error_scope err_scope;

str abi_id_str(AdapterType::abi_id());
dict state_dict = get_python_state_dict();
if (!state_dict.contains(abi_id_str)) {
return nullptr;
}

void *raw_ptr = PyCapsule_GetPointer(state_dict[abi_id_str].ptr(), AdapterType::abi_id());
if (raw_ptr == nullptr) {
raise_from(PyExc_SystemError,
("pybind11::detail::cross_extension_shared_state::get_existing():"
" Retrieve payload_type** from capsule FAILED for ABI ID \""
+ std::string(AdapterType::abi_id()) + "\"")
.c_str());
}
payload_pp() = static_cast<payload_type **>(raw_ptr);
return *payload_pp();
}

static payload_type &get() {
payload_type *existing = get_existing();
if (existing != nullptr) {
return *existing;
}
if (payload_pp() == nullptr) {
payload_pp() = new payload_type *();
}
*payload_pp() = new payload_type();
get_python_state_dict()[AdapterType::abi_id()]
= capsule(payload_pp(), AdapterType::abi_id());
return **payload_pp();
}

struct scoped_clear {
// To be called BEFORE Py_Finalize().
scoped_clear() {
payload_type *existing = get_existing();
if (existing != nullptr) {
AdapterType::payload_clear(*existing);
arm_dtor = true;
}
}

// To be called AFTER Py_Finalize().
~scoped_clear() {
if (arm_dtor) {
delete *payload_pp();
*payload_pp() = nullptr;
}
}

scoped_clear(const scoped_clear &) = delete;
scoped_clear &operator=(const scoped_clear &) = delete;

bool arm_dtor = false;
};
};

PYBIND11_NAMESPACE_END(detail)
PYBIND11_NAMESPACE_END(PYBIND11_NAMESPACE)
Loading