2 #include "xbt/function_types.h"
3 #include "xbt/xbt_context_private.h"
5 #include "portable.h" /* loads context system definitions */
7 #include "xbt/xbt_os_thread.h"
10 typedef struct s_xbt_ctx_thread {
12 xbt_os_thread_t thread; /* a plain dumb thread (portable to posix or windows) */
13 xbt_os_sem_t begin; /* this semaphore is used to schedule/yield the process */
14 xbt_os_sem_t end; /* this semaphore is used to schedule/unschedule the process */
15 } s_xbt_ctx_thread_t, *xbt_ctx_thread_t;
18 xbt_ctx_thread_factory_create_context(const char *name, xbt_main_func_t code,
19 void_f_pvoid_t startup_func,
21 void_f_pvoid_t cleanup_func,
22 void *cleanup_arg, int argc,
27 xbt_ctx_thread_factory_create_master_context(xbt_context_t * maestro);
29 static int xbt_ctx_thread_factory_finalize(xbt_context_factory_t * factory);
31 static void xbt_ctx_thread_free(xbt_context_t context);
33 static void xbt_ctx_thread_kill(xbt_context_t context);
35 static void xbt_ctx_thread_schedule(xbt_context_t context);
37 static void xbt_ctx_thread_yield(void);
39 static void xbt_ctx_thread_start(xbt_context_t context);
41 static void xbt_ctx_thread_stop(int exit_code);
43 static void xbt_ctx_thread_swap(xbt_context_t context);
45 static void xbt_ctx_thread_schedule(xbt_context_t context);
47 static void xbt_ctx_thread_yield(void);
49 static void xbt_ctx_thread_suspend(xbt_context_t context);
51 static void xbt_ctx_thread_resume(xbt_context_t context);
53 static void *xbt_ctx_thread_wrapper(void *param);
55 void xbt_ctx_thread_factory_init(xbt_context_factory_t * factory)
57 *factory = xbt_new0(s_xbt_context_factory_t, 1);
59 (*factory)->create_context = xbt_ctx_thread_factory_create_context;
60 (*factory)->finalize = xbt_ctx_thread_factory_finalize;
61 (*factory)->create_maestro_context =
62 xbt_ctx_thread_factory_create_master_context;
63 (*factory)->name = "ctx_thread_factory";
67 xbt_ctx_thread_factory_create_master_context(xbt_context_t * maestro)
69 *maestro = (xbt_context_t) xbt_new0(s_xbt_ctx_thread_t, 1);
73 static int xbt_ctx_thread_factory_finalize(xbt_context_factory_t * factory)
81 xbt_ctx_thread_factory_create_context(const char *name, xbt_main_func_t code,
82 void_f_pvoid_t startup_func,
84 void_f_pvoid_t cleanup_func,
85 void *cleanup_arg, int argc,
88 xbt_ctx_thread_t context = xbt_new0(s_xbt_ctx_thread_t, 1);
91 context->name = xbt_strdup(name);
92 context->begin = xbt_os_sem_init(0);
93 context->end = xbt_os_sem_init(0);
94 context->iwannadie = 0; /* useless but makes valgrind happy */
97 context->startup_func = startup_func;
98 context->startup_arg = startup_arg;
99 context->cleanup_func = cleanup_func;
100 context->cleanup_arg = cleanup_arg;
102 context->free = xbt_ctx_thread_free;
103 context->kill = xbt_ctx_thread_kill;
104 context->schedule = xbt_ctx_thread_schedule;
105 context->yield = xbt_ctx_thread_yield;
106 context->start = xbt_ctx_thread_start;
107 context->stop = xbt_ctx_thread_stop;
109 return (xbt_context_t) context;
112 static void xbt_ctx_thread_free(xbt_context_t context)
115 xbt_ctx_thread_t ctx_thread = (xbt_ctx_thread_t) context;
117 free(ctx_thread->name);
119 if (ctx_thread->argv) {
122 for (i = 0; i < ctx_thread->argc; i++)
123 if (ctx_thread->argv[i])
124 free(ctx_thread->argv[i]);
126 free(ctx_thread->argv);
129 /* wait about the thread terminason */
130 xbt_os_thread_join(ctx_thread->thread, NULL);
132 /* destroy the synchronisation objects */
133 xbt_os_sem_destroy(ctx_thread->begin);
134 xbt_os_sem_destroy(ctx_thread->end);
136 /* finally destroy the context */
141 static void xbt_ctx_thread_kill(xbt_context_t context)
143 context->iwannadie = 1;
144 xbt_ctx_thread_swap(context);
148 * \param context the winner
150 * Calling this function blocks the current context and schedule \a context.
151 * When \a context will call xbt_context_yield, it will return
152 * to this function as if nothing had happened.
154 * Only the maestro can call this function to run a given process.
156 static void xbt_ctx_thread_schedule(xbt_context_t context)
158 xbt_assert0((current_context == maestro_context),
159 "You are not supposed to run this function here!");
160 xbt_ctx_thread_swap(context);
164 * Calling this function makes the current context yield. The context
165 * that scheduled it returns from xbt_context_schedule as if nothing
168 * Only the processes can call this function, giving back the control
171 static void xbt_ctx_thread_yield(void)
173 xbt_assert0((current_context != maestro_context),
174 "You are not supposed to run this function here!");
175 xbt_ctx_thread_swap(current_context);
178 static void xbt_ctx_thread_start(xbt_context_t context)
180 xbt_ctx_thread_t ctx_thread = (xbt_ctx_thread_t) context;
182 /* create and start the process */
184 xbt_os_thread_create(ctx_thread->name, xbt_ctx_thread_wrapper,
187 /* wait the starting of the newly created process */
188 xbt_os_sem_acquire(ctx_thread->end);
191 static void xbt_ctx_thread_stop(int exit_code)
193 if (current_context->cleanup_func)
194 ((*current_context->cleanup_func)) (current_context->cleanup_arg);
196 xbt_swag_remove(current_context, context_living);
197 xbt_swag_insert(current_context, context_to_destroy);
199 /* signal to the maestro that it has finished */
200 xbt_os_sem_release(((xbt_ctx_thread_t) current_context)->end);
203 xbt_os_thread_exit(NULL); /* We should provide return value in case other wants it */
206 static void xbt_ctx_thread_swap(xbt_context_t context)
208 if ((current_context != maestro_context) && !context->iwannadie) {
209 /* (0) it's not the scheduler and the process doesn't want to die, it just wants to yield */
211 /* yield itself, resume the maestro */
212 xbt_ctx_thread_suspend(context);
214 /* (1) the current process is the scheduler and the process doesn't want to die
215 * <-> the maestro wants to schedule the process
216 * -> the maestro schedules the process and waits
218 * (2) the current process is the scheduler and the process wants to die
219 * <-> the maestro wants to kill the process (has called the function xbt_context_kill())
220 * -> the maestro schedule the process and waits (xbt_os_sem_acquire(context->end))
221 * -> if the process stops (xbt_context_stop())
222 * -> the process resumes the maestro (xbt_os_sem_release(current_context->end)) and exit (xbt_os_thread_exit())
223 * -> else the process call xbt_context_yield()
226 * (3) the current process is not the scheduler and the process wants to die
227 * -> (3.1) if the current process is the process who wants to die
228 * -> (resume not need) goto (4)
229 * -> (3.2) else the current process is not the process who wants to die
230 * <-> the current process wants to kill an other process
231 * -> the current process resumes the process to die and waits
232 * -> if the process to kill stops
233 * -> it resumes the process who kill it and exit
234 * -> else if the process to kill calls to xbt_context_yield()
237 /* schedule the process associated with this context */
238 xbt_ctx_thread_resume(context);
242 /* (4) the current process wants to die */
243 if (current_context->iwannadie)
244 xbt_ctx_thread_stop(1);
247 static void *xbt_ctx_thread_wrapper(void *param)
249 xbt_ctx_thread_t context = (xbt_ctx_thread_t) param;
251 /* Tell the maestro we are starting, and wait for its green light */
252 xbt_os_sem_release(context->end);
253 xbt_os_sem_acquire(context->begin);
255 if (context->startup_func)
256 (*(context->startup_func)) (context->startup_arg);
259 xbt_ctx_thread_stop((context->code) (context->argc, context->argv));
263 static void xbt_ctx_thread_suspend(xbt_context_t context)
265 /* save the current context */
266 xbt_context_t self = current_context;
268 /* update the current context to this context */
269 current_context = context;
271 xbt_os_sem_release(((xbt_ctx_thread_t) context)->end);
272 xbt_os_sem_acquire(((xbt_ctx_thread_t) context)->begin);
274 /* restore the current context to the previously saved context */
275 current_context = self;
278 static void xbt_ctx_thread_resume(xbt_context_t context)
280 /* save the current context */
281 xbt_context_t self = current_context;
283 /* update the current context */
284 current_context = context;
286 xbt_os_sem_release(((xbt_ctx_thread_t) context)->begin);
287 xbt_os_sem_acquire(((xbt_ctx_thread_t) context)->end);
289 /* restore the current context to the previously saved context */
290 current_context = self;