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_thread_context.c
1 \r
2 #include "xbt/function_types.h"\r
3 \r
4 static xbt_context_t \r
5 xbt_thread_context_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
6 \r
7 \r
8 static int\r
9 xbt_thread_context_factory_create_master_context(xbt_context_t* maestro);\r
10 \r
11 static int\r
12 xbt_thread_context_factory_finalize(xbt_context_factory_t* factory);\r
13 \r
14 static void \r
15 xbt_thread_context_free(xbt_context_t context);\r
16 \r
17 static void \r
18 xbt_thread_context_kill(xbt_context_t context);\r
19 \r
20 static void \r
21 xbt_thread_context_schedule(xbt_context_t context);\r
22 \r
23 static void \r
24 xbt_thread_context_yield(void);\r
25 \r
26 static void \r
27 xbt_thread_context_start(xbt_context_t context);\r
28 \r
29 static void \r
30 xbt_thread_context_stop(int exit_code);\r
31 \r
32 static void \r
33 xbt_thread_context_swap(xbt_context_t context);\r
34 \r
35 static void\r
36 xbt_thread_context_schedule(xbt_context_t context);\r
37 \r
38 static void\r
39 xbt_thread_context_yield(void);\r
40 \r
41 static void\r
42 xbt_thread_context_suspend(xbt_context_t context);\r
43 \r
44 static void\r
45 xbt_thread_context_resume(xbt_context_t context);\r
46 \r
47 static void* \r
48 xbt_thread_context_wrapper(void* param);\r
49 \r
50 int\r
51 xbt_thread_context_factory_init(xbt_context_factory_t* factory)\r
52 {\r
53         *factory = xbt_new0(s_xbt_context_factory_t,1);\r
54         \r
55         (*factory)->create_context = xbt_thread_context_factory_create_context;\r
56         (*factory)->finalize = xbt_thread_context_factory_finalize;\r
57         (*factory)->create_maestro_context = xbt_thread_context_factory_create_master_context;\r
58         (*factory)->name = "thread_context_factory";\r
59 \r
60         return 0;\r
61 }\r
62 \r
63 static int\r
64 xbt_thread_context_factory_create_master_context(xbt_context_t* maestro)\r
65 {\r
66         *maestro = (xbt_context_t)xbt_new0(s_xbt_thread_context_t, 1);\r
67     return 0;\r
68 }\r
69 \r
70 static int\r
71 xbt_thread_context_factory_finalize(xbt_context_factory_t* factory)\r
72 {\r
73         free(*factory);\r
74         *factory = NULL;\r
75         return 0;\r
76 }\r
77 \r
78 static xbt_context_t \r
79 xbt_thread_context_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
80 {\r
81         xbt_thread_context_t context = xbt_new0(s_xbt_thread_context_t, 1);\r
82         \r
83         context->code = code;\r
84         context->name = xbt_strdup(name);\r
85         context->begin = xbt_os_sem_init(0);\r
86         context->end = xbt_os_sem_init(0);\r
87         context->iwannadie = 0;           /* useless but makes valgrind happy */\r
88         context->argc = argc;\r
89         context->argv = argv;\r
90         context->startup_func = startup_func;\r
91         context->startup_arg = startup_arg;\r
92         context->cleanup_func = cleanup_func;\r
93         context->cleanup_arg = cleanup_arg;\r
94         \r
95         context->free = xbt_thread_context_free;                        \r
96         context->kill = xbt_thread_context_kill;                        \r
97         context->schedule = xbt_thread_context_schedule;\r
98         context->yield = xbt_thread_context_yield;                      \r
99         context->start = xbt_thread_context_start;                      \r
100         context->stop = xbt_thread_context_stop;                        \r
101         \r
102         return (xbt_context_t)context;\r
103 }\r
104 \r
105 static void \r
106 xbt_thread_context_free(xbt_context_t context)\r
107 {\r
108         if(context)\r
109         {\r
110                 xbt_thread_context_t thread_context = (xbt_thread_context_t)context;\r
111                 \r
112                 free(thread_context->name);\r
113                 \r
114                 if(thread_context->argv)\r
115                 {\r
116                         int i;\r
117                         \r
118                         for(i = 0; i < thread_context->argc; i++)\r
119                                 if(thread_context->argv[i])\r
120                                         free(thread_context->argv[i]);\r
121                                         \r
122                         free(thread_context->argv);\r
123                 }\r
124                 \r
125                 /* wait about the thread terminason */\r
126                 xbt_os_thread_join(thread_context->thread, NULL);\r
127                 \r
128                 /* destroy the synchronisation objects */\r
129                 xbt_os_sem_destroy(thread_context->begin);\r
130                 xbt_os_sem_destroy(thread_context->end);\r
131                 \r
132                 /* finally destroy the context */\r
133                 free(context);\r
134         }\r
135 }\r
136 \r
137 static void \r
138 xbt_thread_context_kill(xbt_context_t context)\r
139 {\r
140         context->iwannadie = 1;\r
141         xbt_thread_context_swap(context);\r
142 }\r
143 \r
144 /** \r
145  * \param context the winner\r
146  *\r
147  * Calling this function blocks the current context and schedule \a context.  \r
148  * When \a context will call xbt_context_yield, it will return\r
149  * to this function as if nothing had happened.\r
150  * \r
151  * Only the maestro can call this function to run a given process.\r
152  */\r
153 static void \r
154 xbt_thread_context_schedule(xbt_context_t context)\r
155 {\r
156         xbt_assert0((current_context == maestro_context),"You are not supposed to run this function here!");\r
157         xbt_thread_context_swap(context);\r
158 }\r
159 \r
160 /** \r
161  * Calling this function makes the current context yield. The context\r
162  * that scheduled it returns from xbt_context_schedule as if nothing\r
163  * had happened.\r
164  * \r
165  * Only the processes can call this function, giving back the control\r
166  * to the maestro\r
167  */\r
168 static void \r
169 xbt_thread_context_yield(void)\r
170 {\r
171         xbt_assert0((current_context != maestro_context),"You are not supposed to run this function here!");\r
172         xbt_thread_context_swap(current_context);\r
173 }\r
174 \r
175 static void \r
176 xbt_thread_context_start(xbt_context_t context)\r
177 {\r
178         xbt_thread_context_t thread_context = (xbt_thread_context_t)context;\r
179         \r
180         /* create and start the process */\r
181         thread_context->thread = xbt_os_thread_create(thread_context->name,xbt_thread_context_wrapper,thread_context);\r
182         \r
183         /* wait the starting of the newly created process */\r
184         xbt_os_sem_acquire(thread_context->end);\r
185 }\r
186 \r
187 static void \r
188 xbt_thread_context_stop(int exit_code)\r
189 {\r
190         if(current_context->cleanup_func) \r
191                 ((*current_context->cleanup_func))(current_context->cleanup_arg);\r
192         \r
193         xbt_swag_remove(current_context, context_living);\r
194         xbt_swag_insert(current_context, context_to_destroy);   \r
195 \r
196         /* signal to the maestro that it has finished */\r
197         xbt_os_sem_release(((xbt_thread_context_t)current_context)->end);\r
198         \r
199         /* exit*/\r
200         xbt_os_thread_exit(NULL);       /* We should provide return value in case other wants it */\r
201 }\r
202 \r
203 static void \r
204 xbt_thread_context_swap(xbt_context_t context)\r
205 {\r
206         if((current_context != maestro_context) && !context->iwannadie)\r
207         {\r
208                 /* (0) it's not the scheduler and the process doesn't want to die, it just wants to yield */\r
209                 \r
210                 /* yield itself, resume the maestro */\r
211                 xbt_thread_context_suspend(context);\r
212         }\r
213         else\r
214         {\r
215                 /* (1) the current process is the scheduler and the process doesn't want to die\r
216                  *      <-> the maestro wants to schedule the process\r
217                  *              -> the maestro schedules the process and waits\r
218                  *\r
219                  * (2) the current process is the scheduler and the process wants to die\r
220                  *      <-> the maestro wants to kill the process (has called the function xbt_context_kill())\r
221                  *              -> the maestro schedule the process and waits (xbt_os_sem_acquire(context->end))\r
222                  *              -> if the process stops (xbt_context_stop())\r
223                  *                      -> the process resumes the maestro (xbt_os_sem_release(current_context->end)) and exit (xbt_os_thread_exit())\r
224                  *              -> else the process call xbt_context_yield()\r
225                  *                      -> goto (3.1)\r
226                  *\r
227                  * (3) the current process is not the scheduler and the process wants to die\r
228                  *              -> (3.1) if the current process is the process who wants to die\r
229                  *                      -> (resume not need) goto (4)\r
230                  *              -> (3.2) else the current process is not the process who wants to die\r
231                  *                      <-> the current process wants to kill an other process\r
232                  *                              -> the current process resumes the process to die and waits\r
233                  *                              -> if the process to kill stops\r
234                  *                                      -> it resumes the process who kill it and exit\r
235                  *                              -> else if the process to kill calls to xbt_context_yield()\r
236                  *                                      -> goto (3.1)\r
237                  */\r
238                 /* schedule the process associated with this context */\r
239                 xbt_thread_context_resume(context);\r
240         \r
241         }\r
242         \r
243         /* (4) the current process wants to die */\r
244         if(current_context->iwannadie)\r
245                 xbt_thread_context_stop(1);\r
246 }\r
247 \r
248 static void* \r
249 xbt_thread_context_wrapper(void* param)\r
250 {\r
251         xbt_thread_context_t context = (xbt_thread_context_t)param;\r
252         \r
253         /* signal its starting to the maestro and wait to start its job*/\r
254         xbt_os_sem_release(context->end);               \r
255         xbt_os_sem_acquire(context->begin);\r
256         \r
257         if (context->startup_func)\r
258                 (*(context->startup_func))(context->startup_arg);\r
259         \r
260         \r
261         xbt_thread_context_stop((context->code) (context->argc, context->argv));\r
262         return NULL;\r
263 }\r
264 \r
265 static void\r
266 xbt_thread_context_suspend(xbt_context_t context)\r
267 {\r
268         /* save the current context */\r
269         xbt_context_t self = current_context;\r
270         \r
271         /* update the current context to this context */\r
272         current_context = context;\r
273         \r
274         xbt_os_sem_release(((xbt_thread_context_t)context)->end);       \r
275         xbt_os_sem_acquire(((xbt_thread_context_t)context)->begin);\r
276         \r
277         /* restore the current context to the previously saved context */\r
278         current_context = self;         \r
279 }\r
280 \r
281 static void\r
282 xbt_thread_context_resume(xbt_context_t context)\r
283 {\r
284         /* save the current context */\r
285         xbt_context_t self = current_context;\r
286         \r
287         /* update the current context */\r
288         current_context = context;\r
289         \r
290         xbt_os_sem_release(((xbt_thread_context_t)context)->begin);             \r
291         xbt_os_sem_acquire(((xbt_thread_context_t)context)->end);\r
292         \r
293         /* restore the current context to the previously saved context */\r
294         current_context = self;\r
295 }\r
296 \r
297 \r
298 \r