2 #include "ucontext_stack.h"
\r
3 #include "xbt/ex_interface.h"
\r
4 #include "xbt/xbt_context_factory.h"
\r
6 #include "ucontext_stack.h" /* loads context system definitions */
\r
7 #include <ucontext.h> /* context relative declarations */
\r
8 #define STACK_SIZE 128*1024 /* lower this if you want to reduce the memory consumption */
\r
10 typedef struct s_xbt_ucontext {
\r
12 ucontext_t uc; /* the thread that execute the code */
\r
13 char stack[STACK_SIZE]; /* the thread stack size */
\r
14 struct s_xbt_ucontext* prev; /* the previous thread */
\r
15 } s_xbt_ucontext_t,* xbt_ucontext_t;
\r
18 /* callback: context fetching */
\r
20 xbt_jcontext_ex_ctx(void);
\r
22 /* callback: termination */
\r
24 xbt_jcontext_ex_terminate(xbt_ex_t *e);
\r
26 static xbt_context_t
\r
27 xbt_ucontext_factory_create_context(const char* name, xbt_main_func_t code, void_f_pvoid_t startup_func, void* startup_arg, void_f_pvoid_t cleanup_func, void* cleanup_arg, int argc, char** argv);
\r
30 xbt_ucontext_factory_finalize(xbt_context_factory_t* factory);
\r
33 xbt_ucontext_factory_create_maestro_context(xbt_context_t* maestro);
\r
36 xbt_ucontext_free(xbt_context_t context);
\r
39 xbt_ucontext_kill(xbt_context_t context);
\r
42 xbt_ucontext_schedule(xbt_context_t context);
\r
45 xbt_ucontext_yield(void);
\r
48 xbt_ucontext_start(xbt_context_t context);
\r
51 xbt_ucontext_stop(int exit_code);
\r
54 xbt_ucontext_swap(xbt_context_t context);
\r
57 xbt_ucontext_schedule(xbt_context_t context);
\r
60 xbt_ucontext_yield(void);
\r
63 xbt_ucontext_suspend(xbt_context_t context);
\r
66 xbt_ucontext_resume(xbt_context_t context);
\r
69 xbt_ucontext_wrapper(void* param);
\r
71 /* callback: context fetching */
\r
73 xbt_ucontext_ex_ctx(void)
\r
75 return current_context->exception;
\r
78 /* callback: termination */
\r
80 xbt_ucontext_ex_terminate(xbt_ex_t *e)
\r
88 xbt_ucontext_factory_init(xbt_context_factory_t* factory)
\r
90 /* context exception */
\r
91 *factory = xbt_new0(s_xbt_context_factory_t,1);
\r
93 (*factory)->create_context = xbt_ucontext_factory_create_context;
\r
94 (*factory)->finalize = xbt_ucontext_factory_finalize;
\r
95 (*factory)->create_maestro_context = xbt_ucontext_factory_create_maestro_context;
\r
96 (*factory)->name = "ucontext_context_factory";
\r
98 /* context exception handlers */
\r
99 __xbt_ex_ctx = xbt_ucontext_ex_ctx;
\r
100 __xbt_ex_terminate = xbt_ucontext_ex_terminate;
\r
106 xbt_ucontext_factory_create_maestro_context(xbt_context_t* maestro)
\r
109 xbt_ucontext_t context = xbt_new0(s_xbt_ucontext_t, 1);
\r
111 context->exception = xbt_new(ex_ctx_t,1);
\r
112 XBT_CTX_INITIALIZE(context->exception);
\r
114 *maestro = (xbt_context_t)context;
\r
122 xbt_ucontext_factory_finalize(xbt_context_factory_t* factory)
\r
124 free(maestro_context->exception);
\r
130 static xbt_context_t
\r
131 xbt_ucontext_factory_create_context(const char* name, xbt_main_func_t code, void_f_pvoid_t startup_func, void* startup_arg, void_f_pvoid_t cleanup_func, void* cleanup_arg, int argc, char** argv)
\r
133 xbt_ucontext_t context = xbt_new0(s_xbt_ucontext_t, 1);
\r
135 context->code = code;
\r
136 context->name = xbt_strdup(name);
\r
138 xbt_assert2(getcontext(&(context->uc)) == 0,"Error in context saving: %d (%s)", errno, strerror(errno));
\r
139 context->uc.uc_link = NULL;
\r
140 context->uc.uc_stack.ss_sp = pth_skaddr_makecontext(context->stack, STACK_SIZE);
\r
141 context->uc.uc_stack.ss_size = pth_sksize_makecontext(context->stack, STACK_SIZE);
\r
143 context->exception = xbt_new(ex_ctx_t, 1);
\r
144 XBT_CTX_INITIALIZE(context->exception);
\r
145 context->iwannadie = 0; /* useless but makes valgrind happy */
\r
146 context->argc = argc;
\r
147 context->argv = argv;
\r
148 context->startup_func = startup_func;
\r
149 context->startup_arg = startup_arg;
\r
150 context->cleanup_func = cleanup_func;
\r
151 context->cleanup_arg = cleanup_arg;
\r
154 context->free = xbt_ucontext_free;
\r
155 context->kill = xbt_ucontext_kill;
\r
156 context->schedule = xbt_ucontext_schedule;
\r
157 context->yield = xbt_ucontext_yield;
\r
158 context->start = xbt_ucontext_start;
\r
159 context->stop = xbt_ucontext_stop;
\r
161 return (xbt_context_t)context;
\r
165 xbt_ucontext_free(xbt_context_t context)
\r
169 free(context->name);
\r
175 for(i = 0; i < context->argc; i++)
\r
176 if(context->argv[i])
\r
177 free(context->argv[i]);
\r
179 free(context->argv);
\r
182 if(context->exception)
\r
183 free(context->exception);
\r
185 /* finally destroy the context */
\r
191 xbt_ucontext_kill(xbt_context_t context)
\r
193 context->iwannadie = 1;
\r
194 xbt_ucontext_swap(context);
\r
198 * \param context the winner
\r
200 * Calling this function blocks the current context and schedule \a context.
\r
201 * When \a context will call xbt_context_yield, it will return
\r
202 * to this function as if nothing had happened.
\r
204 * Only the maestro can call this function to run a given process.
\r
207 xbt_ucontext_schedule(xbt_context_t context)
\r
209 xbt_assert0((current_context == maestro_context),"You are not supposed to run this function here!");
\r
210 xbt_ucontext_swap(context);
\r
214 * Calling this function makes the current context yield. The context
\r
215 * that scheduled it returns from xbt_context_schedule as if nothing
\r
218 * Only the processes can call this function, giving back the control
\r
222 xbt_ucontext_yield(void)
\r
224 xbt_assert0((current_context != maestro_context),"You are not supposed to run this function here!");
\r
225 xbt_ucontext_swap(current_context);
\r
229 xbt_ucontext_start(xbt_context_t context)
\r
231 makecontext(&(((xbt_ucontext_t)context)->uc), (void (*)(void)) xbt_ucontext_wrapper, 1, context);
\r
235 xbt_ucontext_stop(int exit_code)
\r
237 if(current_context->cleanup_func)
\r
238 ((*current_context->cleanup_func))(current_context->cleanup_arg);
\r
240 xbt_swag_remove(current_context, context_living);
\r
241 xbt_swag_insert(current_context, context_to_destroy);
\r
243 xbt_ucontext_swap(current_context);
\r
247 xbt_ucontext_swap(xbt_context_t context)
\r
249 xbt_assert0(current_context, "You have to call context_init() first.");
\r
250 xbt_assert0(context, "Invalid argument");
\r
252 if(((xbt_ucontext_t)context)->prev == NULL)
\r
253 xbt_ucontext_resume(context);
\r
255 xbt_ucontext_suspend(context);
\r
257 if(current_context->iwannadie)
\r
258 xbt_ucontext_stop(1);
\r
262 xbt_ucontext_wrapper(void* param)
\r
264 if (current_context->startup_func)
\r
265 (*current_context->startup_func)(current_context->startup_arg);
\r
267 xbt_ucontext_stop((*(current_context->code))(current_context->argc, current_context->argv));
\r
272 xbt_ucontext_suspend(xbt_context_t context)
\r
276 xbt_ucontext_t prev_context = ((xbt_ucontext_t)context)->prev;
\r
278 current_context = (xbt_context_t)(((xbt_ucontext_t)context)->prev);
\r
280 ((xbt_ucontext_t)context)->prev = NULL;
\r
282 rv = swapcontext(&(((xbt_ucontext_t)context)->uc), &(prev_context->uc));
\r
284 xbt_assert0((rv == 0), "Context swapping failure");
\r
288 xbt_ucontext_resume(xbt_context_t context)
\r
292 ((xbt_ucontext_t)context)->prev = (xbt_ucontext_t)current_context;
\r
294 current_context = context;
\r
296 rv = swapcontext(&(((xbt_ucontext_t)context)->prev->uc), &(((xbt_ucontext_t)context)->uc));
\r
298 xbt_assert0((rv == 0), "Context swapping failure");
\r