Skip to content

Commit 4336d12

Browse files
committed
Addressed PR comments
1 parent 68dfe28 commit 4336d12

File tree

4 files changed

+10
-24
lines changed

4 files changed

+10
-24
lines changed

include/pybind11/detail/type_caster_base.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,7 @@ PYBIND11_NOINLINE void all_type_info_populate(PyTypeObject *t, std::vector<type_
175175
* The value is cached for the lifetime of the Python type.
176176
*/
177177
inline const std::vector<detail::type_info *> &all_type_info(PyTypeObject *type) {
178-
auto ins = all_type_info_get_cache(type);
179-
return ins.first->second;
178+
return all_type_info_get_cache(type).first->second;
180179
}
181180

182181
/**

include/pybind11/pybind11.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,9 +2334,9 @@ all_type_info_get_cache(PyTypeObject *type) {
23342334
.emplace(type, std::vector<detail::type_info *>());
23352335
#endif
23362336
if (ins.second) {
2337-
// In free-threading this method should be called
2338-
// under pymutex lock to avoid other threads
2339-
// continue running with empty ins.first->second
2337+
// For free-threading mode, this call must be under
2338+
// the with_internals() mutex lock, to avoid that other threads
2339+
// continue running with the empty ins.first->second.
23402340
all_type_info_populate(type, ins.first->second);
23412341
}
23422342
return ins;

tests/pybind11_tests.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ void ignoreOldStyleInitWarnings(F &&body) {
9797
py::dict(py::arg("body") = py::cpp_function(body)));
9898
}
9999

100+
// See PR #5419 for background.
100101
class TestContext {
101102
public:
102103
TestContext() = delete;

tests/test_class.py

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -513,35 +513,21 @@ def test_pr4220_tripped_over_this():
513513

514514
@pytest.mark.skipif(sys.platform.startswith("emscripten"), reason="Requires threads")
515515
def test_all_type_info_multithreaded():
516-
# Test data race in all_type_info method in free-threading mode.
517-
# For example, we have 2 threads entering `all_type_info`.
518-
# Both enter `all_type_info_get_cache`` function and
519-
# there is a first one which inserts a tuple (type, empty_vector) to the map
520-
# and second is waiting. Inserting thread gets the (iter_to_key, True) and non-inserting thread
521-
# after waiting gets (iter_to_key, False).
522-
# Inserting thread than will add a weakref and will then call into `all_type_info_populate`.
523-
# However, non-inserting thread is not entering `if (ins.second) {` clause and
524-
# returns `ins.first->second;`` which is just empty_vector.
525-
# Finally, non-inserting thread is failing the check in `allocate_layout`:
526-
# if (n_types == 0) {
527-
# pybind11_fail(
528-
# "instance allocation failed: new instance has no pybind11-registered base types");
529-
# }
516+
# See PR #5419 for background.
530517
import threading
531518

532519
from pybind11_tests import TestContext
533520

534521
class Context(TestContext):
535-
def __init__(self, *args, **kwargs):
536-
super().__init__(*args, **kwargs)
522+
pass
537523

538-
num_runs = 4
539-
num_threads = 5
524+
num_runs = 10
525+
num_threads = 4
540526
barrier = threading.Barrier(num_threads)
541527

542528
def func():
543529
barrier.wait()
544-
with Context():
530+
with Context() as ctx:
545531
pass
546532

547533
for _ in range(num_runs):

0 commit comments

Comments
 (0)