Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Fix crashes with recent versions of pybind11.
[simgrid.git] / src / bindings / python / simgrid_python.cpp
index 670be45..78cb91c 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (c) 2018-2020. The SimGrid Team. All rights reserved.          */
+/* Copyright (c) 2018-2021. The SimGrid Team. All rights reserved.          */
 
 /* This program is free software; you can redistribute it and/or modify it
  * under the terms of the license (GNU LGPL) which comes with this package. */
 #pragma GCC diagnostic ignored "-Wunused-value"
 #endif
 
-#include <pybind11/functional.h>
+#ifndef NDEBUG
+/* Many tests are failing after pybind11 commit ad6bf5cd39ca64b4a9bf846b84b11c4c8df1c8e1 "Adding PyGILState_Check() in
+ *  object_api<>::operator(). (#2919)".
+ * See https://github.com/pybind/pybind11/commit/ad6bf5cd39ca64b4a9bf846b84b11c4c8df1c8e1
+ *
+ * The failing tests are mostly those with boost/raw/sysv contexts. As a workaround, define NDEBUG before pybind11
+ * includes.
+ */
+#define NDEBUG
+#define NDEBUG_LOCALLY_DEFINED
+#endif
+
 #include <pybind11/pybind11.h> // Must come before our own stuff
+
+#include <pybind11/functional.h>
 #include <pybind11/stl.h>
 
+#ifdef NDEBUG_LOCALLY_DEFINED
+#undef NDEBUG_LOCALLY_DEFINED
+#undef NDEBUG
+#endif
+
 #if defined(__GNUG__)
 #pragma GCC diagnostic pop
 #endif
@@ -31,6 +49,7 @@
 #include <simgrid/s4u/Mailbox.hpp>
 #include <simgrid/version.h>
 
+#include <algorithm>
 #include <memory>
 #include <string>
 #include <vector>
@@ -46,7 +65,7 @@ XBT_LOG_NEW_DEFAULT_CATEGORY(python, "python");
 
 namespace {
 
-static std::string get_simgrid_version()
+std::string get_simgrid_version()
 {
   int major;
   int minor;
@@ -134,6 +153,7 @@ PYBIND11_MODULE(simgrid, m)
       .def(
           "on_exit",
           [](py::object fun) {
+            fun.inc_ref(); // FIXME: why is this needed for tests like actor-kill and actor-lifetime?
             simgrid::s4u::this_actor::on_exit([fun](bool /*failed*/) {
               GilScopedAcquire py_context; // need a new context for callback
               try {
@@ -150,14 +170,11 @@ PYBIND11_MODULE(simgrid, m)
   /* Class Engine */
   py::class_<Engine>(m, "Engine", "Simulation Engine")
       .def(py::init([](std::vector<std::string> args) {
-        static char noarg[] = {'\0'};
-        int argc            = args.size();
-        std::unique_ptr<char* []> argv(new char*[argc + 1]);
-        for (int i = 0; i != argc; ++i)
-          argv[i] = args[i].empty() ? noarg : &args[i].front();
-        argv[argc] = nullptr;
+        auto argc           = static_cast<int>(args.size());
+        std::vector<char*> argv(args.size() + 1); // argv[argc] is nullptr
+        std::transform(begin(args), end(args), begin(argv), [](std::string& s) { return &s.front(); });
         // Currently this can be dangling, we should wrap this somehow.
-        return new simgrid::s4u::Engine(&argc, argv.get());
+        return new simgrid::s4u::Engine(&argc, argv.data());
       }))
       .def_static("get_clock", &Engine::get_clock,
                   "The simulation time, ie the amount of simulated seconds since the simulation start.")
@@ -177,7 +194,6 @@ PYBIND11_MODULE(simgrid, m)
                   params[i - 1] = py::cast(args[i]);
 
                 py::object res = fun_or_class(*params);
-
                 /* If I was passed a class, I just built an instance, so I need to call it now */
                 if (py::isinstance<py::function>(res))
                   res();
@@ -186,8 +202,7 @@ PYBIND11_MODULE(simgrid, m)
                 py_context.reset();
                 if (ffk) {
                   XBT_VERB("Actor killed");
-                  /* Forward that ForcefulKill exception */
-                  simgrid::ForcefulKillException::do_throw();
+                  simgrid::ForcefulKillException::do_throw(); // Forward that ForcefulKill exception
                 }
                 throw;
               }
@@ -198,7 +213,7 @@ PYBIND11_MODULE(simgrid, m)
   /* Class Host */
   py::class_<simgrid::s4u::Host, std::unique_ptr<Host, py::nodelete>>(m, "Host", "Simulated host")
       .def("by_name", &Host::by_name, "Retrieves a host from its name, or die")
-      .def("get_pstate_count", &Host::get_pstate_count, "Retrieve the cound of defined pstate levels")
+      .def("get_pstate_count", &Host::get_pstate_count, "Retrieve the count of defined pstate levels")
       .def("get_pstate_speed", &Host::get_pstate_speed, "Retrieve the maximal speed at the given pstate")
       .def_property(
           "pstate", &Host::get_pstate,
@@ -252,7 +267,7 @@ PYBIND11_MODULE(simgrid, m)
       .def(
           "get",
           [](Mailbox* self) {
-            py::object data = pybind11::reinterpret_steal<py::object>(static_cast<PyObject*>(self->get()));
+            py::object data = pybind11::reinterpret_steal<py::object>(self->get<PyObject>());
             // data.dec_ref(); // FIXME: why does it break python-actor-create?
             return data;
           },
@@ -270,10 +285,14 @@ PYBIND11_MODULE(simgrid, m)
            "Test whether the communication is terminated.")
       .def("wait", &simgrid::s4u::Comm::wait, py::call_guard<GilScopedRelease>(),
            "Block until the completion of that communication.")
-      .def("wait_all", &simgrid::s4u::Comm::wait_all, py::call_guard<GilScopedRelease>(),
-           "Block until the completion of all communications in the list.")
-      .def("wait_any", &simgrid::s4u::Comm::wait_any, py::call_guard<GilScopedRelease>(),
-           "Block until the completion of any communication in the list and return the index of the terminated one.");
+      // use py::overload_cast for wait_all/wait_any, until the overload marked XBT_ATTRIB_DEPRECATED_v332 is removed
+      .def_static("wait_all",
+                  py::overload_cast<const std::vector<simgrid::s4u::CommPtr>&>(&simgrid::s4u::Comm::wait_all),
+                  py::call_guard<GilScopedRelease>(), "Block until the completion of all communications in the list.")
+      .def_static(
+          "wait_any", py::overload_cast<const std::vector<simgrid::s4u::CommPtr>&>(&simgrid::s4u::Comm::wait_any),
+          py::call_guard<GilScopedRelease>(),
+          "Block until the completion of any communication in the list and return the index of the terminated one.");
 
   /* Class Exec */
   py::class_<simgrid::s4u::Exec, simgrid::s4u::ExecPtr>(m, "Exec", "Execution")
@@ -319,8 +338,7 @@ PYBIND11_MODULE(simgrid, m)
                 py_context.reset();
                 if (ffk) {
                   XBT_VERB("Actor killed");
-                  /* Forward that ForcefulKill exception */
-                  simgrid::ForcefulKillException::do_throw();
+                  simgrid::ForcefulKillException::do_throw(); // Forward that ForcefulKill exception
                 }
                 throw;
               }
@@ -345,7 +363,7 @@ PYBIND11_MODULE(simgrid, m)
       .def("is_daemon", &Actor::is_daemon,
            "Returns True if that actor is a daemon and will be terminated automatically when the last non-daemon actor "
            "terminates.")
-      .def("join", py::overload_cast<double>(&Actor::join), py::call_guard<GilScopedRelease>(),
+      .def("join", py::overload_cast<double>(&Actor::join, py::const_), py::call_guard<GilScopedRelease>(),
            "Wait for the actor to finish (more info in the C++ documentation).", py::arg("timeout"))
       .def("kill", &Actor::kill, py::call_guard<GilScopedRelease>(), "Kill that actor")
       .def("kill_all", &Actor::kill_all, py::call_guard<GilScopedRelease>(), "Kill all actors but the caller.")