Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot/simgrid/simgrid
authorFrederic Suter <frederic.suter@cc.in2p3.fr>
Mon, 23 Oct 2017 13:30:10 +0000 (15:30 +0200)
committerFrederic Suter <frederic.suter@cc.in2p3.fr>
Mon, 23 Oct 2017 13:30:10 +0000 (15:30 +0200)
include/xbt/xbt_os_thread.h
src/kernel/context/ContextBoost.cpp
src/kernel/context/ContextBoost.hpp
src/kernel/context/ContextRaw.cpp
src/kernel/context/ContextRaw.hpp [new file with mode: 0644]
src/kernel/context/ContextUnix.cpp
src/mc/mc_dwarf.cpp
src/plugins/vm/VirtualMachineImpl.hpp
src/xbt/xbt_os_thread.c
tools/cmake/DefinePackages.cmake

index 097d503..23b8fc8 100644 (file)
@@ -36,6 +36,7 @@ XBT_PUBLIC(const char *) xbt_os_thread_self_name(void);
 XBT_PUBLIC(void) xbt_os_thread_set_extra_data(void *data);
 XBT_PUBLIC(void *) xbt_os_thread_get_extra_data(void);
 XBT_PUBLIC(void) xbt_os_thread_key_create(xbt_os_thread_key_t* key);
+XBT_PUBLIC(void) xbt_os_thread_key_destroy(xbt_os_thread_key_t key);
 XBT_PUBLIC(void) xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value);
 XBT_PUBLIC(void*) xbt_os_thread_get_specific(xbt_os_thread_key_t key);
   /* xbt_os_thread_join frees the joined thread (ie the XBT wrapper around it, the OS frees the rest) */
index 3e18362..a9422e0 100644 (file)
@@ -3,20 +3,10 @@
 /* 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 <cstdint>
+#include "ContextBoost.hpp"
 
-#include <functional>
 #include <utility>
-#include <vector>
-
-#include <boost/context/all.hpp>
-
 #include <xbt/log.h>
-#include <xbt/xbt_os_thread.h>
-
-#include "src/internal_config.h"
-#include "src/kernel/context/ContextBoost.hpp"
-#include "src/simix/smx_private.hpp"
 
 #if HAVE_SANITIZE_ADDRESS_FIBER_SUPPORT
 #include <sanitizer/asan_interface.h>
@@ -36,48 +26,15 @@ namespace simgrid {
 namespace kernel {
 namespace context {
 
-class BoostSerialContext : public BoostContext {
-public:
-  BoostSerialContext(std::function<void()> code,
-      void_pfn_smxprocess_t cleanup_func,
-      smx_actor_t process)
-    : BoostContext(std::move(code), cleanup_func, process) {}
-  void suspend() override;
-};
-
-#if HAVE_THREAD_CONTEXTS
-class BoostParallelContext : public BoostContext {
-public:
-  BoostParallelContext(std::function<void()> code,
-      void_pfn_smxprocess_t cleanup_func,
-      smx_actor_t process)
-    : BoostContext(std::move(code), cleanup_func, process) {}
-  void suspend() override;
-  void resume() override;
-};
-#endif
-
 // BoostContextFactory
 
-bool BoostContext::parallel_                             = false;
-simgrid::xbt::Parmap<smx_actor_t>* BoostContext::parmap_ = nullptr;
-uintptr_t BoostContext::threads_working_                 = 0;
-xbt_os_thread_key_t BoostContext::worker_id_key_;
-unsigned long BoostContext::process_index_   = 0;
-BoostContext* BoostContext::maestro_context_ = nullptr;
-std::vector<BoostContext*> BoostContext::workers_context_;
-
 BoostContextFactory::BoostContextFactory()
-  : ContextFactory("BoostContextFactory")
+    : ContextFactory("BoostContextFactory"), parallel_(SIMIX_context_is_parallel())
 {
-  BoostContext::parallel_ = SIMIX_context_is_parallel();
-  if (BoostContext::parallel_) {
+  BoostContext::setMaestro(nullptr);
+  if (parallel_) {
 #if HAVE_THREAD_CONTEXTS
-    BoostContext::parmap_ = nullptr;
-    BoostContext::workers_context_.clear();
-    BoostContext::workers_context_.resize(SIMIX_context_get_nthreads(), nullptr);
-    BoostContext::maestro_context_ = nullptr;
-    xbt_os_thread_key_create(&BoostContext::worker_id_key_);
+    ParallelBoostContext::initialize();
 #else
     xbt_die("No thread support for parallel context execution");
 #endif
@@ -87,103 +44,45 @@ BoostContextFactory::BoostContextFactory()
 BoostContextFactory::~BoostContextFactory()
 {
 #if HAVE_THREAD_CONTEXTS
-  delete BoostContext::parmap_;
-  BoostContext::parmap_ = nullptr;
-  BoostContext::workers_context_.clear();
+  if (parallel_)
+    ParallelBoostContext::finalize();
 #endif
 }
 
 smx_context_t BoostContextFactory::create_context(std::function<void()> code, void_pfn_smxprocess_t cleanup_func,
                                                   smx_actor_t process)
 {
-  BoostContext* context = nullptr;
-  if (BoostContext::parallel_)
 #if HAVE_THREAD_CONTEXTS
-    context = this->new_context<BoostParallelContext>(std::move(code), cleanup_func, process);
-#else
-    xbt_die("No support for parallel execution");
+  if (parallel_)
+    return this->new_context<ParallelBoostContext>(std::move(code), cleanup_func, process);
 #endif
-  else
-    context = this->new_context<BoostSerialContext>(std::move(code), cleanup_func, process);
-  return context;
+
+  return this->new_context<SerialBoostContext>(std::move(code), cleanup_func, process);
 }
 
 void BoostContextFactory::run_all()
 {
 #if HAVE_THREAD_CONTEXTS
-  if (BoostContext::parallel_) {
-    BoostContext::threads_working_ = 0;
-    if (not BoostContext::parmap_)
-      BoostContext::parmap_ =
-          new simgrid::xbt::Parmap<smx_actor_t>(SIMIX_context_get_nthreads(), SIMIX_context_get_parallel_mode());
-    BoostContext::parmap_->apply(
-        [](smx_actor_t process) {
-          BoostContext* context = static_cast<BoostContext*>(process->context);
-          return context->resume();
-        },
-        simix_global->process_to_run);
-  } else
+  if (parallel_)
+    ParallelBoostContext::run_all();
+  else
 #endif
-  {
-    if (simix_global->process_to_run.empty())
-      return;
-    smx_actor_t first_process    = simix_global->process_to_run.front();
-    BoostContext::process_index_ = 1;
-    /* execute the first process */
-    static_cast<BoostContext*>(first_process->context)->resume();
-  }
+    SerialBoostContext::run_all();
 }
 
-
 // BoostContext
 
-void BoostContext::smx_ctx_boost_wrapper(BoostContext::ctx_arg_type arg)
-{
-#if BOOST_VERSION < 106100
-  BoostContext* context = reinterpret_cast<BoostContext*>(arg);
-#else
-  ASAN_FINISH_SWITCH(nullptr, &static_cast<BoostContext**>(arg.data)[0]->asan_stack_,
-                     &static_cast<BoostContext**>(arg.data)[0]->asan_stack_size_);
-  static_cast<BoostContext**>(arg.data)[0]->fc_ = arg.fctx;
-  BoostContext* context                         = static_cast<BoostContext**>(arg.data)[1];
-#endif
-  try {
-    (*context)();
-    context->Context::stop();
-  } catch (StopRequest const&) {
-    XBT_DEBUG("Caught a StopRequest");
-  }
-  ASAN_EVAL(context->asan_stop_ = true);
-  context->suspend();
-}
-
-inline void BoostContext::smx_ctx_boost_jump_fcontext(BoostContext* from, BoostContext* to)
-{
-#if BOOST_VERSION < 105600
-  boost::context::jump_fcontext(from->fc_, to->fc_, reinterpret_cast<intptr_t>(to));
-#elif BOOST_VERSION < 106100
-  boost::context::jump_fcontext(&from->fc_, to->fc_, reinterpret_cast<intptr_t>(to));
-#else
-  BoostContext* ctx[2] = {from, to};
-  void* fake_stack;
-  ASAN_START_SWITCH(from->asan_stop_ ? nullptr : &fake_stack, to->asan_stack_, to->asan_stack_size_);
-  boost::context::detail::transfer_t arg = boost::context::detail::jump_fcontext(to->fc_, ctx);
-  ASAN_FINISH_SWITCH(fake_stack, &static_cast<BoostContext**>(arg.data)[0]->asan_stack_,
-                     &static_cast<BoostContext**>(arg.data)[0]->asan_stack_size_);
-  static_cast<BoostContext**>(arg.data)[0]->fc_ = arg.fctx;
-#endif
-}
+BoostContext* BoostContext::maestro_context_ = nullptr;
 
-BoostContext::BoostContext(std::function<void()> code,
-    void_pfn_smxprocess_t cleanup_func, smx_actor_t process)
-  : Context(std::move(code), cleanup_func, process)
+BoostContext::BoostContext(std::function<void()> code, void_pfn_smxprocess_t cleanup_func, smx_actor_t process)
+    : Context(std::move(code), cleanup_func, process)
 {
 
   /* if the user provided a function for the process then use it, otherwise it is the context for maestro */
   if (has_code()) {
     this->stack_ = SIMIX_context_stack_new();
-// We need to pass the bottom of the stack to make_fcontext, depending on the stack direction it may be the lower
-// or higher address:
+    /* We need to pass the bottom of the stack to make_fcontext,
+       depending on the stack direction it may be the lower or higher address: */
 #if PTH_STACKGROWTH == -1
     void* stack = static_cast<char*>(this->stack_) + smx_context_usable_stack_size;
 #else
@@ -191,9 +90,9 @@ BoostContext::BoostContext(std::function<void()> code,
 #endif
     ASAN_EVAL(this->asan_stack_ = stack);
 #if BOOST_VERSION < 106100
-    this->fc_ = boost::context::make_fcontext(stack, smx_context_usable_stack_size, smx_ctx_boost_wrapper);
+    this->fc_ = boost::context::make_fcontext(stack, smx_context_usable_stack_size, BoostContext::wrapper);
 #else
-    this->fc_ = boost::context::detail::make_fcontext(stack, smx_context_usable_stack_size, smx_ctx_boost_wrapper);
+    this->fc_ = boost::context::detail::make_fcontext(stack, smx_context_usable_stack_size, BoostContext::wrapper);
 #endif
   } else {
 #if BOOST_VERSION < 105600
@@ -215,7 +114,42 @@ BoostContext::~BoostContext()
   SIMIX_context_stack_delete(this->stack_);
 }
 
-// BoostSerialContext
+void BoostContext::wrapper(BoostContext::arg_type arg)
+{
+#if BOOST_VERSION < 106100
+  BoostContext* context = reinterpret_cast<BoostContext*>(arg);
+#else
+  ASAN_FINISH_SWITCH(nullptr, &static_cast<BoostContext**>(arg.data)[0]->asan_stack_,
+                     &static_cast<BoostContext**>(arg.data)[0]->asan_stack_size_);
+  static_cast<BoostContext**>(arg.data)[0]->fc_ = arg.fctx;
+  BoostContext* context                         = static_cast<BoostContext**>(arg.data)[1];
+#endif
+  try {
+    (*context)();
+    context->Context::stop();
+  } catch (StopRequest const&) {
+    XBT_DEBUG("Caught a StopRequest");
+  }
+  ASAN_EVAL(context->asan_stop_ = true);
+  context->suspend();
+}
+
+inline void BoostContext::swap(BoostContext* from, BoostContext* to)
+{
+#if BOOST_VERSION < 105600
+  boost::context::jump_fcontext(from->fc_, to->fc_, reinterpret_cast<intptr_t>(to));
+#elif BOOST_VERSION < 106100
+  boost::context::jump_fcontext(&from->fc_, to->fc_, reinterpret_cast<intptr_t>(to));
+#else
+  BoostContext* ctx[2] = {from, to};
+  void* fake_stack;
+  ASAN_START_SWITCH(from->asan_stop_ ? nullptr : &fake_stack, to->asan_stack_, to->asan_stack_size_);
+  boost::context::detail::transfer_t arg = boost::context::detail::jump_fcontext(to->fc_, ctx);
+  ASAN_FINISH_SWITCH(fake_stack, &static_cast<BoostContext**>(arg.data)[0]->asan_stack_,
+                     &static_cast<BoostContext**>(arg.data)[0]->asan_stack_size_);
+  static_cast<BoostContext**>(arg.data)[0]->fc_ = arg.fctx;
+#endif
+}
 
 void BoostContext::stop()
 {
@@ -223,63 +157,111 @@ void BoostContext::stop()
   throw StopRequest();
 }
 
-void BoostContext::resume()
-{
-  SIMIX_context_set_current(this);
-  smx_ctx_boost_jump_fcontext(maestro_context_, this);
-}
+// SerialBoostContext
 
-void BoostSerialContext::suspend()
+unsigned long SerialBoostContext::process_index_;
+
+void SerialBoostContext::suspend()
 {
   /* determine the next context */
-  BoostSerialContext* next_context;
+  SerialBoostContext* next_context;
   unsigned long int i = process_index_;
   process_index_++;
 
   if (i < simix_global->process_to_run.size()) {
     /* execute the next process */
     XBT_DEBUG("Run next process");
-    next_context = static_cast<BoostSerialContext*>(simix_global->process_to_run[i]->context);
+    next_context = static_cast<SerialBoostContext*>(simix_global->process_to_run[i]->context);
   } else {
     /* all processes were run, return to maestro */
     XBT_DEBUG("No more process to run");
-    next_context = static_cast<BoostSerialContext*>(maestro_context_);
+    next_context = static_cast<SerialBoostContext*>(BoostContext::getMaestro());
   }
-  SIMIX_context_set_current(static_cast<smx_context_t>(next_context));
-  smx_ctx_boost_jump_fcontext(this, next_context);
+  SIMIX_context_set_current(next_context);
+  BoostContext::swap(this, next_context);
+}
+
+void SerialBoostContext::resume()
+{
+  SIMIX_context_set_current(this);
+  BoostContext::swap(BoostContext::getMaestro(), this);
+}
+
+void SerialBoostContext::run_all()
+{
+  if (simix_global->process_to_run.empty())
+    return;
+  smx_actor_t first_process = simix_global->process_to_run.front();
+  process_index_            = 1;
+  /* execute the first process */
+  static_cast<SerialBoostContext*>(first_process->context)->resume();
 }
 
-// BoostParallelContext
+// ParallelBoostContext
 
 #if HAVE_THREAD_CONTEXTS
 
-void BoostParallelContext::suspend()
+simgrid::xbt::Parmap<smx_actor_t>* ParallelBoostContext::parmap_;
+uintptr_t ParallelBoostContext::threads_working_;
+xbt_os_thread_key_t ParallelBoostContext::worker_id_key_;
+std::vector<ParallelBoostContext*> ParallelBoostContext::workers_context_;
+
+void ParallelBoostContext::initialize()
+{
+  parmap_ = nullptr;
+  workers_context_.clear();
+  workers_context_.resize(SIMIX_context_get_nthreads(), nullptr);
+  xbt_os_thread_key_create(&worker_id_key_);
+}
+
+void ParallelBoostContext::finalize()
+{
+  delete parmap_;
+  parmap_ = nullptr;
+  workers_context_.clear();
+  xbt_os_thread_key_destroy(worker_id_key_);
+}
+
+void ParallelBoostContext::run_all()
+{
+  threads_working_ = 0;
+  if (parmap_ == nullptr)
+    parmap_ = new simgrid::xbt::Parmap<smx_actor_t>(SIMIX_context_get_nthreads(), SIMIX_context_get_parallel_mode());
+  parmap_->apply(
+      [](smx_actor_t process) {
+        ParallelBoostContext* context = static_cast<ParallelBoostContext*>(process->context);
+        context->resume();
+      },
+      simix_global->process_to_run);
+}
+
+void ParallelBoostContext::suspend()
 {
   boost::optional<smx_actor_t> next_work = parmap_->next();
-  BoostParallelContext* next_context;
+  ParallelBoostContext* next_context;
   if (next_work) {
     XBT_DEBUG("Run next process");
-    next_context = static_cast<BoostParallelContext*>(next_work.get()->context);
+    next_context = static_cast<ParallelBoostContext*>(next_work.get()->context);
   } else {
     XBT_DEBUG("No more processes to run");
     uintptr_t worker_id = reinterpret_cast<uintptr_t>(xbt_os_thread_get_specific(worker_id_key_));
-    next_context = static_cast<BoostParallelContext*>(workers_context_[worker_id]);
+    next_context        = workers_context_[worker_id];
   }
 
-  SIMIX_context_set_current(static_cast<smx_context_t>(next_context));
-  smx_ctx_boost_jump_fcontext(this, next_context);
+  SIMIX_context_set_current(next_context);
+  BoostContext::swap(this, next_context);
 }
 
-void BoostParallelContext::resume()
+void ParallelBoostContext::resume()
 {
   uintptr_t worker_id = __sync_fetch_and_add(&threads_working_, 1);
   xbt_os_thread_set_specific(worker_id_key_, reinterpret_cast<void*>(worker_id));
 
-  BoostParallelContext* worker_context = static_cast<BoostParallelContext*>(SIMIX_context_self());
-  workers_context_[worker_id] = worker_context;
+  ParallelBoostContext* worker_context = static_cast<ParallelBoostContext*>(SIMIX_context_self());
+  workers_context_[worker_id]          = worker_context;
 
   SIMIX_context_set_current(this);
-  smx_ctx_boost_jump_fcontext(worker_context, this);
+  BoostContext::swap(worker_context, this);
 }
 
 #endif
@@ -289,5 +271,4 @@ XBT_PRIVATE ContextFactory* boost_factory()
   XBT_VERB("Using Boost contexts. Welcome to the 21th century.");
   return new BoostContextFactory();
 }
-
 }}} // namespace
index f1261db..1132f98 100644 (file)
 #else
 #include <boost/context/detail/fcontext.hpp>
 #endif
+
+#include <cstdint>
 #include <functional>
 #include <vector>
 
-#include <xbt/parmap.hpp>
-
 #include <simgrid/simix.hpp>
+#include <xbt/parmap.hpp>
+#include <xbt/xbt_os_thread.h>
 
+#include "Context.hpp"
+#include "src/internal_config.h"
+#include "src/simix/smx_private.hpp"
 
 namespace simgrid {
 namespace kernel {
 namespace context {
 
-class BoostContext;
-class BoostSerialContext;
-class BoostParallelContext;
-class BoostContextFactory;
-
 /** @brief Userspace context switching implementation based on Boost.Context */
 class BoostContext : public Context {
-protected: // static
-  static bool parallel_;
-  static simgrid::xbt::Parmap<smx_actor_t>* parmap_;
-  static std::vector<BoostContext*> workers_context_;
-  static uintptr_t threads_working_;
-  static xbt_os_thread_key_t worker_id_key_;
-  static unsigned long process_index_;
+public:
+  BoostContext(std::function<void()> code, void_pfn_smxprocess_t cleanup_func, smx_actor_t process);
+  ~BoostContext() override;
+  void stop() override;
+  virtual void resume() = 0;
+
+  static void swap(BoostContext* from, BoostContext* to);
+  static BoostContext* getMaestro() { return maestro_context_; }
+  static void setMaestro(BoostContext* maestro) { maestro_context_ = maestro; }
+
+private:
   static BoostContext* maestro_context_;
+  void* stack_ = nullptr;
 
 #if BOOST_VERSION < 105600
   boost::context::fcontext_t* fc_ = nullptr;
-  typedef intptr_t ctx_arg_type;
+  typedef intptr_t arg_type;
 #elif BOOST_VERSION < 106100
   boost::context::fcontext_t fc_;
-  typedef intptr_t ctx_arg_type;
+  typedef intptr_t arg_type;
 #else
   boost::context::detail::fcontext_t fc_;
-  typedef boost::context::detail::transfer_t ctx_arg_type;
+  typedef boost::context::detail::transfer_t arg_type;
 #endif
-  static void smx_ctx_boost_wrapper(ctx_arg_type);
-  static void smx_ctx_boost_jump_fcontext(BoostContext*, BoostContext*);
-
 #if HAVE_SANITIZE_ADDRESS_FIBER_SUPPORT
   const void* asan_stack_ = nullptr;
   size_t asan_stack_size_ = 0;
   bool asan_stop_         = false;
 #endif
 
-  void* stack_ = nullptr;
+  static void wrapper(arg_type arg);
+};
+
+class SerialBoostContext : public BoostContext {
 public:
-  friend BoostContextFactory;
-  BoostContext(std::function<void()> code,
-          void_pfn_smxprocess_t cleanup_func,
-          smx_actor_t process);
-  ~BoostContext() override;
-  void stop() override;
-  virtual void resume();
+  SerialBoostContext(std::function<void()> code, void_pfn_smxprocess_t cleanup_func, smx_actor_t process)
+      : BoostContext(std::move(code), cleanup_func, process)
+  {
+  }
+  void suspend() override;
+  void resume() override;
+
+  static void run_all();
+
+private:
+  static unsigned long process_index_;
 };
 
-class BoostContextFactory : public ContextFactory {
+#if HAVE_THREAD_CONTEXTS
+class ParallelBoostContext : public BoostContext {
 public:
-  friend BoostContext;
-  friend BoostSerialContext;
-  friend BoostParallelContext;
+  ParallelBoostContext(std::function<void()> code, void_pfn_smxprocess_t cleanup_func, smx_actor_t process)
+      : BoostContext(std::move(code), cleanup_func, process)
+  {
+  }
+  void suspend() override;
+  void resume() override;
+
+  static void initialize();
+  static void finalize();
+  static void run_all();
+
+private:
+  static simgrid::xbt::Parmap<smx_actor_t>* parmap_;
+  static std::vector<ParallelBoostContext*> workers_context_;
+  static uintptr_t threads_working_;
+  static xbt_os_thread_key_t worker_id_key_;
+};
+#endif
 
+class BoostContextFactory : public ContextFactory {
+public:
   BoostContextFactory();
   ~BoostContextFactory() override;
-  Context* create_context(std::function<void()> code,
-    void_pfn_smxprocess_t, smx_actor_t process) override;
+  Context* create_context(std::function<void()> code, void_pfn_smxprocess_t cleanup, smx_actor_t process) override;
   void run_all() override;
-};
 
+private:
+  bool parallel_;
+};
 }}} // namespace
 
 #endif
index 5695d19..c9b66a3 100644 (file)
@@ -3,89 +3,13 @@
 /* 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/internal_config.h"
-
-#include "xbt/parmap.hpp"
+#include "ContextRaw.hpp"
 
 #include "mc/mc.h"
-#include "src/simix/smx_private.hpp"
 
 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
 
-// ***** Class definitions
-
-namespace simgrid {
-namespace kernel {
-namespace context {
-
-class RawContext;
-class RawContextFactory;
-
-/** @brief Fast context switching inspired from SystemV ucontexts.
-  *
-  * The main difference to the System V context is that Raw Contexts are much faster because they don't
-  * preserve the signal mask when switching. This saves a system call (at least on Linux) on each context switch.
-  */
-class RawContext : public Context {
-private:
-  void* stack_ = nullptr;
-  /** pointer to top the stack stack */
-  void* stack_top_ = nullptr;
-
-public:
-  friend class RawContextFactory;
-  RawContext(std::function<void()> code,
-          void_pfn_smxprocess_t cleanup_func,
-          smx_actor_t process);
-  ~RawContext() override;
-
-  static void wrapper(void* arg);
-  void stop() override;
-  void suspend() override;
-  void resume();
-private:
-  void suspend_serial();
-  void suspend_parallel();
-  void resume_serial();
-  void resume_parallel();
-};
-
-class RawContextFactory : public ContextFactory {
-public:
-  RawContextFactory();
-  ~RawContextFactory() override;
-  RawContext* create_context(std::function<void()> code,
-    void_pfn_smxprocess_t cleanup, smx_actor_t process) override;
-  void run_all() override;
-private:
-  void run_all_adaptative();
-  void run_all_serial();
-  void run_all_parallel();
-};
-
-ContextFactory* raw_factory()
-{
-  XBT_VERB("Using raw contexts. Because the glibc is just not good enough for us.");
-  return new RawContextFactory();
-}
-
-}}} // namespace
-
-// ***** Loads of static stuff
-
-#if HAVE_THREAD_CONTEXTS
-static simgrid::xbt::Parmap<smx_actor_t>* raw_parmap;
-static simgrid::kernel::context::RawContext** raw_workers_context;    /* space to save the worker context in each thread */
-static uintptr_t raw_threads_working;     /* number of threads that have started their work */
-static xbt_os_thread_key_t raw_worker_id_key; /* thread-specific storage for the thread id */
-#endif
-static unsigned long raw_process_index = 0;   /* index of the next process to run in the
-                                               * list of runnable processes */
-static simgrid::kernel::context::RawContext* raw_maestro_context;
-
-static bool raw_context_parallel = false;
-
-// ***** Raw context routines
+// Raw context routines
 
 typedef void (*rawctx_entry_point_t)(void *);
 
@@ -258,66 +182,65 @@ namespace simgrid {
 namespace kernel {
 namespace context {
 
-RawContextFactory::RawContextFactory()
-  : ContextFactory("RawContextFactory")
+// RawContextFactory
+
+RawContextFactory::RawContextFactory() : ContextFactory("RawContextFactory"), parallel_(SIMIX_context_is_parallel())
 {
-  raw_context_parallel = SIMIX_context_is_parallel();
-  if (raw_context_parallel) {
+  RawContext::setMaestro(nullptr);
+  if (parallel_) {
 #if HAVE_THREAD_CONTEXTS
-    int nthreads = SIMIX_context_get_nthreads();
-    xbt_os_thread_key_create(&raw_worker_id_key);
-    // TODO, lazily init
-    raw_parmap = nullptr;
-    raw_workers_context = new RawContext*[nthreads];
-    raw_maestro_context = nullptr;
-#endif
     // TODO: choose dynamically when SIMIX_context_get_parallel_threshold() > 1
+    ParallelRawContext::initialize();
+#else
+    xbt_die("You asked for a parallel execution, but you don't have any threads.");
+#endif
   }
 }
 
 RawContextFactory::~RawContextFactory()
 {
 #if HAVE_THREAD_CONTEXTS
-  delete raw_parmap;
-  delete[] raw_workers_context;
+  if (parallel_)
+    ParallelRawContext::finalize();
 #endif
 }
 
-RawContext* RawContextFactory::create_context(std::function<void()> code,
-    void_pfn_smxprocess_t cleanup, smx_actor_t process)
+Context* RawContextFactory::create_context(std::function<void()> code, void_pfn_smxprocess_t cleanup_func,
+                                           smx_actor_t process)
 {
-  return this->new_context<RawContext>(std::move(code), cleanup, process);
+#if HAVE_THREAD_CONTEXTS
+  if (parallel_)
+    return this->new_context<ParallelRawContext>(std::move(code), cleanup_func, process);
+#endif
+
+  return this->new_context<SerialRawContext>(std::move(code), cleanup_func, process);
 }
 
-void RawContext::wrapper(void* arg)
+void RawContextFactory::run_all()
 {
-  RawContext* context = static_cast<RawContext*>(arg);
-  try {
-    (*context)();
-    context->Context::stop();
-  } catch (StopRequest const&) {
-    XBT_DEBUG("Caught a StopRequest");
-  }
-  context->suspend();
+#if HAVE_THREAD_CONTEXTS
+  if (parallel_)
+    ParallelRawContext::run_all();
+  else
+#endif
+    SerialRawContext::run_all();
 }
 
-RawContext::RawContext(std::function<void()> code,
-    void_pfn_smxprocess_t cleanup, smx_actor_t process)
-  : Context(std::move(code), cleanup, process)
+// RawContext
+
+RawContext* RawContext::maestro_context_ = nullptr;
+
+RawContext::RawContext(std::function<void()> code, void_pfn_smxprocess_t cleanup, smx_actor_t process)
+    : Context(std::move(code), cleanup, process)
 {
    if (has_code()) {
      this->stack_ = SIMIX_context_stack_new();
-     this->stack_top_ = raw_makecontext(this->stack_,
-                         smx_context_usable_stack_size,
-                         RawContext::wrapper,
-                         this);
+     this->stack_top_ = raw_makecontext(this->stack_, smx_context_usable_stack_size, RawContext::wrapper, this);
    } else {
-     if(process != nullptr && raw_maestro_context == nullptr)
-       raw_maestro_context = this;
+     if (process != nullptr && maestro_context_ == nullptr)
+       maestro_context_ = this;
      if (MC_is_active())
-       MC_ignore_heap(
-         &raw_maestro_context->stack_top_,
-         sizeof(raw_maestro_context->stack_top_));
+       MC_ignore_heap(&maestro_context_->stack_top_, sizeof(maestro_context_->stack_top_));
    }
 }
 
@@ -326,142 +249,143 @@ RawContext::~RawContext()
   SIMIX_context_stack_delete(this->stack_);
 }
 
-void RawContext::stop()
+void RawContext::wrapper(void* arg)
 {
-  Context::stop();
-  throw StopRequest();
+  RawContext* context = static_cast<RawContext*>(arg);
+  try {
+    (*context)();
+    context->Context::stop();
+  } catch (StopRequest const&) {
+    XBT_DEBUG("Caught a StopRequest");
+  }
+  context->suspend();
 }
 
-void RawContextFactory::run_all()
+inline void RawContext::swap(RawContext* from, RawContext* to)
 {
-  if (raw_context_parallel)
-    run_all_parallel();
-  else
-    run_all_serial();
+  raw_swapcontext(&from->stack_top_, to->stack_top_);
 }
 
-void RawContextFactory::run_all_serial()
+void RawContext::stop()
 {
-  if (simix_global->process_to_run.empty())
-    return;
-
-  smx_actor_t first_process = simix_global->process_to_run.front();
-  raw_process_index = 1;
-  static_cast<RawContext*>(first_process->context)->resume_serial();
+  Context::stop();
+  throw StopRequest();
 }
 
-void RawContextFactory::run_all_parallel()
-{
-#if HAVE_THREAD_CONTEXTS
-  raw_threads_working = 0;
-  if (raw_parmap == nullptr)
-    raw_parmap = new simgrid::xbt::Parmap<smx_actor_t>(SIMIX_context_get_nthreads(), SIMIX_context_get_parallel_mode());
-  raw_parmap->apply(
-      [](smx_actor_t process) {
-        RawContext* context = static_cast<RawContext*>(process->context);
-        context->resume_parallel();
-      },
-      simix_global->process_to_run);
-#else
-  xbt_die("You asked for a parallel execution, but you don't have any threads.");
-#endif
-}
+// SerialRawContext
 
-void RawContext::suspend()
-{
-  if (raw_context_parallel)
-    RawContext::suspend_parallel();
-  else
-    RawContext::suspend_serial();
-}
+unsigned long SerialRawContext::process_index_; /* index of the next process to run in the list of runnable processes */
 
-void RawContext::suspend_serial()
+void SerialRawContext::suspend()
 {
   /* determine the next context */
-  RawContext* next_context = nullptr;
-  unsigned long int i      = raw_process_index;
-  raw_process_index++;
+  SerialRawContext* next_context;
+  unsigned long int i = process_index_;
+  process_index_++;
   if (i < simix_global->process_to_run.size()) {
     /* execute the next process */
     XBT_DEBUG("Run next process");
-    next_context = static_cast<RawContext*>(simix_global->process_to_run[i]->context);
+    next_context = static_cast<SerialRawContext*>(simix_global->process_to_run[i]->context);
   } else {
     /* all processes were run, return to maestro */
     XBT_DEBUG("No more process to run");
-    next_context = static_cast<RawContext*>(raw_maestro_context);
+    next_context = static_cast<SerialRawContext*>(RawContext::getMaestro());
   }
   SIMIX_context_set_current(next_context);
-  raw_swapcontext(&this->stack_top_, next_context->stack_top_);
+  RawContext::swap(this, next_context);
 }
 
-void RawContext::suspend_parallel()
+void SerialRawContext::resume()
 {
+  SIMIX_context_set_current(this);
+  RawContext::swap(RawContext::getMaestro(), this);
+}
+
+void SerialRawContext::run_all()
+{
+  if (simix_global->process_to_run.empty())
+    return;
+  smx_actor_t first_process = simix_global->process_to_run.front();
+  process_index_            = 1;
+  static_cast<SerialRawContext*>(first_process->context)->resume();
+}
+
+// ParallelRawContext
+
 #if HAVE_THREAD_CONTEXTS
+
+simgrid::xbt::Parmap<smx_actor_t>* ParallelRawContext::parmap_;
+uintptr_t ParallelRawContext::threads_working_;         /* number of threads that have started their work */
+xbt_os_thread_key_t ParallelRawContext::worker_id_key_; /* thread-specific storage for the thread id */
+std::vector<ParallelRawContext*> ParallelRawContext::workers_context_; /* space to save the worker context
+                                                                          in each thread */
+
+void ParallelRawContext::initialize()
+{
+  parmap_ = nullptr;
+  workers_context_.clear();
+  workers_context_.resize(SIMIX_context_get_nthreads(), nullptr);
+  xbt_os_thread_key_create(&worker_id_key_);
+}
+
+void ParallelRawContext::finalize()
+{
+  delete parmap_;
+  parmap_ = nullptr;
+  workers_context_.clear();
+  xbt_os_thread_key_destroy(worker_id_key_);
+}
+
+void ParallelRawContext::run_all()
+{
+  threads_working_ = 0;
+  if (parmap_ == nullptr)
+    parmap_ = new simgrid::xbt::Parmap<smx_actor_t>(SIMIX_context_get_nthreads(), SIMIX_context_get_parallel_mode());
+  parmap_->apply(
+      [](smx_actor_t process) {
+        ParallelRawContext* context = static_cast<ParallelRawContext*>(process->context);
+        context->resume();
+      },
+      simix_global->process_to_run);
+}
+
+void ParallelRawContext::suspend()
+{
   /* determine the next context */
-  boost::optional<smx_actor_t> next_work = raw_parmap->next();
-  RawContext* next_context;
+  boost::optional<smx_actor_t> next_work = parmap_->next();
+  ParallelRawContext* next_context;
   if (next_work) {
     /* there is a next process to resume */
     XBT_DEBUG("Run next process");
-    next_context = static_cast<RawContext*>(next_work.get()->context);
+    next_context = static_cast<ParallelRawContext*>(next_work.get()->context);
   } else {
     /* all processes were run, go to the barrier */
     XBT_DEBUG("No more processes to run");
-    uintptr_t worker_id = (uintptr_t)
-      xbt_os_thread_get_specific(raw_worker_id_key);
-    next_context = raw_workers_context[worker_id];
-    XBT_DEBUG("Restoring worker stack %zu (working threads = %zu)",
-        worker_id, raw_threads_working);
+    uintptr_t worker_id = reinterpret_cast<uintptr_t>(xbt_os_thread_get_specific(worker_id_key_));
+    next_context        = workers_context_[worker_id];
+    XBT_DEBUG("Restoring worker stack %zu (working threads = %zu)", worker_id, threads_working_);
   }
 
   SIMIX_context_set_current(next_context);
-  raw_swapcontext(&this->stack_top_, next_context->stack_top_);
-#endif
+  RawContext::swap(this, next_context);
 }
 
-void RawContext::resume()
-{
-  if (raw_context_parallel)
-    resume_parallel();
-  else
-    resume_serial();
-}
-
-void RawContext::resume_serial()
+void ParallelRawContext::resume()
 {
+  uintptr_t worker_id = __sync_fetch_and_add(&threads_working_, 1);
+  xbt_os_thread_set_specific(worker_id_key_, reinterpret_cast<void*>(worker_id));
+  ParallelRawContext* worker_context = static_cast<ParallelRawContext*>(SIMIX_context_self());
+  workers_context_[worker_id]        = worker_context;
+  XBT_DEBUG("Saving worker stack %zu", worker_id);
   SIMIX_context_set_current(this);
-  raw_swapcontext(&raw_maestro_context->stack_top_, this->stack_top_);
+  RawContext::swap(worker_context, this);
 }
 
-void RawContext::resume_parallel()
-{
-#if HAVE_THREAD_CONTEXTS
-  uintptr_t worker_id = __sync_fetch_and_add(&raw_threads_working, 1);
-  xbt_os_thread_set_specific(raw_worker_id_key, (void*) worker_id);
-  RawContext* worker_context     = static_cast<RawContext*>(SIMIX_context_self());
-  raw_workers_context[worker_id] = worker_context;
-  XBT_DEBUG("Saving worker stack %zu", worker_id);
-  SIMIX_context_set_current(this);
-  raw_swapcontext(&worker_context->stack_top_, this->stack_top_);
-#else
-  xbt_die("Parallel execution disabled");
 #endif
-}
 
-/** @brief Resumes all processes ready to run. */
-void RawContextFactory::run_all_adaptative()
+ContextFactory* raw_factory()
 {
-  unsigned long nb_processes = simix_global->process_to_run.size();
-  if (SIMIX_context_is_parallel() &&
-      static_cast<unsigned long>(SIMIX_context_get_parallel_threshold()) < nb_processes) {
-    raw_context_parallel = true;
-    XBT_DEBUG("Runall // %lu", nb_processes);
-    this->run_all_parallel();
-  } else {
-    XBT_DEBUG("Runall serial %lu", nb_processes);
-    raw_context_parallel = false;
-    this->run_all_serial();
-  }
+  XBT_VERB("Using raw contexts. Because the glibc is just not good enough for us.");
+  return new RawContextFactory();
 }
-
 }}}
diff --git a/src/kernel/context/ContextRaw.hpp b/src/kernel/context/ContextRaw.hpp
new file mode 100644 (file)
index 0000000..b4f30ec
--- /dev/null
@@ -0,0 +1,99 @@
+/* Copyright (c) 2009-2017. 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. */
+
+#ifndef SIMGRID_SIMIX_BOOST_CONTEXT_HPP
+#define SIMGRID_SIMIX_BOOST_CONTEXT_HPP
+
+#include <cstdint>
+#include <functional>
+#include <vector>
+
+#include <simgrid/simix.hpp>
+#include <xbt/parmap.hpp>
+#include <xbt/xbt_os_thread.h>
+
+#include "Context.hpp"
+#include "src/internal_config.h"
+#include "src/simix/smx_private.hpp"
+
+namespace simgrid {
+namespace kernel {
+namespace context {
+
+/** @brief Fast context switching inspired from SystemV ucontexts.
+  *
+  * The main difference to the System V context is that Raw Contexts are much faster because they don't
+  * preserve the signal mask when switching. This saves a system call (at least on Linux) on each context switch.
+  */
+class RawContext : public Context {
+public:
+  RawContext(std::function<void()> code, void_pfn_smxprocess_t cleanup_func, smx_actor_t process);
+  ~RawContext() override;
+  void stop() override;
+  virtual void resume() = 0;
+
+  static void swap(RawContext* from, RawContext* to);
+  static RawContext* getMaestro() { return maestro_context_; }
+  static void setMaestro(RawContext* maestro) { maestro_context_ = maestro; }
+
+private:
+  static RawContext* maestro_context_;
+  void* stack_ = nullptr;
+  /** pointer to top the stack stack */
+  void* stack_top_ = nullptr;
+
+  static void wrapper(void* arg);
+};
+
+class SerialRawContext : public RawContext {
+public:
+  SerialRawContext(std::function<void()> code, void_pfn_smxprocess_t cleanup_func, smx_actor_t process)
+      : RawContext(std::move(code), cleanup_func, process)
+  {
+  }
+  void suspend() override;
+  void resume() override;
+
+  static void run_all();
+
+private:
+  static unsigned long process_index_;
+};
+
+#if HAVE_THREAD_CONTEXTS
+class ParallelRawContext : public RawContext {
+public:
+  ParallelRawContext(std::function<void()> code, void_pfn_smxprocess_t cleanup_func, smx_actor_t process)
+      : RawContext(std::move(code), cleanup_func, process)
+  {
+  }
+  void suspend() override;
+  void resume() override;
+
+  static void initialize();
+  static void finalize();
+  static void run_all();
+
+private:
+  static simgrid::xbt::Parmap<smx_actor_t>* parmap_;
+  static std::vector<ParallelRawContext*> workers_context_;
+  static uintptr_t threads_working_;
+  static xbt_os_thread_key_t worker_id_key_;
+};
+#endif
+
+class RawContextFactory : public ContextFactory {
+public:
+  RawContextFactory();
+  ~RawContextFactory() override;
+  Context* create_context(std::function<void()> code, void_pfn_smxprocess_t cleanup, smx_actor_t process) override;
+  void run_all() override;
+
+private:
+  bool parallel_;
+};
+}}} // namespace
+
+#endif
index 2512da7..fd6562f 100644 (file)
 #include "src/simix/smx_private.hpp"
 #include "xbt/parmap.hpp"
 
-/** Many integers are needed to store a pointer
- *
- * This is a bit paranoid about sizeof(smx_ctx_sysv_t) not being a multiple
- * of sizeof(int), but it doesn't harm. */
-#define CTX_ADDR_LEN                            \
-  (sizeof(void*) / sizeof(int) +       \
-   !!(sizeof(void*) % sizeof(int)))
-
-/** A better makecontext
- *
- * Makecontext expects integer arguments, we the context
- * variable is decomposed into a serie of integers and
- * each integer is passed as argument to makecontext. */
-static void simgrid_makecontext(ucontext_t* ucp, void (*func)(int first, ...), void* arg)
-{
-  int ctx_addr[CTX_ADDR_LEN];
-  memcpy(ctx_addr, &arg, sizeof(void*));
-  switch (CTX_ADDR_LEN) {
-  case 1:
-    makecontext(ucp, (void (*)())func, 1, ctx_addr[0]);
-    break;
-  case 2:
-    makecontext(ucp, (void (*)()) func, 2, ctx_addr[0], ctx_addr[1]);
-    break;
-  default:
-    xbt_die("Ucontexts are not supported on this arch yet (addr len = %zu/%zu = %zu)", sizeof(void*), sizeof(int), CTX_ADDR_LEN);
-  }
-}
-
 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
 
 namespace simgrid {
@@ -53,6 +24,26 @@ namespace context {
   class UContextFactory;
 }}}
 
+/** Many integers are needed to store a pointer
+ *
+ * Support up to two ints. */
+constexpr int CTX_ADDR_LEN = 2;
+
+static_assert(sizeof(simgrid::kernel::context::UContext*) <= CTX_ADDR_LEN * sizeof(int),
+              "Ucontexts are not supported on this arch yet");
+
+/** A better makecontext
+ *
+ * Makecontext expects integer arguments, we the context
+ * variable is decomposed into a serie of integers and
+ * each integer is passed as argument to makecontext. */
+static void simgrid_makecontext(ucontext_t* ucp, void (*func)(int, int), simgrid::kernel::context::UContext* arg)
+{
+  int ctx_addr[CTX_ADDR_LEN]{};
+  memcpy(ctx_addr, &arg, sizeof arg);
+  makecontext(ucp, (void (*)())func, 2, ctx_addr[0], ctx_addr[1]);
+}
+
 #if HAVE_THREAD_CONTEXTS
 static simgrid::xbt::Parmap<smx_actor_t>* sysv_parmap;
 static simgrid::kernel::context::UContext** sysv_workers_context; /* space to save the worker's context
@@ -67,7 +58,7 @@ static bool sysv_parallel;
 
 // The name of this function is currently hardcoded in the code (as string).
 // Do not change it without fixing those references as well.
-static void smx_ctx_sysv_wrapper(int first, ...);
+static void smx_ctx_sysv_wrapper(int, int);
 
 namespace simgrid {
 namespace kernel {
@@ -238,20 +229,12 @@ void UContext::stop()
 }
 }}} // namespace simgrid::kernel::context
 
-static void smx_ctx_sysv_wrapper(int first, ...)
+static void smx_ctx_sysv_wrapper(int i1, int i2)
 {
   // Rebuild the Context* pointer from the integers:
-  int ctx_addr[CTX_ADDR_LEN];
+  int ctx_addr[CTX_ADDR_LEN] = {i1, i2};
   simgrid::kernel::context::UContext* context;
-  ctx_addr[0] = first;
-  if (CTX_ADDR_LEN > 1) {
-    va_list ap;
-    va_start(ap, first);
-    for (unsigned i = 1; i < CTX_ADDR_LEN; i++)
-      ctx_addr[i] = va_arg(ap, int);
-    va_end(ap);
-  }
-  memcpy(&context, ctx_addr, sizeof(simgrid::kernel::context::UContext*));
+  memcpy(&context, ctx_addr, sizeof context);
 
   try {
     (*context)();
@@ -270,7 +253,8 @@ void SerialUContext::suspend()
 {
   /* determine the next context */
   UContext* next_context = nullptr;
-  unsigned long int i = sysv_process_index++;
+  unsigned long int i    = sysv_process_index;
+  sysv_process_index++;
 
   if (i < simix_global->process_to_run.size()) {
     /* execute the next process */
index 440de3a..88e1369 100644 (file)
@@ -799,17 +799,13 @@ static std::unique_ptr<simgrid::mc::Variable> MC_die_to_variable(
     dwarf_attr(die, DW_AT_start_scope, &attr);
     int form = dwarf_whatform(&attr);
     simgrid::dwarf::FormClass form_class = simgrid::dwarf::classify_form(form);
-    switch (form_class) {
-      case simgrid::dwarf::FormClass::Constant: {
-        Dwarf_Word value;
-        variable->start_scope =
-            dwarf_formudata(&attr, &value) == 0 ? (size_t) value : 0;
-        break;
-      }
-
-      default: // includes FormClass::RangeListPtr (TODO)
-        xbt_die("Unhandled form 0x%x, class 0x%X for DW_AT_start_scope of variable %s", (unsigned)form,
-                (unsigned)form_class, name == nullptr ? "?" : name);
+    if (form_class == simgrid::dwarf::FormClass::Constant) {
+      Dwarf_Word value;
+      variable->start_scope = dwarf_formudata(&attr, &value) == 0 ? (size_t)value : 0;
+    } else {
+      // TODO: FormClass::RangeListPtr
+      xbt_die("Unhandled form 0x%x, class 0x%X for DW_AT_start_scope of variable %s", (unsigned)form,
+              (unsigned)form_class, name == nullptr ? "?" : name);
     }
   }
 
index 467b3cc..026071e 100644 (file)
@@ -93,7 +93,6 @@ public:
   int dp_enabled                     = 0;
   double dp_updated_by_deleted_tasks = 0;
 
-public:
   e_surf_vm_state_t getState();
   void setState(e_surf_vm_state_t state);
   static std::deque<s4u::VirtualMachine*> allVms_;
index f0d9358..503ad7c 100644 (file)
@@ -252,6 +252,12 @@ void xbt_os_thread_key_create(xbt_os_thread_key_t* key)
   xbt_assert(errcode==0 , "pthread_key_create failed");
 }
 
+void xbt_os_thread_key_destroy(xbt_os_thread_key_t key)
+{
+  int errcode = pthread_key_delete(key);
+  xbt_assert(errcode == 0, "pthread_key_delete failed");
+}
+
 void xbt_os_thread_set_specific(xbt_os_thread_key_t key, void* value)
 {
   int errcode = pthread_setspecific(key, value);
index 794398b..802efdd 100644 (file)
@@ -380,6 +380,7 @@ set(SIMIX_SRC
   src/kernel/context/Context.cpp
   src/kernel/context/Context.hpp
   src/kernel/context/ContextRaw.cpp
+  src/kernel/context/ContextRaw.hpp
   src/simix/smx_deployment.cpp
   src/simix/smx_environment.cpp
   src/simix/smx_global.cpp