1 /* Copyright (c) 2015. The SimGrid Team.
2 * All rights reserved. */
4 /* This program is free software; you can redistribute it and/or modify it
5 * under the terms of the license (GNU LGPL) which comes with this package. */
7 /** @file Userspace context switching implementation based on Boost.Context */
11 #include <boost/context/all.hpp>
14 #include "smx_private.h"
15 #include "internal_config.h"
17 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
19 typedef struct s_smx_ctx_boost {
20 s_smx_ctx_base_t super; /* Fields of super implementation */
21 boost::context::fcontext_t* fc;
23 } s_smx_ctx_boost_t, *smx_ctx_boost_t;
25 static int smx_ctx_boost_factory_finalize(smx_context_factory_t *factory);
27 smx_ctx_boost_create_context(xbt_main_func_t code, int argc, char **argv,
28 void_pfn_smxprocess_t cleanup_func, smx_process_t process);
29 static void smx_ctx_boost_free(smx_context_t context);
31 static void smx_ctx_boost_wrapper(std::intptr_t arg);
33 static void smx_ctx_boost_stop_serial(smx_context_t context);
34 static void smx_ctx_boost_suspend_serial(smx_context_t context);
35 static void smx_ctx_boost_resume_serial(smx_process_t first_process);
36 static void smx_ctx_boost_runall_serial(void);
38 static unsigned long boost_process_index = 0;
39 static boost::context::fcontext_t boost_maestro_fcontext;
40 static smx_ctx_boost_t boost_maestro_context;
42 void SIMIX_ctx_boost_factory_init(smx_context_factory_t *factory)
44 smx_ctx_base_factory_init(factory);
45 XBT_VERB("Activating boost context factory");
47 (*factory)->finalize = smx_ctx_boost_factory_finalize;
48 (*factory)->create_context = smx_ctx_boost_create_context;
49 /* Do not overload that method (*factory)->finalize */
50 (*factory)->free = smx_ctx_boost_free;
51 (*factory)->name = "smx_boost_context_factory";
53 if (SIMIX_context_is_parallel()) {
54 THROWF(arg_error, 0, "No thread support for parallel context execution");
56 (*factory)->stop = smx_ctx_boost_stop_serial;
57 (*factory)->suspend = smx_ctx_boost_suspend_serial;
58 (*factory)->runall = smx_ctx_boost_runall_serial;
62 /* Initialization functions */
64 static int smx_ctx_boost_factory_finalize(smx_context_factory_t *factory)
66 return smx_ctx_base_factory_finalize(factory);
70 smx_ctx_boost_create_context(xbt_main_func_t code, int argc, char **argv,
71 void_pfn_smxprocess_t cleanup_func, smx_process_t process)
73 smx_ctx_boost_t context =
74 (smx_ctx_boost_t) smx_ctx_base_factory_create_context_sized(
75 sizeof(s_smx_ctx_boost_t),
82 /* if the user provided a function for the process then use it,
83 otherwise it is the context for maestro */
85 context->stack = SIMIX_context_stack_new();
86 // We need to pass the bottom of the stack to make_fcontext,
87 // depending on the stack direction it may be the lower or higher address:
88 #if PTH_STACKGROWTH == -1
89 void* stack = (char*) context->stack + smx_context_usable_stack_size - 1;
91 void* stack = context->stack;
93 context->fc = boost::context::make_fcontext(
95 smx_context_usable_stack_size,
96 smx_ctx_boost_wrapper);
97 } else if (process != nullptr && boost_maestro_context == nullptr) {
98 context->stack = nullptr;
99 context->fc = &boost_maestro_fcontext;
100 boost_maestro_context = context;
103 return (smx_context_t) context;
106 static void smx_ctx_boost_free(smx_context_t c)
108 smx_ctx_boost_t context = (smx_ctx_boost_t) c;
111 if ((smx_ctx_boost_t) c == boost_maestro_context)
112 boost_maestro_context = nullptr;
113 SIMIX_context_stack_delete(context->stack);
114 smx_ctx_base_free(c);
117 static void smx_ctx_boost_wrapper(std::intptr_t arg)
119 smx_context_t context = (smx_context_t) arg;
120 context->code(context->argc, context->argv);
121 smx_ctx_boost_stop_serial(context);
124 static void smx_ctx_boost_stop_serial(smx_context_t context)
126 smx_ctx_base_stop(context);
127 simix_global->context_factory->suspend(context);
130 static void smx_ctx_boost_suspend_serial(smx_context_t context)
132 /* determine the next context */
133 smx_ctx_boost_t next_context;
134 unsigned long int i = boost_process_index++;
136 if (i < xbt_dynar_length(simix_global->process_to_run)) {
137 /* execute the next process */
138 XBT_DEBUG("Run next process");
139 next_context = (smx_ctx_boost_t) xbt_dynar_get_as(
140 simix_global->process_to_run, i, smx_process_t)->context;
143 /* all processes were run, return to maestro */
144 XBT_DEBUG("No more process to run");
145 next_context = (smx_ctx_boost_t) boost_maestro_context;
147 SIMIX_context_set_current((smx_context_t) next_context);
148 boost::context::jump_fcontext(
149 ((smx_ctx_boost_t)context)->fc, next_context->fc, (intptr_t)next_context);
152 static void smx_ctx_boost_resume_serial(smx_process_t first_process)
154 smx_ctx_boost_t context = (smx_ctx_boost_t) first_process->context;
155 SIMIX_context_set_current((smx_context_t) context);
156 boost::context::jump_fcontext(boost_maestro_context->fc, context->fc,
160 static void smx_ctx_boost_runall_serial(void)
162 smx_process_t first_process =
163 xbt_dynar_get_as(simix_global->process_to_run, 0, smx_process_t);
164 boost_process_index = 1;
166 /* execute the first process */
167 smx_ctx_boost_resume_serial(first_process);