Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
include cleanups (platf_private.hpp, surf_private.hpp and platf.hpp)
[simgrid.git] / src / kernel / EngineImpl.cpp
index 5832916..bcb3562 100644 (file)
 /* 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. */
 
-#include "src/kernel/EngineImpl.hpp"
+#include <simgrid/Exception.hpp>
+#include <simgrid/kernel/Timer.hpp>
+#include <simgrid/kernel/routing/NetPoint.hpp>
+#include <simgrid/kernel/routing/NetZoneImpl.hpp>
+#include <simgrid/s4u/Host.hpp>
+#include <simgrid/sg_config.hpp>
+
 #include "mc/mc.h"
-#include "simgrid/Exception.hpp"
-#include "simgrid/kernel/Timer.hpp"
-#include "simgrid/kernel/routing/NetPoint.hpp"
-#include "simgrid/kernel/routing/NetZoneImpl.hpp"
-#include "simgrid/s4u/Host.hpp"
-#include "simgrid/sg_config.hpp"
-#include "src/include/surf/surf.hpp" //get_clock() and surf_solve()
-#include "src/kernel/resource/DiskImpl.hpp"
+#include "src/kernel/EngineImpl.hpp"
+#include "src/kernel/resource/profile/Profile.hpp"
 #include "src/mc/mc_record.hpp"
 #include "src/mc/mc_replay.hpp"
-#include "src/simix/smx_private.hpp"
 #include "src/smpi/include/smpi_actor.hpp"
 #include "src/surf/network_interface.hpp"
-#include "src/surf/xml/platf.hpp" // FIXME: KILLME. There must be a better way than mimicking XML here
+#include "src/surf/xml/platf.hpp"
+#include "surf/surf.hpp"          //surf_presolve() and surf_solve()
+#include "xbt/xbt_modinter.h"     /* whether initialization was already done */
 
 #include <boost/algorithm/string/predicate.hpp>
 #ifndef _WIN32
 #include <dlfcn.h>
 #endif /* _WIN32 */
 
-XBT_LOG_NEW_DEFAULT_CATEGORY(ker_engine, "Logging specific to Engine (kernel)");
+#if SIMGRID_HAVE_MC
+#include "src/mc/remote/AppSide.hpp"
+#endif
 
+XBT_LOG_NEW_DEFAULT_CATEGORY(ker_engine, "Logging specific to Engine (kernel)");
 namespace simgrid {
 namespace kernel {
+EngineImpl* EngineImpl::instance_ = nullptr; /* That singleton is awful too. */
 
 config::Flag<double> cfg_breakpoint{"debug/breakpoint",
                                     "When non-negative, raise a SIGTRAP after given (simulated) time", -1.0};
-EngineImpl::~EngineImpl()
+config::Flag<bool> cfg_verbose_exit{"debug/verbose-exit", "Display the actor status at exit", true};
+
+xbt_dynar_t get_actors_addr()
 {
+#if SIMGRID_HAVE_MC
+  return EngineImpl::get_instance()->get_actors_vector();
+#else
+  xbt_die("This function is intended to be used when compiling with MC");
+#endif
+}
 
-  while (not timer::kernel_timers().empty()) {
-    delete timer::kernel_timers().top().second;
-    timer::kernel_timers().pop();
+xbt_dynar_t get_dead_actors_addr()
+{
+#if SIMGRID_HAVE_MC
+  return EngineImpl::get_instance()->get_dead_actors_vector();
+#else
+  xbt_die("This function is intended to be used when compiling with MC");
+#endif
+}
+
+} // namespace kernel
+} // namespace simgrid
+
+XBT_ATTRIB_NORETURN static void inthandler(int)
+{
+  if (simgrid::kernel::cfg_verbose_exit) {
+    XBT_INFO("CTRL-C pressed. The current status will be displayed before exit (disable that behavior with option "
+             "'debug/verbose-exit').");
+    simgrid::kernel::EngineImpl::get_instance()->display_all_actor_status();
+  } else {
+    XBT_INFO("CTRL-C pressed, exiting. Hiding the current process status since 'debug/verbose-exit' is set to false.");
   }
+  exit(1);
+}
+
+#ifndef _WIN32
+static void segvhandler(int signum, siginfo_t* siginfo, void* /*context*/)
+{
+  if ((siginfo->si_signo == SIGSEGV && siginfo->si_code == SEGV_ACCERR) || siginfo->si_signo == SIGBUS) {
+    fprintf(stderr,
+            "Access violation or Bus error detected.\n"
+            "This probably comes from a programming error in your code, or from a stack\n"
+            "overflow. If you are certain of your code, try increasing the stack size\n"
+            "   --cfg=contexts/stack-size:XXX (current size is %u KiB).\n"
+            "\n"
+            "If it does not help, this may have one of the following causes:\n"
+            "a bug in SimGrid, a bug in the OS or a bug in a third-party libraries.\n"
+            "Failing hardware can sometimes generate such errors too.\n"
+            "\n"
+            "If you think you've found a bug in SimGrid, please report it along with a\n"
+            "Minimal Working Example (MWE) reproducing your problem and a full backtrace\n"
+            "of the fault captured with gdb or valgrind.\n",
+            smx_context_stack_size / 1024);
+  } else if (siginfo->si_signo == SIGSEGV) {
+    fprintf(stderr, "Segmentation fault.\n");
+#if HAVE_SMPI
+    if (smpi_enabled() && smpi_cfg_privatization() == SmpiPrivStrategies::NONE) {
+#if HAVE_PRIVATIZATION
+      fprintf(stderr, "Try to enable SMPI variable privatization with --cfg=smpi/privatization:yes.\n");
+#else
+      fprintf(stderr, "Sadly, your system does not support --cfg=smpi/privatization:yes (yet).\n");
+#endif /* HAVE_PRIVATIZATION */
+    }
+#endif /* HAVE_SMPI */
+  }
+  std::raise(signum);
+}
+
+/**
+ * Install signal handler for SIGSEGV.  Check that nobody has already installed
+ * its own handler.  For example, the Java VM does this.
+ */
+static void install_segvhandler()
+{
+  stack_t old_stack;
+
+  if (simgrid::kernel::context::Context::install_sigsegv_stack(&old_stack, true) == -1) {
+    XBT_WARN("Failed to register alternate signal stack: %s", strerror(errno));
+    return;
+  }
+  if (not(old_stack.ss_flags & SS_DISABLE)) {
+    XBT_DEBUG("An alternate stack was already installed (sp=%p, size=%zu, flags=%x). Restore it.", old_stack.ss_sp,
+              old_stack.ss_size, (unsigned)old_stack.ss_flags);
+    sigaltstack(&old_stack, nullptr);
+  }
+
+  struct sigaction action;
+  struct sigaction old_action;
+  action.sa_sigaction = &segvhandler;
+  action.sa_flags     = SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
+  sigemptyset(&action.sa_mask);
+
+  /* Linux tend to raise only SIGSEGV where other systems also raise SIGBUS on severe error */
+  for (int sig : {SIGSEGV, SIGBUS}) {
+    if (sigaction(sig, &action, &old_action) == -1) {
+      XBT_WARN("Failed to register signal handler for signal %d: %s", sig, strerror(errno));
+      continue;
+    }
+    if ((old_action.sa_flags & SA_SIGINFO) || old_action.sa_handler != SIG_DFL) {
+      XBT_DEBUG("A signal handler was already installed for signal %d (%p). Restore it.", sig,
+                (old_action.sa_flags & SA_SIGINFO) ? (void*)old_action.sa_sigaction : (void*)old_action.sa_handler);
+      sigaction(sig, &old_action, nullptr);
+    }
+  }
+}
+
+#endif /* _WIN32 */
 
+namespace simgrid {
+namespace kernel {
+
+EngineImpl::~EngineImpl()
+{
   /* Since hosts_ is a std::map, the hosts are destroyed in the lexicographic order, which ensures that the output is
    * reproducible.
    */
@@ -51,9 +161,8 @@ EngineImpl::~EngineImpl()
   for (auto const& kv : netpoints_)
     delete kv.second;
 
-  for (auto const& kv : links_)
-    if (kv.second)
-      kv.second->destroy();
+  while (not links_.empty())
+    links_.begin()->second->destroy();
 
   for (auto const& kv : mailboxes_)
     delete kv.second;
@@ -65,8 +174,87 @@ EngineImpl::~EngineImpl()
 #endif
   /* clear models before freeing handle, network models can use external callback defined in the handle */
   models_prio_.clear();
-  if (platf_handle_)
-    dlclose(platf_handle_);
+}
+
+void EngineImpl::initialize(int* argc, char** argv)
+{
+  xbt_assert(EngineImpl::instance_ == nullptr,
+             "It is currently forbidden to create more than one instance of kernel::EngineImpl");
+  EngineImpl::instance_ = this;
+#if SIMGRID_HAVE_MC
+  // The communication initialization is done ASAP, as we need to get some init parameters from the MC for different
+  // layers. But simix_global needs to be created, as we send the address of some of its fields to the MC that wants to
+  // read them directly.
+  simgrid::mc::AppSide::initialize();
+#endif
+
+  if (xbt_initialized == 0) {
+    xbt_init(argc, argv);
+
+    sg_config_init(argc, argv);
+  }
+
+  instance_->context_mod_init();
+
+  /* Prepare to display some more info when dying on Ctrl-C pressing */
+  std::signal(SIGINT, inthandler);
+
+#ifndef _WIN32
+  install_segvhandler();
+#endif
+
+  /* register a function to be called by SURF after the environment creation */
+  sg_platf_init();
+  s4u::Engine::on_platform_created.connect(surf_presolve);
+
+  if (config::get_value<bool>("debug/clean-atexit"))
+    atexit(shutdown);
+}
+
+void EngineImpl::shutdown()
+{
+  if (EngineImpl::instance_ == nullptr)
+    return;
+  XBT_DEBUG("EngineImpl::shutdown() called. Simulation's over.");
+#if HAVE_SMPI
+  if (not instance_->actor_list_.empty()) {
+    if (smpi_process()->initialized()) {
+      xbt_die("Process exited without calling MPI_Finalize - Killing simulation");
+    } else {
+      XBT_WARN("Process called exit when leaving - Skipping cleanups");
+      return;
+    }
+  }
+#endif
+
+  if (instance_->has_actors_to_run() && simgrid_get_clock() <= 0.0) {
+    XBT_CRITICAL("   ");
+    XBT_CRITICAL("The time is still 0, and you still have processes ready to run.");
+    XBT_CRITICAL("It seems that you forgot to run the simulation that you setup.");
+    xbt_die("Bailing out to avoid that stop-before-start madness. Please fix your code.");
+  }
+
+  /* Kill all actors (but maestro) */
+  instance_->maestro_->kill_all();
+  instance_->run_all_actors();
+  instance_->empty_trash();
+
+  /* Let's free maestro now */
+  instance_->destroy_maestro();
+
+  /* Finish context module and SURF */
+  instance_->destroy_context_factory();
+
+  while (not timer::kernel_timers().empty()) {
+    delete timer::kernel_timers().top().second;
+    timer::kernel_timers().pop();
+  }
+
+  tmgr_finalize();
+  sg_platf_exit();
+
+  delete instance_;
+  instance_ = nullptr;
 }
 
 void EngineImpl::load_platform(const std::string& platf)
@@ -76,11 +264,11 @@ void EngineImpl::load_platform(const std::string& platf)
 #ifdef _WIN32
     xbt_die("loading platform through shared library isn't supported on windows");
 #else
-    platf_handle_ = dlopen(platf.c_str(), RTLD_LAZY);
-    xbt_assert(platf_handle_, "Impossible to open platform file: %s", platf.c_str());
+    void* handle = dlopen(platf.c_str(), RTLD_LAZY);
+    xbt_assert(handle, "Impossible to open platform file: %s", platf.c_str());
+    platf_handle_           = std::unique_ptr<void, std::function<int(void*)>>(handle, dlclose);
     using load_fct_t = void (*)(const simgrid::s4u::Engine&);
-    dlerror();
-    auto callable           = (load_fct_t)dlsym(platf_handle_, "load_platform");
+    auto callable           = (load_fct_t)dlsym(platf_handle_.get(), "load_platform");
     const char* dlsym_error = dlerror();
     xbt_assert(not dlsym_error, "Error: %s", dlsym_error);
     callable(*simgrid::s4u::Engine::get_instance());
@@ -126,6 +314,11 @@ void EngineImpl::add_model(std::shared_ptr<resource::Model> model, const std::ve
   models_prio_[model_name] = std::move(model);
 }
 
+void EngineImpl::add_split_duplex_link(const std::string& name, std::unique_ptr<resource::SplitDuplexLinkImpl> link)
+{
+  split_duplex_links_[name] = std::move(link);
+}
+
 /** Wake up all actors waiting for a Surf action to finish */
 void EngineImpl::wake_all_waiting_actors() const
 {
@@ -155,7 +348,7 @@ void EngineImpl::wake_all_waiting_actors() const
  */
 void EngineImpl::run_all_actors()
 {
-  simix_global->get_context_factory()->run_all();
+  instance_->get_context_factory()->run_all();
 
   actors_to_run_.swap(actors_that_ran_);
   actors_to_run_.clear();
@@ -173,14 +366,14 @@ actor::ActorImpl* EngineImpl::get_actor_by_pid(aid_t pid)
       return &a;
   return nullptr; // Not found, even in the trash
 }
+
 /** Execute all the tasks that are queued, e.g. `.then()` callbacks of futures. */
 bool EngineImpl::execute_tasks()
 {
-  xbt_assert(tasksTemp.empty());
-
   if (tasks.empty())
     return false;
 
+  std::vector<xbt::Task<void()>> tasksTemp;
   do {
     // We don't want the callbacks to modify the vector we are iterating over:
     tasks.swap(tasksTemp);
@@ -280,7 +473,7 @@ void EngineImpl::run()
   do {
     XBT_DEBUG("New Schedule Round; size(queue)=%zu", actors_to_run_.size());
 
-    if (cfg_breakpoint >= 0.0 && surf_get_clock() >= cfg_breakpoint) {
+    if (cfg_breakpoint >= 0.0 && simgrid_get_clock() >= cfg_breakpoint) {
       XBT_DEBUG("Breakpoint reached (%g)", cfg_breakpoint.get());
       cfg_breakpoint = -1.0;
 #ifdef SIGTRAP
@@ -375,7 +568,7 @@ void EngineImpl::run()
       if (actor_list_.size() == daemons_.size())
         for (auto const& dmon : daemons_) {
           XBT_DEBUG("Kill %s", dmon->get_cname());
-          simix_global->get_maestro()->kill(dmon);
+          maestro_->kill(dmon);
         }
     }
 
@@ -415,7 +608,7 @@ void EngineImpl::run()
       simgrid::s4u::Engine::on_deadlock();
       for (auto const& kv : actor_list_) {
         XBT_DEBUG("Kill %s", kv.second->get_cname());
-        simix_global->get_maestro()->kill(kv.second);
+        maestro_->kill(kv.second);
       }
     }
   } while (time > -1.0 || has_actors_to_run());
@@ -427,3 +620,8 @@ void EngineImpl::run()
 }
 } // namespace kernel
 } // namespace simgrid
+
+void SIMIX_run() // XBT_ATTRIB_DEPRECATED_v332
+{
+  simgrid::kernel::EngineImpl::get_instance()->run();
+}