Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Some more debug output to understand the gras/empty_main bug
[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 XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(xbt_context);
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 static void xbt_ctx_sysv_kill(xbt_context_t context);
54 static void xbt_ctx_sysv_schedule(xbt_context_t context);
55 static void xbt_ctx_sysv_yield(void);
56 static void xbt_ctx_sysv_start(xbt_context_t context);
57 static void xbt_ctx_sysv_stop(int exit_code);
58 static void xbt_ctx_sysv_swap(xbt_context_t context);
59 static void xbt_ctx_sysv_schedule(xbt_context_t context);
60 static void xbt_ctx_sysv_yield(void);
61 static void xbt_ctx_sysv_suspend(xbt_context_t context);
62 static void xbt_ctx_sysv_resume(xbt_context_t context);
63 static void xbt_ctx_sysv_wrapper(void);
64
65 /* callback: context fetching */
66 static ex_ctx_t *xbt_ctx_sysv_ex_ctx(void)
67 {
68   return current_context->exception;
69 }
70
71 /* callback: termination */
72 static void xbt_ctx_sysv_ex_terminate(xbt_ex_t * e)
73 {
74   xbt_ex_display(e);
75   abort();
76 }
77
78
79 void xbt_ctx_sysv_factory_init(xbt_context_factory_t * factory)
80 {
81   /* context exception */
82   *factory = xbt_new0(s_xbt_context_factory_t, 1);
83
84   (*factory)->create_context = xbt_ctx_sysv_factory_create_context;
85   (*factory)->finalize = xbt_ctx_sysv_factory_finalize;
86   (*factory)->create_maestro_context =
87     xbt_ctx_sysv_factory_create_maestro_context;
88   (*factory)->name = "ctx_sysv_context_factory";
89
90   /* context exception handlers */
91   __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
92   __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
93 }
94
95 static int
96 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro)
97 {
98
99   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
100   context->name = (char*)"maestro";
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   VERB1("Create context %s",name);
128   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
129
130   context->code = code;
131   context->name = xbt_strdup(name);
132
133   xbt_assert2(getcontext(&(context->uc)) == 0,
134               "Error in context saving: %d (%s)", errno, strerror(errno));
135   context->uc.uc_link = NULL;
136   context->uc.uc_stack.ss_sp =
137     pth_skaddr_makecontext(context->stack, STACK_SIZE);
138   context->uc.uc_stack.ss_size =
139     pth_sksize_makecontext(context->stack, STACK_SIZE);
140   #ifdef HAVE_VALGRIND_VALGRIND_H
141   context->valgrind_stack_id = VALGRIND_STACK_REGISTER(
142     context->uc.uc_stack.ss_sp,
143     ((char *)context->uc.uc_stack.ss_sp) + context->uc.uc_stack.ss_size
144   );
145   #endif     /* HAVE_VALGRIND_VALGRIND_H */
146
147   context->exception = xbt_new(ex_ctx_t, 1);
148   XBT_CTX_INITIALIZE(context->exception);
149   context->iwannadie = 0;       /* useless but makes valgrind happy */
150   context->argc = argc;
151   context->argv = argv;
152   context->startup_func = startup_func;
153   context->startup_arg = startup_arg;
154   context->cleanup_func = cleanup_func;
155   context->cleanup_arg = cleanup_arg;
156
157
158   context->free = xbt_ctx_sysv_free;
159   context->kill = xbt_ctx_sysv_kill;
160   context->schedule = xbt_ctx_sysv_schedule;
161   context->yield = xbt_ctx_sysv_yield;
162   context->start = xbt_ctx_sysv_start;
163   context->stop = xbt_ctx_sysv_stop;
164
165   return (xbt_context_t) context;
166 }
167
168 static void xbt_ctx_sysv_free(xbt_context_t context)
169 {
170   if (context) {
171     free(context->name);
172
173     if (context->argv) {
174       int i;
175
176       for (i = 0; i < context->argc; i++)
177         if (context->argv[i])
178           free(context->argv[i]);
179
180       free(context->argv);
181     }
182
183     if (context->exception)
184       free(context->exception);
185
186     #ifdef HAVE_VALGRIND_VALGRIND_H
187       VALGRIND_STACK_DEREGISTER(((xbt_ctx_sysv_t)context)->valgrind_stack_id);
188     #endif     /* HAVE_VALGRIND_VALGRIND_H */
189
190     /* finally destroy the context */
191     free(context);
192   }
193 }
194
195 static void xbt_ctx_sysv_kill(xbt_context_t context)
196 {
197   DEBUG2("Kill context '%s' (from '%s')",context->name,current_context->name);
198   context->iwannadie = 1;
199   xbt_ctx_sysv_swap(context);
200 }
201
202 /** 
203  * \param context the winner
204  *
205  * Calling this function blocks the current context and schedule \a context.  
206  * When \a context will call xbt_context_yield, it will return
207  * to this function as if nothing had happened.
208  * 
209  * Only the maestro can call this function to run a given process.
210  */
211 static void xbt_ctx_sysv_schedule(xbt_context_t context)
212 {
213   DEBUG1("Schedule context '%s'",context->name);
214   xbt_assert0((current_context == maestro_context),
215               "You are not supposed to run this function here!");
216   xbt_ctx_sysv_swap(context);
217 }
218
219 /** 
220  * Calling this function makes the current context yield. The context
221  * that scheduled it returns from xbt_context_schedule as if nothing
222  * had happened.
223  * 
224  * Only the processes can call this function, giving back the control
225  * to the maestro
226  */
227 static void xbt_ctx_sysv_yield(void)
228 {
229   DEBUG1("Yielding context '%s'",current_context->name);
230   xbt_assert0((current_context != maestro_context),
231               "You are not supposed to run this function here!");
232   xbt_ctx_sysv_swap(current_context);
233 }
234
235 static void xbt_ctx_sysv_start(xbt_context_t context)
236 {
237   DEBUG1("Start context '%s'",context->name);
238   makecontext(&(((xbt_ctx_sysv_t) context)->uc), xbt_ctx_sysv_wrapper, 0);
239 }
240
241 static void xbt_ctx_sysv_stop(int exit_code)
242 {
243   /* please no debug here: our procdata was already free'd */
244   if (current_context->cleanup_func)
245     ((*current_context->cleanup_func)) (current_context->cleanup_arg);
246
247   xbt_swag_remove(current_context, context_living);
248   xbt_swag_insert(current_context, context_to_destroy);
249
250   xbt_ctx_sysv_swap(current_context);
251 }
252
253 static void xbt_ctx_sysv_swap(xbt_context_t context)
254 {
255   DEBUG2("Swap context: '%s' -> '%s'",current_context->name,context->name);
256   xbt_assert0(current_context, "You have to call context_init() first.");
257   xbt_assert0(context, "Invalid argument");
258
259   if (((xbt_ctx_sysv_t) context)->prev == NULL)
260     xbt_ctx_sysv_resume(context);
261   else
262     xbt_ctx_sysv_suspend(context);
263
264   if (current_context->iwannadie)
265     xbt_ctx_sysv_stop(1);
266 }
267
268 static void xbt_ctx_sysv_wrapper(void)
269 {
270   if (current_context->startup_func)
271     (*current_context->startup_func) (current_context->startup_arg);
272
273   xbt_ctx_sysv_stop((*(current_context->code))
274                     (current_context->argc, current_context->argv));
275 }
276
277 static void xbt_ctx_sysv_suspend(xbt_context_t context)
278 {
279   int rv;
280
281   DEBUG1("Suspend context: '%s'",current_context->name);
282   xbt_ctx_sysv_t prev_context = ((xbt_ctx_sysv_t) context)->prev;
283
284   current_context = (xbt_context_t) (((xbt_ctx_sysv_t) context)->prev);
285
286   ((xbt_ctx_sysv_t) context)->prev = NULL;
287
288   rv = swapcontext(&(((xbt_ctx_sysv_t) context)->uc), &(prev_context->uc));
289
290   xbt_assert0((rv == 0), "Context swapping failure");
291 }
292
293 static void xbt_ctx_sysv_resume(xbt_context_t context)
294 {
295   int rv;
296
297   DEBUG2("Resume context: '%s' (from '%s')",context->name,current_context->name);
298   ((xbt_ctx_sysv_t) context)->prev = (xbt_ctx_sysv_t) current_context;
299
300   current_context = context;
301
302   rv =
303     swapcontext(&(((xbt_ctx_sysv_t) context)->prev->uc),
304                 &(((xbt_ctx_sysv_t) context)->uc));
305
306   xbt_assert0((rv == 0), "Context swapping failure");
307 }