Logo AND Algorithmique Numérique Distribuée

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