2 #include "xbt/ex_interface.h"
3 #include "xbt/xbt_context_private.h"
5 #include "context_sysv_config.h" /* loads context system definitions */
7 #include <ucontext.h> /* context relative declarations */
8 #define STACK_SIZE 128*1024 /* lower this if you want to reduce the memory consumption */
9 #ifdef HAVE_VALGRIND_VALGRIND_H
10 # include <valgrind/valgrind.h>
11 #endif /* HAVE_VALGRIND_VALGRIND_H */
13 typedef struct s_xbt_ctx_sysv {
15 ucontext_t uc; /* the thread that execute the code */
16 char stack[STACK_SIZE]; /* the thread stack size */
17 struct s_xbt_ctx_sysv *prev; /* the previous thread */
18 #ifdef HAVE_VALGRIND_VALGRIND_H
19 unsigned int valgrind_stack_id; /* the valgrind stack id. */
20 #endif /* HAVE_VALGRIND_VALGRIND_H */
21 } s_xbt_ctx_sysv_t, *xbt_ctx_sysv_t;
24 /* callback: context fetching */
25 static ex_ctx_t *xbt_jcontext_ex_ctx(void);
27 /* callback: termination */
28 static void xbt_jcontext_ex_terminate(xbt_ex_t * e);
31 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
32 void_f_pvoid_t startup_func,
34 void_f_pvoid_t cleanup_func,
35 void *cleanup_arg, int argc, char **argv);
37 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory);
40 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro);
42 static void xbt_ctx_sysv_free(xbt_context_t context);
44 static void xbt_ctx_sysv_kill(xbt_context_t context);
46 static void xbt_ctx_sysv_schedule(xbt_context_t context);
48 static void xbt_ctx_sysv_yield(void);
50 static void xbt_ctx_sysv_start(xbt_context_t context);
52 static void xbt_ctx_sysv_stop(int exit_code);
54 static void xbt_ctx_sysv_swap(xbt_context_t context);
56 static void xbt_ctx_sysv_schedule(xbt_context_t context);
58 static void xbt_ctx_sysv_yield(void);
60 static void xbt_ctx_sysv_suspend(xbt_context_t context);
62 static void xbt_ctx_sysv_resume(xbt_context_t context);
64 static void xbt_ctx_sysv_wrapper(void);
66 /* callback: context fetching */
67 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
69 return current_context->exception;
72 /* callback: termination */
73 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
80 void xbt_ctx_sysv_factory_init(xbt_context_factory_t * factory)
82 /* context exception */
83 *factory = xbt_new0(s_xbt_context_factory_t, 1);
85 (*factory)->create_context = xbt_ctx_sysv_factory_create_context;
86 (*factory)->finalize = xbt_ctx_sysv_factory_finalize;
87 (*factory)->create_maestro_context =
88 xbt_ctx_sysv_factory_create_maestro_context;
89 (*factory)->name = "ctx_sysv_context_factory";
91 /* context exception handlers */
92 __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
93 __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
97 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro)
100 xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
102 context->exception = xbt_new(ex_ctx_t, 1);
103 XBT_CTX_INITIALIZE(context->exception);
105 *maestro = (xbt_context_t) context;
112 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory)
114 free(maestro_context->exception);
121 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
122 void_f_pvoid_t startup_func,
124 void_f_pvoid_t cleanup_func,
125 void *cleanup_arg, int argc, char **argv)
127 xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
129 context->code = code;
130 context->name = xbt_strdup(name);
132 xbt_assert2(getcontext(&(context->uc)) == 0,
133 "Error in context saving: %d (%s)", errno, strerror(errno));
134 context->uc.uc_link = NULL;
135 context->uc.uc_stack.ss_sp =
136 pth_skaddr_makecontext(context->stack, STACK_SIZE);
137 context->uc.uc_stack.ss_size =
138 pth_sksize_makecontext(context->stack, STACK_SIZE);
139 #ifdef HAVE_VALGRIND_VALGRIND_H
140 context->valgrind_stack_id = VALGRIND_STACK_REGISTER(
141 context->uc.uc_stack.ss_sp,
142 ((char *)context->uc.uc_stack.ss_sp) + context->uc.uc_stack.ss_size
144 #endif /* HAVE_VALGRIND_VALGRIND_H */
146 context->exception = xbt_new(ex_ctx_t, 1);
147 XBT_CTX_INITIALIZE(context->exception);
148 context->iwannadie = 0; /* useless but makes valgrind happy */
149 context->argc = argc;
150 context->argv = argv;
151 context->startup_func = startup_func;
152 context->startup_arg = startup_arg;
153 context->cleanup_func = cleanup_func;
154 context->cleanup_arg = cleanup_arg;
157 context->free = xbt_ctx_sysv_free;
158 context->kill = xbt_ctx_sysv_kill;
159 context->schedule = xbt_ctx_sysv_schedule;
160 context->yield = xbt_ctx_sysv_yield;
161 context->start = xbt_ctx_sysv_start;
162 context->stop = xbt_ctx_sysv_stop;
164 return (xbt_context_t) context;
167 static void xbt_ctx_sysv_free(xbt_context_t context)
175 for (i = 0; i < context->argc; i++)
176 if (context->argv[i])
177 free(context->argv[i]);
182 if (context->exception)
183 free(context->exception);
185 #ifdef HAVE_VALGRIND_VALGRIND_H
186 VALGRIND_STACK_DEREGISTER(((xbt_ctx_sysv_t)context)->valgrind_stack_id);
187 #endif /* HAVE_VALGRIND_VALGRIND_H */
189 /* finally destroy the context */
194 static void xbt_ctx_sysv_kill(xbt_context_t context)
196 context->iwannadie = 1;
197 xbt_ctx_sysv_swap(context);
201 * \param context the winner
203 * Calling this function blocks the current context and schedule \a context.
204 * When \a context will call xbt_context_yield, it will return
205 * to this function as if nothing had happened.
207 * Only the maestro can call this function to run a given process.
209 static void xbt_ctx_sysv_schedule(xbt_context_t context)
211 xbt_assert0((current_context == maestro_context),
212 "You are not supposed to run this function here!");
213 xbt_ctx_sysv_swap(context);
217 * Calling this function makes the current context yield. The context
218 * that scheduled it returns from xbt_context_schedule as if nothing
221 * Only the processes can call this function, giving back the control
224 static void xbt_ctx_sysv_yield(void)
226 xbt_assert0((current_context != maestro_context),
227 "You are not supposed to run this function here!");
228 xbt_ctx_sysv_swap(current_context);
231 static void xbt_ctx_sysv_start(xbt_context_t context)
233 makecontext(&(((xbt_ctx_sysv_t) context)->uc), xbt_ctx_sysv_wrapper, 0);
236 static void xbt_ctx_sysv_stop(int exit_code)
238 if (current_context->cleanup_func)
239 ((*current_context->cleanup_func)) (current_context->cleanup_arg);
241 xbt_swag_remove(current_context, context_living);
242 xbt_swag_insert(current_context, context_to_destroy);
244 xbt_ctx_sysv_swap(current_context);
247 static void xbt_ctx_sysv_swap(xbt_context_t context)
249 xbt_assert0(current_context, "You have to call context_init() first.");
250 xbt_assert0(context, "Invalid argument");
252 if (((xbt_ctx_sysv_t) context)->prev == NULL)
253 xbt_ctx_sysv_resume(context);
255 xbt_ctx_sysv_suspend(context);
257 if (current_context->iwannadie)
258 xbt_ctx_sysv_stop(1);
261 static void xbt_ctx_sysv_wrapper(void)
263 if (current_context->startup_func)
264 (*current_context->startup_func) (current_context->startup_arg);
266 xbt_ctx_sysv_stop((*(current_context->code))
267 (current_context->argc, current_context->argv));
270 static void xbt_ctx_sysv_suspend(xbt_context_t context)
274 xbt_ctx_sysv_t prev_context = ((xbt_ctx_sysv_t) context)->prev;
276 current_context = (xbt_context_t) (((xbt_ctx_sysv_t) context)->prev);
278 ((xbt_ctx_sysv_t) context)->prev = NULL;
280 rv = swapcontext(&(((xbt_ctx_sysv_t) context)->uc), &(prev_context->uc));
282 xbt_assert0((rv == 0), "Context swapping failure");
285 static void xbt_ctx_sysv_resume(xbt_context_t context)
289 ((xbt_ctx_sysv_t) context)->prev = (xbt_ctx_sysv_t) current_context;
291 current_context = context;
294 swapcontext(&(((xbt_ctx_sysv_t) context)->prev->uc),
295 &(((xbt_ctx_sysv_t) context)->uc));
297 xbt_assert0((rv == 0), "Context swapping failure");