-
Notifications
You must be signed in to change notification settings - Fork 2.2k
fix: don't destruct module objects in atexit #5688
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
3906de6
ac8bc82
476fd4b
441db31
c4346e3
8736e1a
3cd05c6
e17afca
dffb2d5
131d7d5
69a6498
753bc5e
93d093c
580480f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1325,6 +1325,45 @@ inline void *multi_interp_slot(F &&, O &&...o) { | |
} | ||
#endif | ||
|
||
/// Must be a POD type, and must hold enough entries for all of the possible slots PLUS ONE for | ||
/// the sentinel (0) end slot. | ||
using slots_array = std::array<PyModuleDef_Slot, 4>; | ||
|
||
/// Initialize an array of slots based on the supplied exec slot and options. | ||
template <typename... Options> | ||
static slots_array init_slots(int (*exec_fn)(PyObject *), Options &&...options) { | ||
size_t next_slot = 0; | ||
slots_array slots; | ||
constexpr size_t term_slot = slots.size() - 1; | ||
|
||
if (exec_fn != nullptr) { | ||
slots[next_slot++] = {Py_mod_exec, reinterpret_cast<void *>(exec_fn)}; | ||
} | ||
|
||
#ifdef Py_mod_multiple_interpreters | ||
if (next_slot >= term_slot) { | ||
pybind11_fail("initialize_multiphase_module_def: not enough space in slots"); | ||
} | ||
slots[next_slot++] = {Py_mod_multiple_interpreters, multi_interp_slot(options...)}; | ||
#endif | ||
|
||
if (gil_not_used_option(options...)) { | ||
#if defined(Py_mod_gil) && defined(Py_GIL_DISABLED) | ||
if (next_slot >= term_slot) { | ||
pybind11_fail("initialize_multiphase_module_def: not enough space in slots"); | ||
} | ||
slots[next_slot++] = {Py_mod_gil, Py_MOD_GIL_NOT_USED}; | ||
#endif | ||
} | ||
|
||
// slots must have a zero end sentinel | ||
if (next_slot > term_slot) { | ||
pybind11_fail("initialize_multiphase_module_def: not enough space in slots"); | ||
} | ||
slots[next_slot++] = {0, nullptr}; | ||
return slots; | ||
} | ||
|
||
PYBIND11_NAMESPACE_END(detail) | ||
|
||
/// Wrapper for Python extension modules | ||
|
@@ -1438,19 +1477,16 @@ class module_ : public object { | |
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */); | ||
} | ||
|
||
using module_def = PyModuleDef; // TODO: Can this be removed (it was needed only for Python 2)? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While this isn't heavily used, it is used, so maybe we should keep it around just a little longer? Especially since we are in the RC phase? Longer term, we have a collection of these defines used for Py2 compatibility, and it would be really nice to list them as deprecated and ideally make using them produce a deprecation warning. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for catching this! I'll put it back, with a deprecation comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done: commit 93d093c I tried using https://chatgpt.com/share/683351d0-14a8-8008-9d31-0fd287dfc198 |
||
|
||
/** \rst | ||
Create a new top-level module that can be used as the main module of a C extension. | ||
|
||
``def`` should point to a statically allocated module_def. | ||
``def`` should point to a statically allocated PyModuleDef. | ||
\endrst */ | ||
static module_ create_extension_module(const char *name, | ||
const char *doc, | ||
module_def *def, | ||
PyModuleDef *def, | ||
mod_gil_not_used gil_not_used | ||
= mod_gil_not_used(false)) { | ||
// module_def is PyModuleDef | ||
// Placement new (not an allocation). | ||
new (def) PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT, | ||
/* m_name */ name, | ||
|
@@ -1478,74 +1514,6 @@ class module_ : public object { | |
// For Python 2, reinterpret_borrow was correct. | ||
return reinterpret_borrow<module_>(m); | ||
} | ||
|
||
/// Must be a POD type, and must hold enough entries for all of the possible slots PLUS ONE for | ||
/// the sentinel (0) end slot. | ||
using slots_array = std::array<PyModuleDef_Slot, 4>; | ||
|
||
/** \rst | ||
Initialize a module def for use with multi-phase module initialization. | ||
|
||
``def`` should point to a statically allocated module_def. | ||
``slots`` must already contain a Py_mod_exec or Py_mod_create slot and will be filled with | ||
additional slots from the supplied options (and the empty sentinel slot). | ||
\endrst */ | ||
template <typename... Options> | ||
static object initialize_multiphase_module_def(const char *name, | ||
const char *doc, | ||
module_def *def, | ||
slots_array &slots, | ||
Options &&...options) { | ||
size_t next_slot = 0; | ||
size_t term_slot = slots.size() - 1; | ||
|
||
// find the end of the supplied slots | ||
while (next_slot < term_slot && slots[next_slot].slot != 0) { | ||
++next_slot; | ||
} | ||
|
||
#ifdef Py_mod_multiple_interpreters | ||
if (next_slot >= term_slot) { | ||
pybind11_fail("initialize_multiphase_module_def: not enough space in slots"); | ||
} | ||
slots[next_slot++] = {Py_mod_multiple_interpreters, detail::multi_interp_slot(options...)}; | ||
#endif | ||
|
||
if (detail::gil_not_used_option(options...)) { | ||
#if defined(Py_mod_gil) && defined(Py_GIL_DISABLED) | ||
if (next_slot >= term_slot) { | ||
pybind11_fail("initialize_multiphase_module_def: not enough space in slots"); | ||
} | ||
slots[next_slot++] = {Py_mod_gil, Py_MOD_GIL_NOT_USED}; | ||
#endif | ||
} | ||
|
||
// slots must have a zero end sentinel | ||
if (next_slot > term_slot) { | ||
pybind11_fail("initialize_multiphase_module_def: not enough space in slots"); | ||
} | ||
slots[next_slot++] = {0, nullptr}; | ||
|
||
// module_def is PyModuleDef | ||
// Placement new (not an allocation). | ||
new (def) PyModuleDef{/* m_base */ PyModuleDef_HEAD_INIT, | ||
/* m_name */ name, | ||
/* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr, | ||
/* m_size */ 0, | ||
/* m_methods */ nullptr, | ||
/* m_slots */ &slots[0], | ||
/* m_traverse */ nullptr, | ||
/* m_clear */ nullptr, | ||
/* m_free */ nullptr}; | ||
auto *m = PyModuleDef_Init(def); | ||
if (m == nullptr) { | ||
if (PyErr_Occurred()) { | ||
throw error_already_set(); | ||
} | ||
pybind11_fail("Internal error in module_::initialize_multiphase_module_def()"); | ||
} | ||
b-pass marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return reinterpret_borrow<object>(m); | ||
b-pass marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}; | ||
|
||
PYBIND11_NAMESPACE_BEGIN(detail) | ||
|
Uh oh!
There was an error while loading. Please reload this page.