Skip to content

Commit b4c0a19

Browse files
committed
Merge branch 'multiphase-init' into subinterpreters
2 parents 5425990 + 422b08f commit b4c0a19

File tree

2 files changed

+50
-42
lines changed

2 files changed

+50
-42
lines changed

include/pybind11/detail/common.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -454,22 +454,22 @@ PYBIND11_WARNING_PUSH
454454
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
455455
#define PYBIND11_MODULE(name, variable, ...) \
456456
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
457-
static PyModuleDef_Slot PYBIND11_CONCAT(pybind11_module_slots_, name)[5]; \
457+
static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \
458458
static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \
459459
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
460460
PYBIND11_PLUGIN_IMPL(name) { \
461461
PYBIND11_CHECK_PYTHON_VERSION \
462462
PYBIND11_ENSURE_INTERNALS_READY \
463-
PYBIND11_CONCAT(pybind11_module_slots_, name)[0].slot = Py_mod_exec; \
464-
PYBIND11_CONCAT(pybind11_module_slots_, name) \
465-
[0].value = reinterpret_cast<void *>(&PYBIND11_CONCAT(pybind11_exec_, name)); \
466-
PYBIND11_CONCAT(pybind11_module_slots_, name)[1] = {0, nullptr}; \
467-
auto m \
468-
= ::pybind11::module_::init_module_def(PYBIND11_TOSTRING(name), \
469-
nullptr, \
470-
&PYBIND11_CONCAT(pybind11_module_def_, name), \
471-
PYBIND11_CONCAT(pybind11_module_slots_, name), \
472-
##__VA_ARGS__); \
463+
auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \
464+
slots[0] \
465+
= {Py_mod_exec, reinterpret_cast<void *>(&PYBIND11_CONCAT(pybind11_exec_, name))}; \
466+
slots[1] = {0, nullptr}; \
467+
auto m = ::pybind11::module_::initialize_multiphase_module_def( \
468+
PYBIND11_TOSTRING(name), \
469+
nullptr, \
470+
&PYBIND11_CONCAT(pybind11_module_def_, name), \
471+
slots, \
472+
##__VA_ARGS__); \
473473
return m.ptr(); \
474474
} \
475475
int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject * pm) { \

include/pybind11/pybind11.h

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,7 +1286,7 @@ inline bool gil_not_used_option(mod_gil_not_used f, O &&...o) {
12861286
}
12871287
template <typename F, typename... O>
12881288
inline bool gil_not_used_option(F &&, O &&...o) {
1289-
return false || gil_not_used_option(o...);
1289+
return gil_not_used_option(o...);
12901290
}
12911291

12921292
#ifdef Py_mod_multiple_interpreters
@@ -1453,52 +1453,60 @@ class module_ : public object {
14531453
return reinterpret_borrow<module_>(m);
14541454
}
14551455

1456+
/// Must be a POD type, and must hold enough entries for all of the possible slots PLUS ONE for
1457+
/// the sentinel (0) end slot.
1458+
using slots_array = std::array<PyModuleDef_Slot, 5>;
1459+
14561460
/** \rst
14571461
Initialized a module def for use with multi-phase module initialization.
14581462
14591463
``def`` should point to a statically allocated module_def.
1460-
``slots`` must point to an initialized array of slots with space for at
1461-
least two additional slots to be populated based on the options.
1464+
``slots`` must already contain a Py_mod_exec or Py_mod_create slot and will be filled with
1465+
additional slots from the supplied options (and the empty sentinel slot).
14621466
\endrst */
14631467
template <typename... Options>
1464-
static object init_module_def(const char *name,
1465-
const char *doc,
1466-
module_def *def,
1467-
PyModuleDef_Slot *slots,
1468-
Options &&...options) {
1469-
int i = 0;
1470-
while (slots[i].slot != 0) {
1471-
++i;
1468+
static object initialize_multiphase_module_def(const char *name,
1469+
const char *doc,
1470+
module_def *def,
1471+
slots_array &slots,
1472+
Options &&...options) {
1473+
size_t next_slot = 0;
1474+
size_t term_slot = slots.size() - 1;
1475+
1476+
// find the end of the supplied slots
1477+
while (next_slot < term_slot && slots[next_slot].slot != 0) {
1478+
++next_slot;
14721479
}
14731480

14741481
bool nogil PYBIND11_MAYBE_UNUSED = detail::gil_not_used_option(options...);
1482+
if (nogil) {
1483+
#if defined(Py_mod_gil) && defined(Py_GIL_DISABLED)
1484+
if (next_slot >= term_slot) {
1485+
pybind11_fail("initialize_multiphase_module_def: not enough space in slots");
1486+
}
1487+
slots[next_slot++] = {Py_mod_gil, Py_MOD_GIL_NOT_USED};
1488+
#endif
1489+
}
14751490

14761491
#ifdef Py_mod_multiple_interpreters
1477-
slots[i].slot = Py_mod_multiple_interpreters;
1478-
slots[i].value = detail::multi_interp_option(options...);
1479-
if (nogil && slots[i].value == Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED) {
1492+
auto mi_opt = detail::multi_interp_option(options...);
1493+
if (nogil && mi_opt == Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED) {
14801494
// if you support free threading and multi-interpreters,
14811495
// then you definitely also support per-interpreter GIL
14821496
// even if you don't know it.
1483-
slots[i].value = Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
1497+
mi_opt = Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
14841498
}
1485-
++i;
1499+
if (next_slot >= term_slot) {
1500+
pybind11_fail("initialize_multiphase_module_def: not enough space in slots");
1501+
}
1502+
slots[next_slot++] = {Py_mod_multiple_interpreters, mi_opt};
14861503
#endif
14871504

1488-
if (nogil) {
1489-
#ifdef Py_mod_gil
1490-
slots[i].slot = Py_mod_gil;
1491-
# ifdef Py_GIL_DISABLED
1492-
slots[i].value = Py_MOD_GIL_NOT_USED;
1493-
# else
1494-
slots[i].value = Py_MOD_GIL_USED;
1495-
# endif
1496-
++i;
1497-
#endif
1505+
// slots must have a zero end sentinel
1506+
if (next_slot > term_slot) {
1507+
pybind11_fail("initialize_multiphase_module_def: not enough space in slots");
14981508
}
1499-
1500-
slots[i].slot = 0;
1501-
slots[i].value = nullptr;
1509+
slots[next_slot++] = {0, nullptr};
15021510

15031511
// module_def is PyModuleDef
15041512
// Placement new (not an allocation).
@@ -1508,7 +1516,7 @@ class module_ : public object {
15081516
/* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr,
15091517
/* m_size */ 0,
15101518
/* m_methods */ nullptr,
1511-
/* m_slots */ slots,
1519+
/* m_slots */ &slots[0],
15121520
/* m_traverse */ nullptr,
15131521
/* m_clear */ nullptr,
15141522
/* m_free */ nullptr};
@@ -1517,7 +1525,7 @@ class module_ : public object {
15171525
if (PyErr_Occurred()) {
15181526
throw error_already_set();
15191527
}
1520-
pybind11_fail("Internal error in module_::init_module_def()");
1528+
pybind11_fail("Internal error in module_::initialize_multiphase_module_def()");
15211529
}
15221530
return reinterpret_borrow<object>(m);
15231531
}

0 commit comments

Comments
 (0)