Logo AND Algorithmique Numérique Distribuée

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