Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Make sure all the source files have an reference of the copyright and of the licence
[simgrid.git] / src / xbt / xbt_context_sysv.c
1 /* $Id$ */
2
3 /* context_sysv - implementation of context switching with ucontextes from Sys V */
4
5 /* Copyright (c) 2004-2008 the SimGrid team. All right reserved */
6
7 /* This program is free software; you can redistribute it and/or modify it
8  * under the terms of the license (GNU LGPL) which comes with this package. */
9
10 #include "xbt/ex_interface.h"
11 #include "xbt/xbt_context_private.h"
12
13 #include "context_sysv_config.h"        /* loads context system definitions                             */
14 #include "portable.h"
15 #include <ucontext.h>           /* context relative declarations                                */
16 #define STACK_SIZE 128*1024     /* lower this if you want to reduce the memory consumption      */
17 #ifdef HAVE_VALGRIND_VALGRIND_H
18 #  include <valgrind/valgrind.h>
19 #endif     /* HAVE_VALGRIND_VALGRIND_H */
20
21
22
23 typedef struct s_xbt_ctx_sysv {
24   XBT_CTX_BASE_T;
25   ucontext_t uc;                    /* the thread that execute the code                             */
26   char stack[STACK_SIZE];           /* the thread stack size                                        */
27   struct s_xbt_ctx_sysv *prev;      /* the previous thread                                              */
28 #ifdef HAVE_VALGRIND_VALGRIND_H
29   unsigned int valgrind_stack_id;   /* the valgrind stack id.       */
30 #endif /* HAVE_VALGRIND_VALGRIND_H */
31 } s_xbt_ctx_sysv_t, *xbt_ctx_sysv_t;
32
33
34 /* callback: context fetching */
35 static ex_ctx_t *xbt_jcontext_ex_ctx(void);
36
37 /* callback: termination */
38 static void xbt_jcontext_ex_terminate(xbt_ex_t * e);
39
40 static xbt_context_t
41 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
42                                     void_f_pvoid_t startup_func,
43                                     void *startup_arg,
44                                     void_f_pvoid_t cleanup_func,
45                                     void *cleanup_arg, int argc, char **argv);
46
47 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory);
48
49 static int
50 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro);
51
52 static void xbt_ctx_sysv_free(xbt_context_t context);
53
54 static void xbt_ctx_sysv_kill(xbt_context_t context);
55
56 static void xbt_ctx_sysv_schedule(xbt_context_t context);
57
58 static void xbt_ctx_sysv_yield(void);
59
60 static void xbt_ctx_sysv_start(xbt_context_t context);
61
62 static void xbt_ctx_sysv_stop(int exit_code);
63
64 static void xbt_ctx_sysv_swap(xbt_context_t context);
65
66 static void xbt_ctx_sysv_schedule(xbt_context_t context);
67
68 static void xbt_ctx_sysv_yield(void);
69
70 static void xbt_ctx_sysv_suspend(xbt_context_t context);
71
72 static void xbt_ctx_sysv_resume(xbt_context_t context);
73
74 static void xbt_ctx_sysv_wrapper(void);
75
76 /* callback: context fetching */
77 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
78 {
79   return current_context->exception;
80 }
81
82 /* callback: termination */
83 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
84 {
85   xbt_ex_display(e);
86   abort();
87 }
88
89
90 void xbt_ctx_sysv_factory_init(xbt_context_factory_t * factory)
91 {
92   /* context exception */
93   *factory = xbt_new0(s_xbt_context_factory_t, 1);
94
95   (*factory)->create_context = xbt_ctx_sysv_factory_create_context;
96   (*factory)->finalize = xbt_ctx_sysv_factory_finalize;
97   (*factory)->create_maestro_context =
98     xbt_ctx_sysv_factory_create_maestro_context;
99   (*factory)->name = "ctx_sysv_context_factory";
100
101   /* context exception handlers */
102   __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
103   __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
104 }
105
106 static int
107 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro)
108 {
109
110   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
111
112   context->exception = xbt_new(ex_ctx_t, 1);
113   XBT_CTX_INITIALIZE(context->exception);
114
115   *maestro = (xbt_context_t) context;
116
117   return 0;
118
119 }
120
121
122 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory)
123 {
124   free(maestro_context->exception);
125   free(*factory);
126   *factory = NULL;
127   return 0;
128 }
129
130 static xbt_context_t
131 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
132                                     void_f_pvoid_t startup_func,
133                                     void *startup_arg,
134                                     void_f_pvoid_t cleanup_func,
135                                     void *cleanup_arg, int argc, char **argv)
136 {
137   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
138
139   context->code = code;
140   context->name = xbt_strdup(name);
141
142   xbt_assert2(getcontext(&(context->uc)) == 0,
143               "Error in context saving: %d (%s)", errno, strerror(errno));
144   context->uc.uc_link = NULL;
145   context->uc.uc_stack.ss_sp =
146     pth_skaddr_makecontext(context->stack, STACK_SIZE);
147   context->uc.uc_stack.ss_size =
148     pth_sksize_makecontext(context->stack, STACK_SIZE);
149   #ifdef HAVE_VALGRIND_VALGRIND_H
150   context->valgrind_stack_id = VALGRIND_STACK_REGISTER(
151     context->uc.uc_stack.ss_sp,
152     ((char *)context->uc.uc_stack.ss_sp) + context->uc.uc_stack.ss_size
153   );
154   #endif     /* HAVE_VALGRIND_VALGRIND_H */
155
156   context->exception = xbt_new(ex_ctx_t, 1);
157   XBT_CTX_INITIALIZE(context->exception);
158   context->iwannadie = 0;       /* useless but makes valgrind happy */
159   context->argc = argc;
160   context->argv = argv;
161   context->startup_func = startup_func;
162   context->startup_arg = startup_arg;
163   context->cleanup_func = cleanup_func;
164   context->cleanup_arg = cleanup_arg;
165
166
167   context->free = xbt_ctx_sysv_free;
168   context->kill = xbt_ctx_sysv_kill;
169   context->schedule = xbt_ctx_sysv_schedule;
170   context->yield = xbt_ctx_sysv_yield;
171   context->start = xbt_ctx_sysv_start;
172   context->stop = xbt_ctx_sysv_stop;
173
174   return (xbt_context_t) context;
175 }
176
177 static void xbt_ctx_sysv_free(xbt_context_t context)
178 {
179   if (context) {
180     free(context->name);
181
182     if (context->argv) {
183       int i;
184
185       for (i = 0; i < context->argc; i++)
186         if (context->argv[i])
187           free(context->argv[i]);
188
189       free(context->argv);
190     }
191
192     if (context->exception)
193       free(context->exception);
194
195     #ifdef HAVE_VALGRIND_VALGRIND_H
196       VALGRIND_STACK_DEREGISTER(((xbt_ctx_sysv_t)context)->valgrind_stack_id);
197     #endif     /* HAVE_VALGRIND_VALGRIND_H */
198
199     /* finally destroy the context */
200     free(context);
201   }
202 }
203
204 static void xbt_ctx_sysv_kill(xbt_context_t context)
205 {
206   context->iwannadie = 1;
207   xbt_ctx_sysv_swap(context);
208 }
209
210 /** 
211  * \param context the winner
212  *
213  * Calling this function blocks the current context and schedule \a context.  
214  * When \a context will call xbt_context_yield, it will return
215  * to this function as if nothing had happened.
216  * 
217  * Only the maestro can call this function to run a given process.
218  */
219 static void xbt_ctx_sysv_schedule(xbt_context_t context)
220 {
221   xbt_assert0((current_context == maestro_context),
222               "You are not supposed to run this function here!");
223   xbt_ctx_sysv_swap(context);
224 }
225
226 /** 
227  * Calling this function makes the current context yield. The context
228  * that scheduled it returns from xbt_context_schedule as if nothing
229  * had happened.
230  * 
231  * Only the processes can call this function, giving back the control
232  * to the maestro
233  */
234 static void xbt_ctx_sysv_yield(void)
235 {
236   xbt_assert0((current_context != maestro_context),
237               "You are not supposed to run this function here!");
238   xbt_ctx_sysv_swap(current_context);
239 }
240
241 static void xbt_ctx_sysv_start(xbt_context_t context)
242 {
243   makecontext(&(((xbt_ctx_sysv_t) context)->uc), xbt_ctx_sysv_wrapper, 0);
244 }
245
246 static void xbt_ctx_sysv_stop(int exit_code)
247 {
248   if (current_context->cleanup_func)
249     ((*current_context->cleanup_func)) (current_context->cleanup_arg);
250
251   xbt_swag_remove(current_context, context_living);
252   xbt_swag_insert(current_context, context_to_destroy);
253
254   xbt_ctx_sysv_swap(current_context);
255 }
256
257 static void xbt_ctx_sysv_swap(xbt_context_t context)
258 {
259   xbt_assert0(current_context, "You have to call context_init() first.");
260   xbt_assert0(context, "Invalid argument");
261
262   if (((xbt_ctx_sysv_t) context)->prev == NULL)
263     xbt_ctx_sysv_resume(context);
264   else
265     xbt_ctx_sysv_suspend(context);
266
267   if (current_context->iwannadie)
268     xbt_ctx_sysv_stop(1);
269 }
270
271 static void xbt_ctx_sysv_wrapper(void)
272 {
273   if (current_context->startup_func)
274     (*current_context->startup_func) (current_context->startup_arg);
275
276   xbt_ctx_sysv_stop((*(current_context->code))
277                     (current_context->argc, current_context->argv));
278 }
279
280 static void xbt_ctx_sysv_suspend(xbt_context_t context)
281 {
282   int rv;
283
284   xbt_ctx_sysv_t prev_context = ((xbt_ctx_sysv_t) context)->prev;
285
286   current_context = (xbt_context_t) (((xbt_ctx_sysv_t) context)->prev);
287
288   ((xbt_ctx_sysv_t) context)->prev = NULL;
289
290   rv = swapcontext(&(((xbt_ctx_sysv_t) context)->uc), &(prev_context->uc));
291
292   xbt_assert0((rv == 0), "Context swapping failure");
293 }
294
295 static void xbt_ctx_sysv_resume(xbt_context_t context)
296 {
297   int rv;
298
299   ((xbt_ctx_sysv_t) context)->prev = (xbt_ctx_sysv_t) current_context;
300
301   current_context = context;
302
303   rv =
304     swapcontext(&(((xbt_ctx_sysv_t) context)->prev->uc),
305                 &(((xbt_ctx_sysv_t) context)->uc));
306
307   xbt_assert0((rv == 0), "Context swapping failure");
308 }