Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Inform valgrind about ucontextes [S├ękou Diakite]
[simgrid.git] / src / xbt / xbt_context_sysv.c
1
2 #include "xbt/ex_interface.h"
3 #include "xbt/xbt_context_private.h"
4
5 #include "context_sysv_config.h"        /* loads context system definitions                             */
6 #include "portable.h"
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 */
12
13 typedef struct s_xbt_ctx_sysv {
14   XBT_CTX_BASE_T;
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;
22
23
24 /* callback: context fetching */
25 static ex_ctx_t *xbt_jcontext_ex_ctx(void);
26
27 /* callback: termination */
28 static void xbt_jcontext_ex_terminate(xbt_ex_t * e);
29
30 static xbt_context_t
31 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
32                                     void_f_pvoid_t startup_func,
33                                     void *startup_arg,
34                                     void_f_pvoid_t cleanup_func,
35                                     void *cleanup_arg, int argc, char **argv);
36
37 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory);
38
39 static int
40 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro);
41
42 static void xbt_ctx_sysv_free(xbt_context_t context);
43
44 static void xbt_ctx_sysv_kill(xbt_context_t context);
45
46 static void xbt_ctx_sysv_schedule(xbt_context_t context);
47
48 static void xbt_ctx_sysv_yield(void);
49
50 static void xbt_ctx_sysv_start(xbt_context_t context);
51
52 static void xbt_ctx_sysv_stop(int exit_code);
53
54 static void xbt_ctx_sysv_swap(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_suspend(xbt_context_t context);
61
62 static void xbt_ctx_sysv_resume(xbt_context_t context);
63
64 static void xbt_ctx_sysv_wrapper(void);
65
66 /* callback: context fetching */
67 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
68 {
69   return current_context->exception;
70 }
71
72 /* callback: termination */
73 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
74 {
75   xbt_ex_display(e);
76   abort();
77 }
78
79
80 void xbt_ctx_sysv_factory_init(xbt_context_factory_t * factory)
81 {
82   /* context exception */
83   *factory = xbt_new0(s_xbt_context_factory_t, 1);
84
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";
90
91   /* context exception handlers */
92   __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
93   __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
94 }
95
96 static int
97 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro)
98 {
99
100   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
101
102   context->exception = xbt_new(ex_ctx_t, 1);
103   XBT_CTX_INITIALIZE(context->exception);
104
105   *maestro = (xbt_context_t) context;
106
107   return 0;
108
109 }
110
111
112 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory)
113 {
114   free(maestro_context->exception);
115   free(*factory);
116   *factory = NULL;
117   return 0;
118 }
119
120 static xbt_context_t
121 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
122                                     void_f_pvoid_t startup_func,
123                                     void *startup_arg,
124                                     void_f_pvoid_t cleanup_func,
125                                     void *cleanup_arg, int argc, char **argv)
126 {
127   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
128
129   context->code = code;
130   context->name = xbt_strdup(name);
131
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
143   );
144   #endif     /* HAVE_VALGRIND_VALGRIND_H */
145
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;
155
156
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;
163
164   return (xbt_context_t) context;
165 }
166
167 static void xbt_ctx_sysv_free(xbt_context_t context)
168 {
169   if (context) {
170     free(context->name);
171
172     if (context->argv) {
173       int i;
174
175       for (i = 0; i < context->argc; i++)
176         if (context->argv[i])
177           free(context->argv[i]);
178
179       free(context->argv);
180     }
181
182     if (context->exception)
183       free(context->exception);
184
185     #ifdef HAVE_VALGRIND_VALGRIND_H
186       VALGRIND_STACK_DEREGISTER(((xbt_ctx_sysv_t)context)->valgrind_stack_id);
187     #endif     /* HAVE_VALGRIND_VALGRIND_H */
188
189     /* finally destroy the context */
190     free(context);
191   }
192 }
193
194 static void xbt_ctx_sysv_kill(xbt_context_t context)
195 {
196   context->iwannadie = 1;
197   xbt_ctx_sysv_swap(context);
198 }
199
200 /** 
201  * \param context the winner
202  *
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.
206  * 
207  * Only the maestro can call this function to run a given process.
208  */
209 static void xbt_ctx_sysv_schedule(xbt_context_t context)
210 {
211   xbt_assert0((current_context == maestro_context),
212               "You are not supposed to run this function here!");
213   xbt_ctx_sysv_swap(context);
214 }
215
216 /** 
217  * Calling this function makes the current context yield. The context
218  * that scheduled it returns from xbt_context_schedule as if nothing
219  * had happened.
220  * 
221  * Only the processes can call this function, giving back the control
222  * to the maestro
223  */
224 static void xbt_ctx_sysv_yield(void)
225 {
226   xbt_assert0((current_context != maestro_context),
227               "You are not supposed to run this function here!");
228   xbt_ctx_sysv_swap(current_context);
229 }
230
231 static void xbt_ctx_sysv_start(xbt_context_t context)
232 {
233   makecontext(&(((xbt_ctx_sysv_t) context)->uc), xbt_ctx_sysv_wrapper, 0);
234 }
235
236 static void xbt_ctx_sysv_stop(int exit_code)
237 {
238   if (current_context->cleanup_func)
239     ((*current_context->cleanup_func)) (current_context->cleanup_arg);
240
241   xbt_swag_remove(current_context, context_living);
242   xbt_swag_insert(current_context, context_to_destroy);
243
244   xbt_ctx_sysv_swap(current_context);
245 }
246
247 static void xbt_ctx_sysv_swap(xbt_context_t context)
248 {
249   xbt_assert0(current_context, "You have to call context_init() first.");
250   xbt_assert0(context, "Invalid argument");
251
252   if (((xbt_ctx_sysv_t) context)->prev == NULL)
253     xbt_ctx_sysv_resume(context);
254   else
255     xbt_ctx_sysv_suspend(context);
256
257   if (current_context->iwannadie)
258     xbt_ctx_sysv_stop(1);
259 }
260
261 static void xbt_ctx_sysv_wrapper(void)
262 {
263   if (current_context->startup_func)
264     (*current_context->startup_func) (current_context->startup_arg);
265
266   xbt_ctx_sysv_stop((*(current_context->code))
267                     (current_context->argc, current_context->argv));
268 }
269
270 static void xbt_ctx_sysv_suspend(xbt_context_t context)
271 {
272   int rv;
273
274   xbt_ctx_sysv_t prev_context = ((xbt_ctx_sysv_t) context)->prev;
275
276   current_context = (xbt_context_t) (((xbt_ctx_sysv_t) context)->prev);
277
278   ((xbt_ctx_sysv_t) context)->prev = NULL;
279
280   rv = swapcontext(&(((xbt_ctx_sysv_t) context)->uc), &(prev_context->uc));
281
282   xbt_assert0((rv == 0), "Context swapping failure");
283 }
284
285 static void xbt_ctx_sysv_resume(xbt_context_t context)
286 {
287   int rv;
288
289   ((xbt_ctx_sysv_t) context)->prev = (xbt_ctx_sysv_t) current_context;
290
291   current_context = context;
292
293   rv =
294     swapcontext(&(((xbt_ctx_sysv_t) context)->prev->uc),
295                 &(((xbt_ctx_sysv_t) context)->uc));
296
297   xbt_assert0((rv == 0), "Context swapping failure");
298 }