diff --git a/src/sim/init.cc b/src/sim/init.cc index d594b08933..1c3d3aa958 100644 --- a/src/sim/init.cc +++ b/src/sim/init.cc @@ -55,76 +55,89 @@ namespace py = pybind11; namespace gem5 { +pybind11::module_ *EmbeddedPyBind::mod = nullptr; + EmbeddedPyBind::EmbeddedPyBind(const char *_name, void (*init_func)(py::module_ &), - const char *_base) - : initFunc(init_func), registered(false), name(_name), base(_base) + const char *_base) : + initFunc(init_func), name(_name), base(_base) { - getMap()[_name] = this; + init(); } EmbeddedPyBind::EmbeddedPyBind(const char *_name, - void (*init_func)(py::module_ &)) - : initFunc(init_func), registered(false), name(_name), base("") + void (*init_func)(py::module_ &)) : + EmbeddedPyBind(_name, init_func, "") +{} + +void +EmbeddedPyBind::init() { - getMap()[_name] = this; + // If this module is already registered, complain and stop. + if (registered) { + cprintf("Warning: %s already registered.\n", name); + return; + } + + auto &ready = getReady(); + auto &pending = getPending(); + + // If we're not ready for this module yet, defer intialization. + if (!mod || (!base.empty() && ready.find(base) == ready.end())) { + pending.insert({std::string(base), this}); + return; + } + + // We must be ready, so set this module up. + initFunc(*mod); + ready[name] = this; + registered = true; + + // Find any other modules that were waiting for this one and init them. + initPending(name); } void -EmbeddedPyBind::init(py::module_ &m) +EmbeddedPyBind::initPending(const std::string &finished) { - if (!registered) { - initFunc(m); - registered = true; - } else { - cprintf("Warning: %s already registered.\n", name); - } -} + auto &pending = getPending(); -bool -EmbeddedPyBind::depsReady() const -{ - return base.empty() || getMap()[base]->registered; + auto range = pending.equal_range(finished); + std::list> todo( + range.first, range.second); + pending.erase(range.first, range.second); + + for (auto &entry: todo) + entry.second->init(); } std::map & -EmbeddedPyBind::getMap() +EmbeddedPyBind::getReady() { - static std::map objs; - return objs; + static std::map ready; + return ready; +} + +std::multimap & +EmbeddedPyBind::getPending() +{ + static std::multimap pending; + return pending; } void EmbeddedPyBind::initAll(py::module_ &_m5) { - std::list pending; - pybind_init_core(_m5); pybind_init_debug(_m5); pybind_init_event(_m5); pybind_init_stats(_m5); - for (auto &kv : EmbeddedPyBind::getMap()) { - auto &obj = kv.second; - if (obj->base.empty()) { - obj->init(_m5); - } else { - pending.push_back(obj); - } - } + mod = &_m5; - while (!pending.empty()) { - for (auto it = pending.begin(); it != pending.end(); ) { - EmbeddedPyBind &obj = **it; - if (obj.depsReady()) { - obj.init(_m5); - it = pending.erase(it); - } else { - ++it; - } - } - } + // Init all the modules that were waiting on the _m5 module itself. + initPending(""); } GEM5_PYBIND_MODULE_INIT(_m5, EmbeddedPyBind::initAll) diff --git a/src/sim/init.hh b/src/sim/init.hh index 9e7158a63e..3b86f82b29 100644 --- a/src/sim/init.hh +++ b/src/sim/init.hh @@ -43,6 +43,7 @@ #include "pybind11/pybind11.h" +#include #include #include @@ -64,14 +65,22 @@ class EmbeddedPyBind private: void (*initFunc)(pybind11::module_ &); - bool depsReady() const; - void init(pybind11::module_ &m); + void init(); - bool registered; + bool registered = false; const std::string name; const std::string base; - static std::map &getMap(); + // The _m5 module. + static pybind11::module_ *mod; + + // A map from initialized module names to their descriptors. + static std::map &getReady(); + // A map to pending modules from the name of what they're waiting on. + static std::multimap &getPending(); + + // Initialize all modules waiting on "finished". + static void initPending(const std::string &finished); }; } // namespace gem5