Skip to content

Commit 0b74dd3

Browse files
committed
Add test_multi_acquire_release_cross_module, while also forcing unique PYBIND11_INTERNALS_VERSION for cross_module_gil_utils.cpp
1 parent b71b9f0 commit 0b74dd3

File tree

3 files changed

+66
-22
lines changed

3 files changed

+66
-22
lines changed

tests/cross_module_gil_utils.cpp

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66
All rights reserved. Use of this source code is governed by a
77
BSD-style license that can be found in the LICENSE file.
88
*/
9+
#if defined(PYBIND11_INTERNALS_VERSION)
10+
# undef PYBIND11_INTERNALS_VERSION
11+
#endif
12+
#define PYBIND11_INTERNALS_VERSION 21814642 // Ensure this module has its own `internals` instance.
913
#include <pybind11/pybind11.h>
1014

1115
#include <cstdint>
16+
#include <string>
1217
#include <thread>
1318

1419
// This file mimics a DSO that makes pybind11 calls but does not define a
@@ -22,9 +27,24 @@
2227
namespace {
2328

2429
namespace py = pybind11;
30+
2531
void gil_acquire() { py::gil_scoped_acquire gil; }
2632

27-
constexpr char kModuleName[] = "cross_module_gil_utils";
33+
std::string gil_multi_acquire_release(unsigned bits) {
34+
if (bits & 0x1u) {
35+
py::gil_scoped_acquire gil;
36+
}
37+
if (bits & 0x2u) {
38+
py::gil_scoped_release gil;
39+
}
40+
if (bits & 0x4u) {
41+
py::gil_scoped_acquire gil;
42+
}
43+
if (bits & 0x8u) {
44+
py::gil_scoped_release gil;
45+
}
46+
return PYBIND11_INTERNALS_ID;
47+
}
2848

2949
struct CustomAutoGIL {
3050
CustomAutoGIL() : gstate(PyGILState_Ensure()) {}
@@ -55,6 +75,8 @@ void gil_acquire_nested() {
5575
thread.join();
5676
}
5777

78+
constexpr char kModuleName[] = "cross_module_gil_utils";
79+
5880
struct PyModuleDef moduledef = {
5981
PyModuleDef_HEAD_INIT, kModuleName, nullptr, 0, nullptr, nullptr, nullptr, nullptr, nullptr};
6082

@@ -71,6 +93,7 @@ extern "C" PYBIND11_EXPORT PyObject *PyInit_cross_module_gil_utils() {
7193
static_assert(sizeof(&gil_acquire) == sizeof(void *),
7294
"Function pointer must have the same size as void*");
7395
ADD_FUNCTION("gil_acquire_funcaddr", gil_acquire)
96+
ADD_FUNCTION("gil_multi_acquire_release_funcaddr", gil_multi_acquire_release)
7497
ADD_FUNCTION("gil_acquire_inner_custom_funcaddr",
7598
gil_acquire_inner<CustomAutoGIL, CustomAutoNoGIL>)
7699
ADD_FUNCTION("gil_acquire_nested_custom_funcaddr",

tests/test_gil_scoped.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
#include "pybind11_tests.h"
1313

14+
#include <string>
15+
#include <thread>
16+
1417
#define CROSS_MODULE(Function) \
1518
auto cm = py::module_::import("cross_module_gil_utils"); \
1619
auto target = reinterpret_cast<void (*)()>(PyLong_AsVoidPtr(cm.attr(Function).ptr()));
@@ -102,4 +105,30 @@ TEST_SUBMODULE(gil_scoped, m) {
102105
py::gil_scoped_acquire gil_acquired_inner;
103106
return py::str(obj);
104107
});
108+
m.def("test_multi_acquire_release_cross_module", [](unsigned bits) {
109+
py::set internals_ids;
110+
internals_ids.add(PYBIND11_INTERNALS_ID);
111+
{
112+
py::gil_scoped_release gil_released;
113+
auto thread_f = [bits, &internals_ids]() {
114+
py::gil_scoped_acquire gil_acquired;
115+
auto cm = py::module_::import("cross_module_gil_utils");
116+
auto target = reinterpret_cast<std::string (*)(unsigned)>(
117+
PyLong_AsVoidPtr(cm.attr("gil_multi_acquire_release_funcaddr").ptr()));
118+
std::string cm_internals_id = target(bits >> 3);
119+
internals_ids.add(cm_internals_id);
120+
};
121+
if (bits & 0x1u) {
122+
thread_f();
123+
}
124+
if (bits & 0x2u) {
125+
std::thread non_python_thread(std::move(thread_f));
126+
non_python_thread.join();
127+
}
128+
if (bits & 0x4u) {
129+
thread_f();
130+
}
131+
}
132+
return internals_ids;
133+
});
105134
}

tests/test_gil_scoped.py

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
1-
import builtins
21
import multiprocessing
32
import threading
43

5-
import pytest
6-
74
from pybind11_tests import gil_scoped as m
85

96

10-
def get_pybind11_internals_keys():
11-
keys = []
12-
for key in dir(builtins):
13-
if key.startswith("__pybind11_internals_"):
14-
assert key.endswith("__")
15-
keys.append(key)
16-
return tuple(sorted(keys))
17-
18-
197
def _run_in_process(target, *args, **kwargs):
208
"""Runs target in process and returns its exitcode after 10s (None if still alive)."""
219
process = multiprocessing.Process(target=target, args=args, kwargs=kwargs)
@@ -45,6 +33,7 @@ def pure_virtual_func(self):
4533
m.test_callback_std_func(lambda: None)
4634
m.test_callback_virtual_func(extended)
4735
m.test_callback_pure_virtual_func(extended)
36+
4837
m.test_cross_module_gil_released()
4938
m.test_cross_module_gil_acquired()
5039
m.test_cross_module_gil_inner_custom_released()
@@ -54,10 +43,15 @@ def pure_virtual_func(self):
5443
m.test_cross_module_gil_nested_custom_released()
5544
m.test_cross_module_gil_nested_custom_acquired()
5645
m.test_cross_module_gil_nested_pybind11_released()
57-
# m.test_cross_module_gil_nested_pybind11_acquire() # this one dies in test_python_to_cpp_to_python_from_process
46+
m.test_cross_module_gil_nested_pybind11_acquired()
47+
5848
assert m.test_release_acquire(0xAB) == "171"
5949
assert m.test_nested_acquire(0xAB) == "171"
6050

51+
for bits in range(16 * 8):
52+
internals_ids = m.test_multi_acquire_release_cross_module(bits)
53+
assert len(internals_ids) == 2 if bits % 8 else 1
54+
6155

6256
def _python_to_cpp_to_python_from_threads(num_threads, parallel=False):
6357
"""Calls different C++ functions that come back to Python, from Python threads."""
@@ -122,14 +116,6 @@ def test_cross_module_gil_acquired():
122116
m.test_cross_module_gil_acquired() # Should not raise a SIGSEGV
123117

124118

125-
def test_report_builtins_internals_keys():
126-
"""For reporting, not an actual test."""
127-
m.test_cross_module_gil_released() # Any test that imports cross_module_gil_utils
128-
keys = get_pybind11_internals_keys()
129-
assert len(keys) != 0
130-
pytest.skip("builtins internals keys: %s" % ", ".join(keys))
131-
132-
133119
def test_cross_module_gil_inner_custom_released():
134120
"""Makes sure that the GIL can be acquired/released by another module
135121
from a GIL-released state using custom locking logic."""
@@ -184,3 +170,9 @@ def test_release_acquire():
184170

185171
def test_nested_acquire():
186172
assert m.test_nested_acquire(0xAB) == "171"
173+
174+
175+
def test_multi_acquire_release_cross_module():
176+
for bits in range(16 * 8):
177+
internals_ids = m.test_multi_acquire_release_cross_module(bits)
178+
assert len(internals_ids) == 2 if bits % 8 else 1

0 commit comments

Comments
 (0)