Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
28f5a9fccdad0c6066c2fb6fdf64b8de38df6fab
[simgrid.git] / src / simix / 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_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
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   *factory = xbt_new0(s_xbt_context_factory_t, 1);
93
94   (*factory)->create_context = xbt_ctx_sysv_factory_create_context;
95   (*factory)->finalize = xbt_ctx_sysv_factory_finalize;
96   (*factory)->create_maestro_context = xbt_ctx_sysv_factory_create_maestro_context;
97   (*factory)->free = xbt_ctx_sysv_free;
98   (*factory)->kill = xbt_ctx_sysv_kill;
99   (*factory)->schedule = xbt_ctx_sysv_schedule;
100   (*factory)->yield = xbt_ctx_sysv_yield;
101   (*factory)->start = xbt_ctx_sysv_start;
102   (*factory)->stop = xbt_ctx_sysv_stop;
103   (*factory)->name = "ctx_sysv_context_factory";
104
105   /* context exception handlers */
106   __xbt_ex_ctx = xbt_ctx_sysv_ex_ctx;
107   __xbt_ex_terminate = xbt_ctx_sysv_ex_terminate;
108 }
109
110 static int
111 xbt_ctx_sysv_factory_create_maestro_context(xbt_context_t * maestro)
112 {
113
114   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
115
116   context->name = (char *) "maestro";
117
118   context->exception = xbt_new(ex_ctx_t, 1);
119   XBT_CTX_INITIALIZE(context->exception);
120
121   *maestro = (xbt_context_t) context;
122
123   return 0;
124
125 }
126
127
128 static int xbt_ctx_sysv_factory_finalize(xbt_context_factory_t * factory)
129 {
130   free(maestro_context->exception);
131   free(*factory);
132   *factory = NULL;
133   return 0;
134 }
135
136 static xbt_context_t
137 xbt_ctx_sysv_factory_create_context(const char *name, xbt_main_func_t code,
138                                     void_f_pvoid_t startup_func,
139                                     void *startup_arg,
140                                     void_f_pvoid_t cleanup_func,
141                                     void *cleanup_arg, int argc, char **argv)
142 {
143   VERB1("Create context %s", name);
144   xbt_ctx_sysv_t context = xbt_new0(s_xbt_ctx_sysv_t, 1);
145
146   context->code = code;
147   context->name = xbt_strdup(name);
148
149   xbt_assert2(getcontext(&(context->uc)) == 0,
150               "Error in context saving: %d (%s)", errno, strerror(errno));
151   context->uc.uc_link = NULL;
152   context->uc.uc_stack.ss_sp =
153     pth_skaddr_makecontext(context->stack, STACK_SIZE);
154   context->uc.uc_stack.ss_size =
155     pth_sksize_makecontext(context->stack, STACK_SIZE);
156 #ifdef HAVE_VALGRIND_VALGRIND_H
157   context->valgrind_stack_id =
158     VALGRIND_STACK_REGISTER(context->uc.uc_stack.ss_sp,
159                             ((char *) context->uc.uc_stack.ss_sp) +
160                             context->uc.uc_stack.ss_size);
161 #endif /* HAVE_VALGRIND_VALGRIND_H */
162
163   context->exception = xbt_new(ex_ctx_t, 1);
164   XBT_CTX_INITIALIZE(context->exception);
165   context->iwannadie = 0;       /* useless but makes valgrind happy */
166   context->argc = argc;
167   context->argv = argv;
168   context->startup_func = startup_func;
169   context->startup_arg = startup_arg;
170   context->cleanup_func = cleanup_func;
171   context->cleanup_arg = cleanup_arg;
172
173   return (xbt_context_t) context;
174 }
175
176 static void xbt_ctx_sysv_free(xbt_context_t context)
177 {
178   if (context) {
179     free(context->name);
180
181     if (context->argv) {
182       int i;
183
184       for (i = 0; i < context->argc; i++)
185         if (context->argv[i])
186           free(context->argv[i]);
187
188       free(context->argv);
189     }
190
191     if (context->exception)
192       free(context->exception);
193
194 #ifdef HAVE_VALGRIND_VALGRIND_H
195     VALGRIND_STACK_DEREGISTER(((xbt_ctx_sysv_t) context)->valgrind_stack_id);
196 #endif /* HAVE_VALGRIND_VALGRIND_H */
197
198     /* finally destroy the context */
199     free(context);
200   }
201 }
202
203 static void xbt_ctx_sysv_kill(xbt_context_t context)
204 {
205   DEBUG2("Kill context '%s' (from '%s')", context->name,
206          current_context->name);
207   context->iwannadie = 1;
208   xbt_ctx_sysv_swap(context);
209 }
210
211 /** 
212  * \param context the winner
213  *
214  * Calling this function blocks the current context and schedule \a context.  
215  * When \a context will call xbt_context_yield, it will return
216  * to this function as if nothing had happened.
217  * 
218  * Only the maestro can call this function to run a given process.
219  */
220 static void xbt_ctx_sysv_schedule(xbt_context_t context)
221 {
222   DEBUG1("Schedule context '%s'", context->name);
223   xbt_assert0((current_context == maestro_context),
224               "You are not supposed to run this function here!");
225   xbt_ctx_sysv_swap(context);
226 }
227
228 /** 
229  * Calling this function makes the current context yield. The context
230  * that scheduled it returns from xbt_context_schedule as if nothing
231  * had happened.
232  * 
233  * Only the processes can call this function, giving back the control
234  * to the maestro
235  */
236 static void xbt_ctx_sysv_yield(void)
237 {
238   DEBUG1("Yielding context '%s'", current_context->name);
239   xbt_assert0((current_context != maestro_context),
240               "You are not supposed to run this function here!");
241   xbt_ctx_sysv_swap(current_context);
242 }
243
244 static void xbt_ctx_sysv_start(xbt_context_t context)
245 {
246   DEBUG1("Start context '%s'", context->name);
247   makecontext(&(((xbt_ctx_sysv_t) context)->uc), xbt_ctx_sysv_wrapper, 0);
248 }
249
250 static void xbt_ctx_sysv_stop(int exit_code)
251 {
252   /* please no debug here: our procdata was already free'd */
253   if (current_context->cleanup_func)
254     ((*current_context->cleanup_func)) (current_context->cleanup_arg);
255
256   xbt_swag_remove(current_context, context_living);
257   xbt_swag_insert(current_context, context_to_destroy);
258
259   xbt_ctx_sysv_swap(current_context);
260 }
261
262 static void xbt_ctx_sysv_swap(xbt_context_t context)
263 {
264   DEBUG2("Swap context: '%s' -> '%s'", current_context->name, context->name);
265   xbt_assert0(current_context, "You have to call context_init() first.");
266   xbt_assert0(context, "Invalid argument");
267
268   if (((xbt_ctx_sysv_t) context)->prev == NULL)
269     xbt_ctx_sysv_resume(context);
270   else
271     xbt_ctx_sysv_suspend(context);
272
273   if (current_context->iwannadie)
274     xbt_ctx_sysv_stop(1);
275 }
276
277 static void xbt_ctx_sysv_wrapper(void)
278 {
279   if (current_context->startup_func)
280     (*current_context->startup_func) (current_context->startup_arg);
281
282   xbt_ctx_sysv_stop((*(current_context->code))
283                     (current_context->argc, current_context->argv));
284 }
285
286 static void xbt_ctx_sysv_suspend(xbt_context_t context)
287 {
288   int rv;
289
290   DEBUG1("Suspend context: '%s'", current_context->name);
291   xbt_ctx_sysv_t prev_context = ((xbt_ctx_sysv_t) context)->prev;
292
293   current_context = (xbt_context_t) (((xbt_ctx_sysv_t) context)->prev);
294
295   ((xbt_ctx_sysv_t) context)->prev = NULL;
296
297   rv = swapcontext(&(((xbt_ctx_sysv_t) context)->uc), &(prev_context->uc));
298
299   xbt_assert0((rv == 0), "Context swapping failure");
300 }
301
302 static void xbt_ctx_sysv_resume(xbt_context_t context)
303 {
304   int rv;
305
306   DEBUG2("Resume context: '%s' (from '%s')", context->name,
307          current_context->name);
308   ((xbt_ctx_sysv_t) context)->prev = (xbt_ctx_sysv_t) current_context;
309
310   current_context = context;
311
312   rv = swapcontext(&(((xbt_ctx_sysv_t) context)->prev->uc),
313                    &(((xbt_ctx_sysv_t) context)->uc));
314
315   xbt_assert0((rv == 0), "Context swapping failure");
316 }