arch-arm, dev-arm: Remove Python 2 compatibility code
[gem5.git] / src / sim / init.cc
index 0cebc417d21af081c37424916d6a5a1d066e5f8d..73d4dbd703e76619abdfc3f0bef1f4cde5e5f4b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012 ARM Limited
+ * Copyright (c) 2012, 2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
  */
 
 #include <Python.h>
 
+#include "sim/init.hh"
+
 #include <marshal.h>
 #include <zlib.h>
 
-#include <csignal>
 #include <iostream>
 #include <list>
 #include <string>
+#include <vector>
 
+#include "base/compiler.hh"
 #include "base/cprintf.hh"
-#include "base/misc.hh"
+#include "base/logging.hh"
 #include "base/types.hh"
 #include "config/have_protobuf.hh"
+#include "python/pybind11/pybind.hh"
 #include "sim/async.hh"
 #include "sim/core.hh"
-#include "sim/init.hh"
 
 #if HAVE_PROTOBUF
 #include <google/protobuf/stubs/common.h>
+
 #endif
 
 using namespace std;
-
-/// Stats signal handler.
-void
-dumpStatsHandler(int sigtype)
-{
-    async_event = true;
-    async_statdump = true;
-}
-
-void
-dumprstStatsHandler(int sigtype)
-{
-    async_event = true;
-    async_statdump = true;
-    async_statreset = true;
-}
-
-/// Exit signal handler.
-void
-exitNowHandler(int sigtype)
-{
-    async_event = true;
-    async_exit = true;
-}
-
-/// Abort signal handler.
-void
-abortHandler(int sigtype)
-{
-    ccprintf(cerr, "Program aborted at cycle %d\n", curTick());
-}
-
-/*
- * M5 can do several special things when various signals are sent.
- * None are mandatory.
- */
-void
-initSignals()
-{
-    // Floating point exceptions may happen on misspeculated paths, so
-    // ignore them
-    signal(SIGFPE, SIG_IGN);
-
-    // We use SIGTRAP sometimes for debugging
-    signal(SIGTRAP, SIG_IGN);
-
-    // Dump intermediate stats
-    signal(SIGUSR1, dumpStatsHandler);
-
-    // Dump intermediate stats and reset them
-    signal(SIGUSR2, dumprstStatsHandler);
-
-    // Exit cleanly on Interrupt (Ctrl-C)
-    signal(SIGINT, exitNowHandler);
-
-    // Print out cycle number on abort
-    signal(SIGABRT, abortHandler);
-}
+namespace py = pybind11;
 
 // The python library is totally messed up with respect to constness,
 // so make a simple macro to make life a little easier
@@ -182,8 +127,7 @@ EmbeddedPython::addModule() const
 }
 
 /*
- * Load and initialize all of the python parts of M5, including Swig
- * and the embedded module importer.
+ * Load and initialize all of the python parts of M5.
  */
 int
 EmbeddedPython::initAll()
@@ -207,42 +151,102 @@ EmbeddedPython::initAll()
     return 0;
 }
 
-EmbeddedSwig::EmbeddedSwig(void (*init_func)())
-    : initFunc(init_func)
+EmbeddedPyBind::EmbeddedPyBind(const char *_name,
+                               void (*init_func)(py::module &),
+                               const char *_base)
+    : initFunc(init_func), registered(false), name(_name), base(_base)
 {
-    getList().push_back(this);
+    getMap()[_name] = this;
 }
 
-list<EmbeddedSwig *> &
-EmbeddedSwig::getList()
+EmbeddedPyBind::EmbeddedPyBind(const char *_name,
+                               void (*init_func)(py::module &))
+    : initFunc(init_func), registered(false), name(_name), base("")
 {
-    static list<EmbeddedSwig *> the_list;
-    return the_list;
+    getMap()[_name] = this;
 }
 
 void
-EmbeddedSwig::initAll()
+EmbeddedPyBind::init(py::module &m)
 {
-    // initialize SWIG modules.  initSwig() is autogenerated and calls
-    // all of the individual swig initialization functions.
-    list<EmbeddedSwig *>::iterator i = getList().begin();
-    list<EmbeddedSwig *>::iterator end = getList().end();
-    for (; i != end; ++i)
-        (*i)->initFunc();
+    if (!registered) {
+        initFunc(m);
+        registered = true;
+    } else {
+        cprintf("Warning: %s already registered.\n", name);
+    }
 }
 
-int
-initM5Python()
+bool
+EmbeddedPyBind::depsReady() const
+{
+    return base.empty() || getMap()[base]->registered;
+}
+
+std::map<std::string, EmbeddedPyBind *> &
+EmbeddedPyBind::getMap()
+{
+    static std::map<std::string, EmbeddedPyBind *> objs;
+    return objs;
+}
+
+#if PY_MAJOR_VERSION >= 3
+PyObject *
+#else
+void
+#endif
+EmbeddedPyBind::initAll()
+{
+    std::list<EmbeddedPyBind *> pending;
+
+    py::module m_m5 = py::module("_m5");
+    m_m5.attr("__package__") = py::cast("_m5");
+
+    pybind_init_core(m_m5);
+    pybind_init_debug(m_m5);
+
+    pybind_init_event(m_m5);
+    pybind_init_stats(m_m5);
+
+    for (auto &kv : getMap()) {
+        auto &obj = kv.second;
+        if (obj->base.empty()) {
+            obj->init(m_m5);
+        } else {
+            pending.push_back(obj);
+        }
+    }
+
+    while (!pending.empty()) {
+        for (auto it = pending.begin(); it != pending.end(); ) {
+            EmbeddedPyBind &obj = **it;
+            if (obj.depsReady()) {
+                obj.init(m_m5);
+                it = pending.erase(it);
+            } else {
+                ++it;
+            }
+        }
+    }
+
+#if PY_MAJOR_VERSION >= 3
+    return m_m5.ptr();
+#endif
+}
+
+void
+registerNativeModules()
 {
-    EmbeddedSwig::initAll();
-    return EmbeddedPython::initAll();
+    auto result = PyImport_AppendInittab("_m5", EmbeddedPyBind::initAll);
+    if (result == -1)
+        panic("Failed to add _m5 to Python's inittab\n");
 }
 
 /*
  * Make the commands array weak so that they can be overridden (used
  * by unit tests to specify a different python main function.
  */
-const char * __attribute__((weak)) m5MainCommands[] = {
+M5_WEAK const char *m5MainCommands[] = {
     "import m5",
     "m5.main()",
     0 // sentinel is required
@@ -253,7 +257,7 @@ const char * __attribute__((weak)) m5MainCommands[] = {
  * main function.
  */
 int
-m5Main(int argc, char **argv)
+m5Main(int argc, char **_argv)
 {
 #if HAVE_PROTOBUF
     // Verify that the version of the protobuf library that we linked
@@ -262,6 +266,23 @@ m5Main(int argc, char **argv)
     GOOGLE_PROTOBUF_VERIFY_VERSION;
 #endif
 
+
+#if PY_MAJOR_VERSION >= 3
+    typedef std::unique_ptr<wchar_t[], decltype(&PyMem_RawFree)> WArgUPtr;
+    std::vector<WArgUPtr> v_argv;
+    std::vector<wchar_t *> vp_argv;
+    v_argv.reserve(argc);
+    vp_argv.reserve(argc);
+    for (int i = 0; i < argc; i++) {
+        v_argv.emplace_back(Py_DecodeLocale(_argv[i], NULL), &PyMem_RawFree);
+        vp_argv.emplace_back(v_argv.back().get());
+    }
+
+    wchar_t **argv = vp_argv.data();
+#else
+    char **argv = _argv;
+#endif
+
     PySys_SetArgv(argc, argv);
 
     // We have to set things up in the special __main__ module
@@ -293,10 +314,3 @@ m5Main(int argc, char **argv)
 
     return 0;
 }
-
-PyMODINIT_FUNC
-initm5(void)
-{
-    initM5Python();
-    PyImport_ImportModule(PyCC("m5"));
-}