Logo AND Algorithmique Numérique Distribuée

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