Logo AND Algorithmique Numérique Distribuée

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