@@ -1242,6 +1242,71 @@ class mod_gil_not_used {
12421242 bool flag_;
12431243};
12441244
1245+ // Use to activate Py_MOD_PER_INTERPRETER_GIL_SUPPORTED
1246+ class mod_per_interpreter_gil {
1247+ public:
1248+ explicit mod_per_interpreter_gil (bool flag = true ) : flag_(flag) {}
1249+ bool flag () const { return flag_; }
1250+
1251+ private:
1252+ bool flag_;
1253+ };
1254+
1255+ // Use to activate Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED
1256+ class mod_multi_interpreter_one_gil {
1257+ public:
1258+ explicit mod_multi_interpreter_one_gil (bool flag = true ) : flag_(flag) {}
1259+ bool flag () const { return flag_; }
1260+
1261+ private:
1262+ bool flag_;
1263+ };
1264+
1265+ PYBIND11_NAMESPACE_BEGIN (detail)
1266+
1267+ inline bool gil_not_used_option () { return false ; }
1268+ template <typename F, typename ... O>
1269+ bool gil_not_used_option (F &&, O &&...o );
1270+ template <typename ... O>
1271+ inline bool gil_not_used_option (mod_gil_not_used f, O &&...o ) {
1272+ return f.flag () || gil_not_used_option (o...);
1273+ }
1274+ template <typename F, typename ... O>
1275+ inline bool gil_not_used_option (F &&, O &&...o ) {
1276+ return false || gil_not_used_option (o...);
1277+ }
1278+
1279+ #ifdef Py_mod_multiple_interpreters
1280+ inline void *multi_interp_option () { return Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED; }
1281+ # ifdef PYBIND11_SUBINTERPRETER_SUPPORT
1282+ template <typename F, typename ... O>
1283+ void *multi_interp_option (F &&, O &&...o );
1284+ template <typename ... O>
1285+ void *multi_interp_option (mod_multi_interpreter_one_gil f, O &&...o );
1286+ template <typename ... O>
1287+ inline void *multi_interp_option (mod_per_interpreter_gil f, O &&...o ) {
1288+ if (f.flag ()) {
1289+ return Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
1290+ }
1291+ return multi_interp_option (o...);
1292+ }
1293+ template <typename ... O>
1294+ inline void *multi_interp_option (mod_multi_interpreter_one_gil f, O &&...o ) {
1295+ void *others = multi_interp_option (o...);
1296+ if (!f.flag () || others == Py_MOD_PER_INTERPRETER_GIL_SUPPORTED) {
1297+ return others;
1298+ }
1299+ return Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED;
1300+ }
1301+ # endif
1302+ template <typename F, typename ... O>
1303+ inline void *multi_interp_option (F &&, O &&...o ) {
1304+ return multi_interp_option (o...);
1305+ }
1306+ #endif
1307+
1308+ PYBIND11_NAMESPACE_END (detail)
1309+
12451310// / Wrapper for Python extension modules
12461311class module_ : public object {
12471312public:
@@ -1376,6 +1441,75 @@ class module_ : public object {
13761441 // For Python 2, reinterpret_borrow was correct.
13771442 return reinterpret_borrow<module_>(m);
13781443 }
1444+
1445+ /* * \rst
1446+ Initialized a module def for use with multi-phase module initialization.
1447+
1448+ ``def`` should point to a statically allocated module_def.
1449+ ``slots`` must point to an initialized array of slots with space for at
1450+ least two additional slots to be populated based on the options.
1451+ \endrst */
1452+ template <typename ... Options>
1453+ static object init_module_def (const char *name,
1454+ const char *doc,
1455+ module_def *def,
1456+ PyModuleDef_Slot *slots,
1457+ Options &&...options) {
1458+ int i = 0 ;
1459+ while (slots[i].slot != 0 ) {
1460+ ++i;
1461+ }
1462+
1463+ bool nogil PYBIND11_MAYBE_UNUSED = detail::gil_not_used_option (options...);
1464+
1465+ #ifdef Py_mod_multiple_interpreters
1466+ slots[i].slot = Py_mod_multiple_interpreters;
1467+ slots[i].value = detail::multi_interp_option (options...);
1468+ if (nogil && slots[i].value == Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED) {
1469+ // if you support free threading and multi-interpreters,
1470+ // then you definitely also support per-interpreter GIL
1471+ // even if you don't know it.
1472+ slots[i].value = Py_MOD_PER_INTERPRETER_GIL_SUPPORTED;
1473+ }
1474+ ++i;
1475+ #endif
1476+
1477+ if (nogil) {
1478+ #ifdef Py_mod_gil
1479+ slots[i].slot = Py_mod_gil;
1480+ # ifdef Py_GIL_DISABLED
1481+ slots[i].value = Py_MOD_GIL_NOT_USED;
1482+ # else
1483+ slots[i].value = Py_MOD_GIL_USED;
1484+ # endif
1485+ ++i;
1486+ #endif
1487+ }
1488+
1489+ slots[i].slot = 0 ;
1490+ slots[i].value = nullptr ;
1491+
1492+ // module_def is PyModuleDef
1493+ // Placement new (not an allocation).
1494+ def = new (def)
1495+ PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT,
1496+ /* m_name */ name,
1497+ /* m_doc */ options::show_user_defined_docstrings () ? doc : nullptr ,
1498+ /* m_size */ 0 ,
1499+ /* m_methods */ nullptr ,
1500+ /* m_slots */ slots,
1501+ /* m_traverse */ nullptr ,
1502+ /* m_clear */ nullptr ,
1503+ /* m_free */ nullptr };
1504+ auto *m = PyModuleDef_Init (def);
1505+ if (m == nullptr ) {
1506+ if (PyErr_Occurred ()) {
1507+ throw error_already_set ();
1508+ }
1509+ pybind11_fail (" Internal error in module_::init_module_def()" );
1510+ }
1511+ return reinterpret_borrow<object>(m);
1512+ }
13791513};
13801514
13811515PYBIND11_NAMESPACE_BEGIN (detail)
0 commit comments