X-Git-Url: http://info.iut-bm.univ-fcomte.fr/pub/gitweb/simgrid.git/blobdiff_plain/70439fdf4efc3ac256a832dcad7b3ce04c35be23..a23e91ed7615232922aa1b38cef206dce24eb072:/src/simix/smx_context_boost.cpp diff --git a/src/simix/smx_context_boost.cpp b/src/simix/smx_context_boost.cpp new file mode 100644 index 0000000000..ce8d08a2e0 --- /dev/null +++ b/src/simix/smx_context_boost.cpp @@ -0,0 +1,168 @@ +/* Copyright (c) 2015. 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. */ + +/** @file Userspace context switching implementation based on Boost.Context */ + +#include + +#include + +#include "xbt/log.h" +#include "smx_private.h" +#include "internal_config.h" + +XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context); + +typedef struct s_smx_ctx_boost { + s_smx_ctx_base_t super; /* Fields of super implementation */ + boost::context::fcontext_t* fc; + void* stack; +} s_smx_ctx_boost_t, *smx_ctx_boost_t; + +static int smx_ctx_boost_factory_finalize(smx_context_factory_t *factory); +static smx_context_t +smx_ctx_boost_create_context(xbt_main_func_t code, int argc, char **argv, + void_pfn_smxprocess_t cleanup_func, smx_process_t process); +static void smx_ctx_boost_free(smx_context_t context); + +static void smx_ctx_boost_wrapper(std::intptr_t arg); + +static void smx_ctx_boost_stop_serial(smx_context_t context); +static void smx_ctx_boost_suspend_serial(smx_context_t context); +static void smx_ctx_boost_resume_serial(smx_process_t first_process); +static void smx_ctx_boost_runall_serial(void); + +static unsigned long boost_process_index = 0; +static boost::context::fcontext_t boost_maestro_fcontext; +static smx_ctx_boost_t boost_maestro_context; + +void SIMIX_ctx_boost_factory_init(smx_context_factory_t *factory) +{ + smx_ctx_base_factory_init(factory); + XBT_VERB("Activating boost context factory"); + + (*factory)->finalize = smx_ctx_boost_factory_finalize; + (*factory)->create_context = smx_ctx_boost_create_context; + /* Do not overload that method (*factory)->finalize */ + (*factory)->free = smx_ctx_boost_free; + (*factory)->name = "smx_boost_context_factory"; + + if (SIMIX_context_is_parallel()) { + THROWF(arg_error, 0, "No thread support for parallel context execution"); + } else { + (*factory)->stop = smx_ctx_boost_stop_serial; + (*factory)->suspend = smx_ctx_boost_suspend_serial; + (*factory)->runall = smx_ctx_boost_runall_serial; + } +} + +/* Initialization functions */ + +static int smx_ctx_boost_factory_finalize(smx_context_factory_t *factory) +{ + return smx_ctx_base_factory_finalize(factory); +} + +static smx_context_t +smx_ctx_boost_create_context(xbt_main_func_t code, int argc, char **argv, + void_pfn_smxprocess_t cleanup_func, smx_process_t process) +{ + smx_ctx_boost_t context = + (smx_ctx_boost_t) smx_ctx_base_factory_create_context_sized( + sizeof(s_smx_ctx_boost_t), + code, + argc, + argv, + cleanup_func, + process); + + /* if the user provided a function for the process then use it, + otherwise it is the context for maestro */ + if (code) { + context->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: +#if PTH_STACKGROWTH == -1 + void* stack = (char*) context->stack + smx_context_usable_stack_size - 1; +#else + void* stack = context->stack; +#endif + context->fc = boost::context::make_fcontext( + stack, + smx_context_usable_stack_size, + smx_ctx_boost_wrapper); + } else if (process != nullptr && boost_maestro_context == nullptr) { + context->stack = nullptr; + context->fc = &boost_maestro_fcontext; + boost_maestro_context = context; + } + + return (smx_context_t) context; +} + +static void smx_ctx_boost_free(smx_context_t c) +{ + smx_ctx_boost_t context = (smx_ctx_boost_t) c; + if (!context) + return; + if ((smx_ctx_boost_t) c == boost_maestro_context) + boost_maestro_context = nullptr; + SIMIX_context_stack_delete(context->stack); + smx_ctx_base_free(c); +} + +static void smx_ctx_boost_wrapper(std::intptr_t arg) +{ + smx_context_t context = (smx_context_t) arg; + context->code(context->argc, context->argv); + smx_ctx_boost_stop_serial(context); +} + +static void smx_ctx_boost_stop_serial(smx_context_t context) +{ + smx_ctx_base_stop(context); + simix_global->context_factory->suspend(context); +} + +static void smx_ctx_boost_suspend_serial(smx_context_t context) +{ + /* determine the next context */ + smx_ctx_boost_t next_context; + unsigned long int i = boost_process_index++; + + if (i < xbt_dynar_length(simix_global->process_to_run)) { + /* execute the next process */ + XBT_DEBUG("Run next process"); + next_context = (smx_ctx_boost_t) xbt_dynar_get_as( + simix_global->process_to_run, i, smx_process_t)->context; + } + else { + /* all processes were run, return to maestro */ + XBT_DEBUG("No more process to run"); + next_context = (smx_ctx_boost_t) boost_maestro_context; + } + SIMIX_context_set_current((smx_context_t) next_context); + boost::context::jump_fcontext( + ((smx_ctx_boost_t)context)->fc, next_context->fc, (intptr_t)next_context); +} + +static void smx_ctx_boost_resume_serial(smx_process_t first_process) +{ + smx_ctx_boost_t context = (smx_ctx_boost_t) first_process->context; + SIMIX_context_set_current((smx_context_t) context); + boost::context::jump_fcontext(boost_maestro_context->fc, context->fc, + (intptr_t)context); +} + +static void smx_ctx_boost_runall_serial(void) +{ + smx_process_t first_process = + xbt_dynar_get_as(simix_global->process_to_run, 0, smx_process_t); + boost_process_index = 1; + + /* execute the first process */ + smx_ctx_boost_resume_serial(first_process); +}