Logo AND Algorithmique Numérique Distribuée

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