@@ -55,7 +55,7 @@ class test_override_cache_helper_trampoline : public test_override_cache_helper
55
55
int func () override { PYBIND11_OVERRIDE (int , test_override_cache_helper, func); }
56
56
};
57
57
58
- PYBIND11_EMBEDDED_MODULE (widget_module, m) {
58
+ PYBIND11_EMBEDDED_MODULE (widget_module, m, py::multiple_interpreters::per_interpreter_gil() ) {
59
59
py::class_<Widget, PyWidget>(m, " Widget" )
60
60
.def (py::init<std::string>())
61
61
.def_property_readonly (" the_message" , &Widget::the_message);
@@ -336,6 +336,7 @@ TEST_CASE("Restart the interpreter") {
336
336
REQUIRE (py_widget.attr (" the_message" ).cast <std::string>() == " Hello after restart" );
337
337
}
338
338
339
+ #if defined(PYBIND11_SUBINTERPRETER_SUPPORT)
339
340
TEST_CASE (" Subinterpreter" ) {
340
341
py::module_::import (" external_module" ); // in the main interpreter
341
342
@@ -347,6 +348,10 @@ TEST_CASE("Subinterpreter") {
347
348
348
349
REQUIRE (m.attr (" add" )(1 , 2 ).cast <int >() == 3 );
349
350
}
351
+
352
+ auto main_int
353
+ = py::module_::import (" external_module" ).attr (" internals_at" )().cast <uintptr_t >();
354
+
350
355
REQUIRE (has_state_dict_internals_obj ());
351
356
REQUIRE (has_pybind11_internals_static ());
352
357
@@ -359,7 +364,6 @@ TEST_CASE("Subinterpreter") {
359
364
// Subinterpreters get their own copy of builtins.
360
365
REQUIRE_FALSE (has_state_dict_internals_obj ());
361
366
362
- #if defined(PYBIND11_SUBINTERPRETER_SUPPORT) && PY_VERSION_HEX >= 0x030C0000
363
367
// internals hasn't been populated yet, but will be different for the subinterpreter
364
368
REQUIRE_FALSE (has_pybind11_internals_static ());
365
369
@@ -369,14 +373,12 @@ TEST_CASE("Subinterpreter") {
369
373
py::detail::get_internals ();
370
374
REQUIRE (has_pybind11_internals_static ());
371
375
REQUIRE (get_details_as_uintptr () == ext_int);
372
- #else
373
- // This static is still defined
374
- REQUIRE (has_pybind11_internals_static ());
375
- #endif
376
+ REQUIRE (main_int != ext_int);
376
377
377
378
// Modules tags should be gone.
378
379
REQUIRE_FALSE (py::hasattr (py::module_::import (" __main__" ), " tag" ));
379
380
{
381
+ REQUIRE_NOTHROW (py::module_::import (" widget_module" ));
380
382
auto m = py::module_::import (" widget_module" );
381
383
REQUIRE_FALSE (py::hasattr (m, " extension_module_tag" ));
382
384
@@ -397,7 +399,6 @@ TEST_CASE("Subinterpreter") {
397
399
REQUIRE (has_state_dict_internals_obj ());
398
400
}
399
401
400
- #if defined(PYBIND11_SUBINTERPRETER_SUPPORT)
401
402
TEST_CASE (" Multiple Subinterpreters" ) {
402
403
// Make sure the module is in the main interpreter and save its pointer
403
404
auto *main_ext = py::module_::import (" external_module" ).ptr ();
@@ -512,10 +513,11 @@ TEST_CASE("Per-Subinterpreter GIL") {
512
513
513
514
// we have switched to the new interpreter and released the main gil
514
515
515
- // widget_module did not provide the mod_per_interpreter_gil tag, so it cannot be imported
516
+ // trampoline_module did not provide the per_interpreter_gil tag, so it cannot be
517
+ // imported
516
518
bool caught = false ;
517
519
try {
518
- py::module_::import (" widget_module " );
520
+ py::module_::import (" trampoline_module " );
519
521
} catch (pybind11::error_already_set &pe) {
520
522
T_REQUIRE (pe.matches (PyExc_ImportError));
521
523
std::string msg (pe.what ());
@@ -525,6 +527,9 @@ TEST_CASE("Per-Subinterpreter GIL") {
525
527
}
526
528
T_REQUIRE (caught);
527
529
530
+ // widget_module did provide the per_interpreter_gil tag, so it this does not throw
531
+ py::module_::import (" widget_module" );
532
+
528
533
T_REQUIRE (!py::hasattr (py::module_::import (" external_module" ), " multi_interp" ));
529
534
py::module_::import (" external_module" ).attr (" multi_interp" ) = std::to_string (num);
530
535
@@ -547,8 +552,8 @@ TEST_CASE("Per-Subinterpreter GIL") {
547
552
548
553
Py_EndInterpreter (sub);
549
554
550
- PyThreadState_Swap (
551
- main_tstate); // switch back so the scoped_acquire can release the GIL properly
555
+ // switch back so the scoped_acquire can release the GIL properly
556
+ PyThreadState_Swap ( main_tstate);
552
557
};
553
558
554
559
std::thread t1 (thread_main, 1 );
@@ -622,12 +627,26 @@ TEST_CASE("Threads") {
622
627
623
628
{
624
629
py::gil_scoped_release gil_release{};
630
+ #if defined(Py_GIL_DISABLED) && PY_VERSION_HEX < 0x030E0000
631
+ std::mutex mutex;
632
+ #endif
625
633
626
634
auto threads = std::vector<std::thread>();
627
635
for (auto i = 0 ; i < num_threads; ++i) {
628
636
threads.emplace_back ([&]() {
629
637
py::gil_scoped_acquire gil{};
638
+ #ifdef Py_GIL_DISABLED
639
+ # if PY_VERSION_HEX < 0x030E0000
640
+ std::lock_guard<std::mutex> lock (mutex);
641
+ locals[" count" ] = locals[" count" ].cast <int >() + 1 ;
642
+ # else
643
+ Py_BEGIN_CRITICAL_SECTION (locals.ptr ());
630
644
locals[" count" ] = locals[" count" ].cast <int >() + 1 ;
645
+ Py_END_CRITICAL_SECTION ();
646
+ # endif
647
+ #else
648
+ locals[" count" ] = locals[" count" ].cast <int >() + 1 ;
649
+ #endif
631
650
});
632
651
}
633
652
0 commit comments