mirror of
https://github.com/pybind/pybind11.git
synced 2025-01-31 07:10:30 +00:00
Merge branch 'master' into sh_merge_master
This commit is contained in:
commit
dbd79474b4
@ -25,14 +25,14 @@ repos:
|
|||||||
|
|
||||||
# Clang format the codebase automatically
|
# Clang format the codebase automatically
|
||||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||||
rev: "v19.1.4"
|
rev: "v19.1.6"
|
||||||
hooks:
|
hooks:
|
||||||
- id: clang-format
|
- id: clang-format
|
||||||
types_or: [c++, c, cuda]
|
types_or: [c++, c, cuda]
|
||||||
|
|
||||||
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
# Ruff, the Python auto-correcting linter/formatter written in Rust
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: v0.8.1
|
rev: v0.8.6
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
args: ["--fix", "--show-fixes"]
|
args: ["--fix", "--show-fixes"]
|
||||||
@ -40,7 +40,7 @@ repos:
|
|||||||
|
|
||||||
# Check static types with mypy
|
# Check static types with mypy
|
||||||
- repo: https://github.com/pre-commit/mirrors-mypy
|
- repo: https://github.com/pre-commit/mirrors-mypy
|
||||||
rev: "v1.13.0"
|
rev: "v1.14.1"
|
||||||
hooks:
|
hooks:
|
||||||
- id: mypy
|
- id: mypy
|
||||||
args: []
|
args: []
|
||||||
@ -144,7 +144,7 @@ repos:
|
|||||||
|
|
||||||
# PyLint has native support - not always usable, but works for us
|
# PyLint has native support - not always usable, but works for us
|
||||||
- repo: https://github.com/PyCQA/pylint
|
- repo: https://github.com/PyCQA/pylint
|
||||||
rev: "v3.3.2"
|
rev: "v3.3.3"
|
||||||
hooks:
|
hooks:
|
||||||
- id: pylint
|
- id: pylint
|
||||||
files: ^pybind11
|
files: ^pybind11
|
||||||
|
@ -130,9 +130,9 @@ imagesize==1.4.1 \
|
|||||||
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
|
--hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \
|
||||||
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
|
--hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a
|
||||||
# via sphinx
|
# via sphinx
|
||||||
jinja2==3.1.4 \
|
jinja2==3.1.5 \
|
||||||
--hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
|
--hash=sha256:8fefff8dc3034e27bb80d67c671eb8a9bc424c0ef4c0826edbff304cceff43bb \
|
||||||
--hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
|
--hash=sha256:aba0f4dc9ed8013c424088f68a5c226f7d6097ed89b246d7749c2ec4175c6adb
|
||||||
# via sphinx
|
# via sphinx
|
||||||
markupsafe==2.1.5 \
|
markupsafe==2.1.5 \
|
||||||
--hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \
|
--hash=sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf \
|
||||||
|
@ -312,7 +312,31 @@ inline void traverse_offset_bases(void *valueptr,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
inline void enable_try_inc_ref(PyObject *obj) {
|
||||||
|
// TODO: Replace with PyUnstable_Object_EnableTryIncRef when available.
|
||||||
|
// See https://github.com/python/cpython/issues/128844
|
||||||
|
if (_Py_IsImmortal(obj)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared);
|
||||||
|
if ((shared & _Py_REF_SHARED_FLAG_MASK) != 0) {
|
||||||
|
// Nothing to do if it's in WEAKREFS, QUEUED, or MERGED states.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_Py_atomic_compare_exchange_ssize(
|
||||||
|
&obj->ob_ref_shared, &shared, shared | _Py_REF_MAYBE_WEAKREF)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
inline bool register_instance_impl(void *ptr, instance *self) {
|
inline bool register_instance_impl(void *ptr, instance *self) {
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
enable_try_inc_ref(reinterpret_cast<PyObject *>(self));
|
||||||
|
#endif
|
||||||
with_instance_map(ptr, [&](instance_map &instances) { instances.emplace(ptr, self); });
|
with_instance_map(ptr, [&](instance_map &instances) { instances.emplace(ptr, self); });
|
||||||
return true; // unused, but gives the same signature as the deregister func
|
return true; // unused, but gives the same signature as the deregister func
|
||||||
}
|
}
|
||||||
|
@ -245,6 +245,49 @@ PYBIND11_NOINLINE handle get_type_handle(const std::type_info &tp, bool throw_if
|
|||||||
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
|
return handle(type_info ? ((PyObject *) type_info->type) : nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool try_incref(PyObject *obj) {
|
||||||
|
// Tries to increment the reference count of an object if it's not zero.
|
||||||
|
// TODO: Use PyUnstable_TryIncref when available.
|
||||||
|
// See https://github.com/python/cpython/issues/128844
|
||||||
|
#ifdef Py_GIL_DISABLED
|
||||||
|
// See
|
||||||
|
// https://github.com/python/cpython/blob/d05140f9f77d7dfc753dd1e5ac3a5962aaa03eff/Include/internal/pycore_object.h#L761
|
||||||
|
uint32_t local = _Py_atomic_load_uint32_relaxed(&obj->ob_ref_local);
|
||||||
|
local += 1;
|
||||||
|
if (local == 0) {
|
||||||
|
// immortal
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (_Py_IsOwnedByCurrentThread(obj)) {
|
||||||
|
_Py_atomic_store_uint32_relaxed(&obj->ob_ref_local, local);
|
||||||
|
# ifdef Py_REF_DEBUG
|
||||||
|
_Py_INCREF_IncRefTotal();
|
||||||
|
# endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared);
|
||||||
|
for (;;) {
|
||||||
|
// If the shared refcount is zero and the object is either merged
|
||||||
|
// or may not have weak references, then we cannot incref it.
|
||||||
|
if (shared == 0 || shared == _Py_REF_MERGED) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_Py_atomic_compare_exchange_ssize(
|
||||||
|
&obj->ob_ref_shared, &shared, shared + (1 << _Py_REF_SHARED_SHIFT))) {
|
||||||
|
# ifdef Py_REF_DEBUG
|
||||||
|
_Py_INCREF_IncRefTotal();
|
||||||
|
# endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
assert(Py_REFCNT(obj) > 0);
|
||||||
|
Py_INCREF(obj);
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Searches the inheritance graph for a registered Python instance, using all_type_info().
|
// Searches the inheritance graph for a registered Python instance, using all_type_info().
|
||||||
PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
||||||
const detail::type_info *tinfo) {
|
const detail::type_info *tinfo) {
|
||||||
@ -253,7 +296,10 @@ PYBIND11_NOINLINE handle find_registered_python_instance(void *src,
|
|||||||
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
for (auto it_i = it_instances.first; it_i != it_instances.second; ++it_i) {
|
||||||
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
|
for (auto *instance_type : detail::all_type_info(Py_TYPE(it_i->second))) {
|
||||||
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
|
if (instance_type && same_type(*instance_type->cpptype, *tinfo->cpptype)) {
|
||||||
return handle((PyObject *) it_i->second).inc_ref();
|
auto *wrapper = reinterpret_cast<PyObject *>(it_i->second);
|
||||||
|
if (try_incref(wrapper)) {
|
||||||
|
return handle(wrapper);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,9 @@ struct IntStruct {
|
|||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct EmptyStruct {};
|
||||||
|
EmptyStruct SharedInstance;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
TEST_SUBMODULE(thread, m) {
|
TEST_SUBMODULE(thread, m) {
|
||||||
@ -61,6 +64,9 @@ TEST_SUBMODULE(thread, m) {
|
|||||||
},
|
},
|
||||||
py::call_guard<py::gil_scoped_release>());
|
py::call_guard<py::gil_scoped_release>());
|
||||||
|
|
||||||
|
py::class_<EmptyStruct>(m, "EmptyStruct")
|
||||||
|
.def_readonly_static("SharedInstance", &SharedInstance);
|
||||||
|
|
||||||
// NOTE: std::string_view also uses loader_life_support to ensure that
|
// NOTE: std::string_view also uses loader_life_support to ensure that
|
||||||
// the string contents remain alive, but that's a C++ 17 feature.
|
// the string contents remain alive, but that's a C++ 17 feature.
|
||||||
}
|
}
|
||||||
|
@ -47,3 +47,22 @@ def test_implicit_conversion_no_gil():
|
|||||||
x.start()
|
x.start()
|
||||||
for x in [c, b, a]:
|
for x in [c, b, a]:
|
||||||
x.join()
|
x.join()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
|
||||||
|
def test_bind_shared_instance():
|
||||||
|
nb_threads = 4
|
||||||
|
b = threading.Barrier(nb_threads)
|
||||||
|
|
||||||
|
def access_shared_instance():
|
||||||
|
b.wait()
|
||||||
|
for _ in range(1000):
|
||||||
|
m.EmptyStruct.SharedInstance # noqa: B018
|
||||||
|
|
||||||
|
threads = [
|
||||||
|
threading.Thread(target=access_shared_instance) for _ in range(nb_threads)
|
||||||
|
]
|
||||||
|
for thread in threads:
|
||||||
|
thread.start()
|
||||||
|
for thread in threads:
|
||||||
|
thread.join()
|
||||||
|
Loading…
Reference in New Issue
Block a user