Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of scm.gforge.inria.fr:/gitroot/simgrid/simgrid
[simgrid.git] / src / simix / smx_context_boost.cpp
1 /* Copyright (c) 2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
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. */
6
7 /** @file smx_context_boost.cpp Userspace context switching implementation based on Boost.Context */
8
9 #include <cstdint>
10
11 #include <boost/context/all.hpp>
12
13 #include "xbt/log.h"
14 #include "smx_private.h"
15 #include "internal_config.h"
16
17 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(simix_context);
18
19 typedef struct s_smx_ctx_boost {
20   s_smx_ctx_base_t super;       /* Fields of super implementation */
21   boost::context::fcontext_t* fc;
22   void* stack;
23 } s_smx_ctx_boost_t, *smx_ctx_boost_t;
24
25 static int smx_ctx_boost_factory_finalize(smx_context_factory_t *factory);
26 static smx_context_t
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);
30
31 static void smx_ctx_boost_wrapper(std::intptr_t arg);
32
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);
37
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;
41
42 void SIMIX_ctx_boost_factory_init(smx_context_factory_t *factory)
43 {
44   smx_ctx_base_factory_init(factory);
45   XBT_VERB("Activating boost context factory");
46
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";
52
53   if (SIMIX_context_is_parallel()) {
54     THROWF(arg_error, 0, "No thread support for parallel context execution");
55   } else {
56     (*factory)->stop = smx_ctx_boost_stop_serial;
57     (*factory)->suspend = smx_ctx_boost_suspend_serial;
58     (*factory)->runall = smx_ctx_boost_runall_serial;
59   }
60 }
61
62 /* Initialization functions */
63
64 static int smx_ctx_boost_factory_finalize(smx_context_factory_t *factory)
65 {
66   return smx_ctx_base_factory_finalize(factory);
67 }
68
69 static smx_context_t
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)
72 {
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),
76           code,
77           argc,
78           argv,
79           cleanup_func,
80           process);
81
82   /* if the user provided a function for the process then use it,
83      otherwise it is the context for maestro */
84   if (code) {
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;
90 #else
91     void* stack = context->stack;
92 #endif
93    context->fc = boost::context::make_fcontext(
94                       stack,
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;
101   }
102
103   return (smx_context_t) context;
104 }
105
106 static void smx_ctx_boost_free(smx_context_t c)
107 {
108   smx_ctx_boost_t context = (smx_ctx_boost_t) c;
109   if (!context)
110     return;
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);
115 }
116
117 static void smx_ctx_boost_wrapper(std::intptr_t arg)
118 {
119   smx_context_t context = (smx_context_t) arg;
120   context->code(context->argc, context->argv);
121   smx_ctx_boost_stop_serial(context);
122 }
123
124 static void smx_ctx_boost_stop_serial(smx_context_t context)
125 {
126   smx_ctx_base_stop(context);
127   simix_global->context_factory->suspend(context);
128 }
129
130 static void smx_ctx_boost_suspend_serial(smx_context_t context)
131 {
132   /* determine the next context */
133   smx_ctx_boost_t next_context;
134   unsigned long int i = boost_process_index++;
135
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;
141   }
142   else {
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;
146   }
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);
150 }
151
152 static void smx_ctx_boost_resume_serial(smx_process_t first_process)
153 {
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,
157     (intptr_t)context);
158 }
159
160 static void smx_ctx_boost_runall_serial(void)
161 {
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;
165
166   /* execute the first process */
167   smx_ctx_boost_resume_serial(first_process);
168 }