2 #include "xbt/function_types.h"
\r
3 #include "xbt/xbt_context_private.h"
\r
5 #include "portable.h" /* loads context system definitions */
\r
6 #include "xbt/swag.h"
\r
7 #include "xbt/xbt_os_thread.h"
\r
10 typedef struct s_xbt_ctx_thread {
\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
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
22 xbt_ctx_thread_factory_create_master_context(xbt_context_t* maestro);
\r
25 xbt_ctx_thread_factory_finalize(xbt_context_factory_t* factory);
\r
28 xbt_ctx_thread_free(xbt_context_t context);
\r
31 xbt_ctx_thread_kill(xbt_context_t context);
\r
34 xbt_ctx_thread_schedule(xbt_context_t context);
\r
37 xbt_ctx_thread_yield(void);
\r
40 xbt_ctx_thread_start(xbt_context_t context);
\r
43 xbt_ctx_thread_stop(int exit_code);
\r
46 xbt_ctx_thread_swap(xbt_context_t context);
\r
49 xbt_ctx_thread_schedule(xbt_context_t context);
\r
52 xbt_ctx_thread_yield(void);
\r
55 xbt_ctx_thread_suspend(xbt_context_t context);
\r
58 xbt_ctx_thread_resume(xbt_context_t context);
\r
61 xbt_ctx_thread_wrapper(void* param);
\r
64 xbt_ctx_thread_factory_init(xbt_context_factory_t* factory)
\r
66 *factory = xbt_new0(s_xbt_context_factory_t,1);
\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
75 xbt_ctx_thread_factory_create_master_context(xbt_context_t* maestro)
\r
77 *maestro = (xbt_context_t)xbt_new0(s_xbt_ctx_thread_t, 1);
\r
82 xbt_ctx_thread_factory_finalize(xbt_context_factory_t* factory)
\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
92 xbt_ctx_thread_t context = xbt_new0(s_xbt_ctx_thread_t, 1);
\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
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
113 return (xbt_context_t)context;
\r
117 xbt_ctx_thread_free(xbt_context_t context)
\r
121 xbt_ctx_thread_t ctx_thread = (xbt_ctx_thread_t)context;
\r
123 free(ctx_thread->name);
\r
125 if(ctx_thread->argv)
\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
133 free(ctx_thread->argv);
\r
136 /* wait about the thread terminason */
\r
137 xbt_os_thread_join(ctx_thread->thread, NULL);
\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
143 /* finally destroy the context */
\r
149 xbt_ctx_thread_kill(xbt_context_t context)
\r
151 context->iwannadie = 1;
\r
152 xbt_ctx_thread_swap(context);
\r
156 * \param context the winner
\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
162 * Only the maestro can call this function to run a given process.
\r
165 xbt_ctx_thread_schedule(xbt_context_t context)
\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
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
176 * Only the processes can call this function, giving back the control
\r
180 xbt_ctx_thread_yield(void)
\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
187 xbt_ctx_thread_start(xbt_context_t context)
\r
189 xbt_ctx_thread_t ctx_thread = (xbt_ctx_thread_t)context;
\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
194 /* wait the starting of the newly created process */
\r
195 xbt_os_sem_acquire(ctx_thread->end);
\r
199 xbt_ctx_thread_stop(int exit_code)
\r
201 if(current_context->cleanup_func)
\r
202 ((*current_context->cleanup_func))(current_context->cleanup_arg);
\r
204 xbt_swag_remove(current_context, context_living);
\r
205 xbt_swag_insert(current_context, context_to_destroy);
\r
207 /* signal to the maestro that it has finished */
\r
208 xbt_os_sem_release(((xbt_ctx_thread_t)current_context)->end);
\r
211 xbt_os_thread_exit(NULL); /* We should provide return value in case other wants it */
\r
215 xbt_ctx_thread_swap(xbt_context_t context)
\r
217 if((current_context != maestro_context) && !context->iwannadie)
\r
219 /* (0) it's not the scheduler and the process doesn't want to die, it just wants to yield */
\r
221 /* yield itself, resume the maestro */
\r
222 xbt_ctx_thread_suspend(context);
\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
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
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
249 /* schedule the process associated with this context */
\r
250 xbt_ctx_thread_resume(context);
\r
254 /* (4) the current process wants to die */
\r
255 if(current_context->iwannadie)
\r
256 xbt_ctx_thread_stop(1);
\r
260 xbt_ctx_thread_wrapper(void* param)
\r
262 xbt_ctx_thread_t context = (xbt_ctx_thread_t)param;
\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
268 if (context->startup_func)
\r
269 (*(context->startup_func))(context->startup_arg);
\r
272 xbt_ctx_thread_stop((context->code) (context->argc, context->argv));
\r
277 xbt_ctx_thread_suspend(xbt_context_t context)
\r
279 /* save the current context */
\r
280 xbt_context_t self = current_context;
\r
282 /* update the current context to this context */
\r
283 current_context = context;
\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
288 /* restore the current context to the previously saved context */
\r
289 current_context = self;
\r
293 xbt_ctx_thread_resume(xbt_context_t context)
\r
295 /* save the current context */
\r
296 xbt_context_t self = current_context;
\r
298 /* update the current context */
\r
299 current_context = context;
\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
304 /* restore the current context to the previously saved context */
\r
305 current_context = self;
\r