Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
The file containing the new implementation of the switch context mechanism.
[simgrid.git] / src / xbt / xbt_context.c
1 /* a fast and simple context switching library                              */\r
2 \r
3 /* Copyright (c) 2004 Arnaud Legrand.                                       */\r
4 /* Copyright (c) 2004, 2005 Martin Quinson.                                 */\r
5 /* All rights reserved.                                                     */\r
6 \r
7 /* This program is free software; you can redistribute it and/or modify it\r
8  * under the terms of the license (GNU LGPL) which comes with this package. */\r
9 \r
10 #include "portable.h"\r
11 #include "xbt/log.h"\r
12 #include "xbt/swag.h"\r
13 #include "xbt_context_factory.h"\r
14 \r
15 /* the context associated with the current process                              */\r
16 static xbt_context_t \r
17 current_context = NULL;\r
18 \r
19 /* the context associated with the maestro                                              */\r
20 static xbt_context_t \r
21 maestro_context = NULL;\r
22 \r
23 \r
24 /* this list contains the contexts to destroy                                   */\r
25 static xbt_swag_t \r
26 context_to_destroy = NULL;\r
27 \r
28 /* this list contains the contexts in use                                               */\r
29 static xbt_swag_t \r
30 context_living = NULL;\r
31 \r
32 /* the context factory used to create the appropriate context   \r
33  * each context implementation define its own context factory\r
34  * a context factory is responsable of the creation of the context\r
35  * associated with the maestro and of all the context based on\r
36  * the selected implementation.\r
37  *\r
38  * for example, the context switch based on java thread use the\r
39  * java implementation of the context and the java factory build\r
40  * the context depending of this implementation.\r
41  */\r
42 static xbt_context_factory_t\r
43 context_factory = NULL;\r
44 \r
45 /* java implementation of the context */\r
46 #include "xbt_jcontext.c"\r
47 \r
48 #ifdef CONTEXT_THREADS\r
49 /* use the native thread implementation of the context */\r
50 #include "xbt_thread_context.c"\r
51 #elif !defined(WIN32)\r
52 /* use the ucontext     based context           */\r
53 #  include "xbt_ucontext.c" \r
54 #endif \r
55 \r
56 \r
57 /**\r
58  * This function is call by the xbt_init() function to initialize the context module.\r
59  */\r
60 void\r
61 xbt_context_mod_init(void)\r
62 {\r
63         if(!context_factory)\r
64         {\r
65                 /* select context factory to use to create the context(depends of the macro definitions) */\r
66 \r
67                 #ifdef CONTEXT_THREADS\r
68                         /* context switch based os thread */\r
69                         xbt_thread_context_factory_init(&context_factory);\r
70                 #elif !defined(WIN32)\r
71                         /* context switch based ucontext */\r
72                         xbt_ucontext_factory_init(&context_factory);\r
73                 #else\r
74                         /* context switch is not allowed on Windows */\r
75                         #error ERROR [__FILE__, line __LINE__]: no context based implementation specified.\r
76                 #endif\r
77                 \r
78                 /* maestro context specialisation (this create the maestro with the good implementation */\r
79                 (*(context_factory->create_maestro_context))(&maestro_context);\r
80                 \r
81                 /* the current context is the context of the maestro */\r
82                 current_context = maestro_context;\r
83                 \r
84                 /* the current context doesn't want to die */\r
85                 current_context->iwannadie = 0;\r
86                 \r
87                 /* intantiation of the lists containing the contexts to destroy and the contexts in use */  \r
88                 context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
89                 context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
90                 \r
91                 /* insert the current context in the list of the contexts in use */\r
92                 xbt_swag_insert(current_context, context_living);\r
93                 \r
94         }                \r
95\r
96 \r
97 /**\r
98  * This function is call by the xbt_exit() function to finalize the context module.\r
99  */\r
100 void\r
101 xbt_context_mod_exit(void)\r
102 {\r
103         if(context_factory)\r
104         {\r
105                 xbt_context_t context = NULL;\r
106                 xbt_pfn_context_factory_finalize_t finalize_factory;\r
107                 \r
108                 /* finalize the context factory */\r
109                 finalize_factory = context_factory->finalize;\r
110                 \r
111                 (*finalize_factory)(&context_factory);\r
112                 \r
113                 /* destroy all contexts in the list of contexts to destroy */\r
114                 xbt_context_empty_trash();\r
115                 \r
116                 /* remove the context of the scheduler from the list of the contexts in use */\r
117                 xbt_swag_remove(maestro_context, context_living);\r
118                 \r
119                 free(maestro_context);\r
120                 maestro_context = current_context = NULL;\r
121                 \r
122                 /*  \r
123                  * kill all the contexts in use :\r
124                  * the killed contexts are added in the list of the contexts to destroy\r
125                  */\r
126                 while((context = xbt_swag_extract(context_living))) \r
127                                 (*(context->kill))(context);    \r
128         \r
129                 \r
130                 /* destroy all contexts in the list of contexts to destroy */\r
131                 xbt_context_empty_trash();\r
132                 \r
133                 /* destroy the lists */\r
134                 xbt_swag_free(context_to_destroy);\r
135                 xbt_swag_free(context_living);\r
136         }\r
137 }\r
138 \r
139 /*******************************/\r
140 /* Object creation/destruction */\r
141 /*******************************/\r
142 /** \r
143  * \param code a main function\r
144  * \param startup_func a function to call when running the context for\r
145  *      the first time and just before the main function \a code\r
146  * \param startup_arg the argument passed to the previous function (\a startup_func)\r
147  * \param cleanup_func a function to call when running the context, just after \r
148         the termination of the main function \a code\r
149  * \param cleanup_arg the argument passed to the previous function (\a cleanup_func)\r
150  * \param argc first argument of function \a code\r
151  * \param argv seconde argument of function \a code\r
152  */\r
153 xbt_context_t\r
154 xbt_context_new(const char *name,\r
155                 xbt_main_func_t code,\r
156                 void_f_pvoid_t startup_func,\r
157                 void *startup_arg,\r
158                 void_f_pvoid_t cleanup_func,\r
159                 void *cleanup_arg, int argc, char *argv[]\r
160 )\r
161 {\r
162         /* use the appropriate context factory to create the appropriate context */\r
163         xbt_context_t context = (*(context_factory->create_context))(name, code, startup_func, startup_arg, cleanup_func, cleanup_arg, argc, argv);\r
164         \r
165         /* add the context in the list of the contexts in use */\r
166         xbt_swag_insert(context, context_living);\r
167 \r
168         return context;\r
169 }\r
170 \r
171 /* Scenario for the end of a context:\r
172  * \r
173  * CASE 1: death after end of function\r
174  *   __context_wrapper, called by os thread, calls xbt_context_stop after user code stops\r
175  *   xbt_context_stop calls user cleanup_func if any (in context settings),\r
176  *                    add current to trashbin\r
177  *                    yields back to maestro (destroy os thread on need)\r
178  *   From time to time, maestro calls xbt_context_empty_trash, \r
179  *       which maps xbt_context_free on the content\r
180  *   xbt_context_free frees some more memory, \r
181  *                    joins os thread\r
182  * \r
183  * CASE 2: brutal death\r
184  *   xbt_context_kill (from any context)\r
185  *                    set context->wannadie to 1\r
186  *                    yields to the context\r
187  *   the context is awaken in the middle of __yield. \r
188  *   At the end of it, it checks that wannadie == 1, and call xbt_context_stop\r
189  *   (same than first case afterward)\r
190  */\r
191 \r
192 \r
193 /* Argument must be stopped first -- runs in maestro context */\r
194 void\r
195 xbt_context_free(xbt_context_t context)\r
196 {\r
197         (*(context->free))(context);    \r
198 }\r
199 \r
200 \r
201 void\r
202 xbt_context_kill(xbt_context_t context)\r
203 {\r
204         (*(context->kill))(context);    \r
205 }\r
206 \r
207 /** \r
208  * \param context the context to start\r
209  * \r
210  * Calling this function prepares \a context to be run. It will \r
211    however run effectively only when calling #xbt_context_schedule\r
212  */\r
213 void\r
214 xbt_context_start(xbt_context_t context)\r
215 {\r
216         (*(context->start))(context);\r
217 }\r
218 \r
219 /** \r
220  * Calling this function makes the current context yield. The context\r
221  * that scheduled it returns from xbt_context_schedule as if nothing\r
222  * had happened.\r
223  * \r
224  * Only the processes can call this function, giving back the control\r
225  * to the maestro\r
226  */\r
227 void\r
228 xbt_context_yield(void)\r
229 {\r
230         (*(current_context->yield))();  \r
231 }\r
232 \r
233 /** \r
234  * \param context the winner\r
235  *\r
236  * Calling this function blocks the current context and schedule \a context.  \r
237  * When \a context will call xbt_context_yield, it will return\r
238  * to this function as if nothing had happened.\r
239  * \r
240  * Only the maestro can call this function to run a given process.\r
241  */\r
242 void\r
243 xbt_context_schedule(xbt_context_t context)\r
244 {\r
245         (*(context->schedule))(context);        \r
246 }\r
247 \r
248 void\r
249 xbt_context_stop(int exit_code)\r
250 {\r
251 \r
252         (*(current_context->stop))(exit_code);\r
253 }\r
254 \r
255 int\r
256 xbt_context_select_factory(const char* name)\r
257 {\r
258         /* if a factory is already instantiated (xbt_context_mod_init() was called) */\r
259         if(NULL != context_factory)\r
260         {\r
261                 /* if the desired factory is different of the current factory, call xbt_context_mod_exit() */\r
262                 if(strcmp(context_factory->name,name))\r
263                 {\r
264                         xbt_context_mod_exit();\r
265                                 \r
266                 }\r
267                 else\r
268                 {\r
269                         /* the same context factory is requested return directly */\r
270                         return 0;\r
271                 }\r
272         }\r
273         \r
274         /* get the desired factory */\r
275         xbt_context_init_factory_by_name(&context_factory,name);\r
276         \r
277         /* maestro context specialisation */\r
278         (*(context_factory->create_maestro_context))(&maestro_context);\r
279         \r
280         /* the current context is the context of the maestro */\r
281         current_context = maestro_context;\r
282         \r
283         /* the current context doesn't want to die */\r
284         current_context->iwannadie = 0;\r
285         \r
286         /* intantiation of the lists containing the contexts to destroy and the contexts in use */  \r
287         context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
288         context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));\r
289         \r
290         /* insert the current context in the list of the contexts in use */\r
291         xbt_swag_insert(current_context, context_living);       \r
292         \r
293         return 0;       \r
294 }\r
295 \r
296 int\r
297 xbt_context_init_factory_by_name(xbt_context_factory_t* factory, const char* name)\r
298 {\r
299         if(!strcmp(name,"jcontext_factory"))\r
300         {\r
301                 return xbt_jcontext_factory_init(factory);      \r
302         }\r
303         #ifdef CONTEXT_THREADS\r
304         else if(!strcmp(name,"thread_context_factory")) \r
305         {\r
306                 return xbt_thread_context_factory_init(factory);        \r
307         }\r
308         #elif !defined(WIN32)\r
309         else if(!strcmp(name,"ucontext_context_factory"))       \r
310         {\r
311                 return xbt_ucontext_factory_init(factory);      \r
312         }\r
313         #endif\r
314         \r
315         return EINVAL;\r
316 }\r
317 \r
318 /** Garbage collection\r
319  *\r
320  * Should be called some time to time to free the memory allocated for contexts\r
321  * that have finished executing their main functions.\r
322  */\r
323 void \r
324 xbt_context_empty_trash(void)\r
325 {\r
326         xbt_context_t context = NULL;\r
327         \r
328         while((context = xbt_swag_extract(context_to_destroy)))\r
329                 (*(context->free))(context);\r
330 }\r
331 \r
332 \r
333 \r