X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/f734ec7475682eb90323e804cbcfddd7e4523992..9ba5d8e19e181d2018da7f4e9060eda73b02fe23:/src/kernel/context/ContextUnix.cpp diff --git a/src/kernel/context/ContextUnix.cpp b/src/kernel/context/ContextUnix.cpp index ae143b8a7e..7ddae022aa 100644 --- a/src/kernel/context/ContextUnix.cpp +++ b/src/kernel/context/ContextUnix.cpp @@ -13,35 +13,6 @@ #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,9 +24,30 @@ 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* sysv_parmap; -static simgrid::kernel::context::ParallelUContext** sysv_workers_context; /* space to save the worker's context in each thread */ +static simgrid::kernel::context::UContext** sysv_workers_context; /* space to save the worker's context + * in each thread */ static uintptr_t sysv_threads_working; /* number of threads that have started their work */ static xbt_os_thread_key_t sysv_worker_id_key; /* thread-specific storage for the thread id */ #endif @@ -66,14 +58,14 @@ 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 { namespace context { class UContext : public Context { -protected: +private: ucontext_t uc_; /* the ucontext that executes the code */ char *stack_ = nullptr; /* the thread stack */ public: @@ -82,6 +74,7 @@ public: void_pfn_smxprocess_t cleanup_func, smx_actor_t process); ~UContext() override; void stop() override; + static void swap(UContext* from, UContext* to) { swapcontext(&from->uc_, &to->uc_); } }; class SerialUContext : public UContext { @@ -130,7 +123,7 @@ UContextFactory::UContextFactory() : ContextFactory("UContextFactory") #if HAVE_THREAD_CONTEXTS /* To use parallel ucontexts a thread pool is needed */ int nthreads = SIMIX_context_get_nthreads(); sysv_parmap = nullptr; - sysv_workers_context = xbt_new(ParallelUContext*, nthreads); + sysv_workers_context = new UContext*[nthreads]; sysv_maestro_context = nullptr; xbt_os_thread_key_create(&sysv_worker_id_key); #else @@ -145,7 +138,7 @@ UContextFactory::~UContextFactory() { #if HAVE_THREAD_CONTEXTS delete sysv_parmap; - xbt_free(sysv_workers_context); + delete[] sysv_workers_context; #endif } @@ -236,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)(); @@ -267,20 +252,20 @@ namespace context { void SerialUContext::suspend() { /* determine the next context */ - SerialUContext* next_context = nullptr; + UContext* next_context = nullptr; unsigned long int i = sysv_process_index++; if (i < simix_global->process_to_run.size()) { /* execute the next process */ XBT_DEBUG("Run next process"); - next_context = static_cast(simix_global->process_to_run[i]->context); + next_context = static_cast(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(sysv_maestro_context); + next_context = sysv_maestro_context; } SIMIX_context_set_current(next_context); - swapcontext(&this->uc_, &next_context->uc_); + UContext::swap(this, next_context); } // UContextSerial @@ -288,7 +273,7 @@ void SerialUContext::suspend() void SerialUContext::resume() { SIMIX_context_set_current(this); - swapcontext(&static_cast(sysv_maestro_context)->uc_, &this->uc_); + UContext::swap(sysv_maestro_context, this); } /** Run one particular simulated process on the current thread. */ @@ -300,15 +285,13 @@ void ParallelUContext::resume() // Store the number of my containing body in os-thread-specific area : xbt_os_thread_set_specific(sysv_worker_id_key, (void*) worker_id); // Get my current soul: - ParallelUContext* worker_context = static_cast(SIMIX_context_self()); + UContext* worker_context = static_cast(SIMIX_context_self()); // Write down that this soul is hosted in that body (for now) sysv_workers_context[worker_id] = worker_context; - // Retrieve the system-level info that fuels this soul: - ucontext_t* worker_stack = &worker_context->uc_; // Write in simix that I switched my soul SIMIX_context_set_current(this); // Actually do that using the relevant library call: - swapcontext(worker_stack, &this->uc_); + UContext::swap(worker_context, this); // No body runs that soul anymore at this point. // Instead the current body took the soul of simulated process // The simulated process wakes back after the call to @@ -339,11 +322,11 @@ void ParallelUContext::suspend() /* determine the next context */ // Get the next soul to embody now: boost::optional next_work = sysv_parmap->next(); - ParallelUContext* next_context; + UContext* next_context; if (next_work) { // There is a next soul to embody (ie, a next process to resume) XBT_DEBUG("Run next process"); - next_context = static_cast(next_work.get()->context); + next_context = static_cast(next_work.get()->context); } else { // All processes were run, go to the barrier XBT_DEBUG("No more processes to run"); @@ -356,12 +339,9 @@ void ParallelUContext::suspend() // When given that soul, the body will wait for the next scheduling round } - // Will contain the next soul to run, either simulated or initial minion's one - ucontext_t* next_stack = &next_context->uc_; - SIMIX_context_set_current(next_context); - // Get that next soul: - swapcontext(&this->uc_, next_stack); + // Get the next soul to run, either simulated or initial minion's one: + UContext::swap(this, next_context); #endif }