1 /* a fast and simple context switching library */
\r
3 /* Copyright (c) 2004 Arnaud Legrand. */
\r
4 /* Copyright (c) 2004, 2005 Martin Quinson. */
\r
5 /* All rights reserved. */
\r
7 /* This program is free software; you can redistribute it and/or modify it
\r
8 * under the terms of the license (GNU LGPL) which comes with this package. */
\r
10 #include "portable.h"
\r
11 #include "xbt/log.h"
\r
12 #include "xbt/swag.h"
\r
13 #include "xbt_context_private.h"
\r
15 /* the context associated with the current process */
\r
16 xbt_context_t current_context = NULL;
\r
18 /* the context associated with the maestro */
\r
19 xbt_context_t maestro_context = NULL;
\r
22 /* this list contains the contexts to destroy */
\r
23 xbt_swag_t context_to_destroy = NULL;
\r
25 /* this list contains the contexts in use */
\r
26 xbt_swag_t context_living = NULL;
\r
28 /* the context factory used to create the appropriate context
\r
29 * each context implementation define its own context factory
\r
30 * a context factory is responsable of the creation of the context
\r
31 * associated with the maestro and of all the context based on
\r
32 * the selected implementation.
\r
34 * for example, the context switch based on java thread use the
\r
35 * java implementation of the context and the java factory build
\r
36 * the context depending of this implementation.
\r
38 static xbt_context_factory_t
\r
39 context_factory = NULL;
\r
42 * This function is call by the xbt_init() function to initialize the context module.
\r
45 xbt_context_mod_init(void)
\r
47 if(!context_factory)
\r
49 /* select context factory to use to create the context(depends of the macro definitions) */
\r
51 #ifdef CONTEXT_THREADS
\r
52 /* context switch based os thread */
\r
53 xbt_ctx_thread_factory_init(&context_factory);
\r
54 #elif !defined(WIN32)
\r
55 /* context switch based ucontext */
\r
56 xbt_ctx_sysv_factory_init(&context_factory);
\r
58 /* context switch is not allowed on Windows */
\r
59 #error ERROR [__FILE__, line __LINE__]: no context based implementation specified.
\r
62 /* maestro context specialisation (this create the maestro with the good implementation */
\r
63 (*(context_factory->create_maestro_context))(&maestro_context);
\r
65 /* the current context is the context of the maestro */
\r
66 current_context = maestro_context;
\r
68 /* the current context doesn't want to die */
\r
69 current_context->iwannadie = 0;
\r
71 /* intantiation of the lists containing the contexts to destroy and the contexts in use */
\r
72 context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
73 context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
75 /* insert the current context in the list of the contexts in use */
\r
76 xbt_swag_insert(current_context, context_living);
\r
82 * This function is call by the xbt_exit() function to finalize the context module.
\r
85 xbt_context_mod_exit(void)
\r
89 xbt_context_t context = NULL;
\r
90 xbt_pfn_context_factory_finalize_t finalize_factory;
\r
92 /* finalize the context factory */
\r
93 finalize_factory = context_factory->finalize;
\r
95 (*finalize_factory)(&context_factory);
\r
97 /* destroy all contexts in the list of contexts to destroy */
\r
98 xbt_context_empty_trash();
\r
100 /* remove the context of the scheduler from the list of the contexts in use */
\r
101 xbt_swag_remove(maestro_context, context_living);
\r
104 * kill all the contexts in use :
\r
105 * the killed contexts are added in the list of the contexts to destroy
\r
107 while((context = xbt_swag_extract(context_living)))
\r
108 (*(context->kill))(context);
\r
111 /* destroy all contexts in the list of contexts to destroy */
\r
112 xbt_context_empty_trash();
\r
114 free(maestro_context);
\r
115 maestro_context = current_context = NULL;
\r
117 /* destroy the lists */
\r
118 xbt_swag_free(context_to_destroy);
\r
119 xbt_swag_free(context_living);
\r
123 /*******************************/
\r
124 /* Object creation/destruction */
\r
125 /*******************************/
\r
127 * \param code a main function
\r
128 * \param startup_func a function to call when running the context for
\r
129 * the first time and just before the main function \a code
\r
130 * \param startup_arg the argument passed to the previous function (\a startup_func)
\r
131 * \param cleanup_func a function to call when running the context, just after
\r
132 the termination of the main function \a code
\r
133 * \param cleanup_arg the argument passed to the previous function (\a cleanup_func)
\r
134 * \param argc first argument of function \a code
\r
135 * \param argv seconde argument of function \a code
\r
138 xbt_context_new(const char *name,
\r
139 xbt_main_func_t code,
\r
140 void_f_pvoid_t startup_func,
\r
142 void_f_pvoid_t cleanup_func,
\r
143 void *cleanup_arg, int argc, char *argv[]
\r
146 /* use the appropriate context factory to create the appropriate context */
\r
147 xbt_context_t context = (*(context_factory->create_context))(name, code, startup_func, startup_arg, cleanup_func, cleanup_arg, argc, argv);
\r
149 /* add the context in the list of the contexts in use */
\r
150 xbt_swag_insert(context, context_living);
\r
155 /* Scenario for the end of a context:
\r
157 * CASE 1: death after end of function
\r
158 * __context_wrapper, called by os thread, calls xbt_context_stop after user code stops
\r
159 * xbt_context_stop calls user cleanup_func if any (in context settings),
\r
160 * add current to trashbin
\r
161 * yields back to maestro (destroy os thread on need)
\r
162 * From time to time, maestro calls xbt_context_empty_trash,
\r
163 * which maps xbt_context_free on the content
\r
164 * xbt_context_free frees some more memory,
\r
167 * CASE 2: brutal death
\r
168 * xbt_context_kill (from any context)
\r
169 * set context->wannadie to 1
\r
170 * yields to the context
\r
171 * the context is awaken in the middle of __yield.
\r
172 * At the end of it, it checks that wannadie == 1, and call xbt_context_stop
\r
173 * (same than first case afterward)
\r
177 /* Argument must be stopped first -- runs in maestro context */
\r
179 xbt_context_free(xbt_context_t context)
\r
181 (*(context->free))(context);
\r
186 xbt_context_kill(xbt_context_t context)
\r
188 (*(context->kill))(context);
\r
192 * \param context the context to start
\r
194 * Calling this function prepares \a context to be run. It will
\r
195 however run effectively only when calling #xbt_context_schedule
\r
198 xbt_context_start(xbt_context_t context)
\r
200 (*(context->start))(context);
\r
204 * Calling this function makes the current context yield. The context
\r
205 * that scheduled it returns from xbt_context_schedule as if nothing
\r
208 * Only the processes can call this function, giving back the control
\r
212 xbt_context_yield(void)
\r
214 (*(current_context->yield))();
\r
218 * \param context the winner
\r
220 * Calling this function blocks the current context and schedule \a context.
\r
221 * When \a context will call xbt_context_yield, it will return
\r
222 * to this function as if nothing had happened.
\r
224 * Only the maestro can call this function to run a given process.
\r
227 xbt_context_schedule(xbt_context_t context)
\r
229 (*(context->schedule))(context);
\r
233 xbt_context_stop(int exit_code)
\r
236 (*(current_context->stop))(exit_code);
\r
240 xbt_context_select_factory(const char* name)
\r
242 /* if a factory is already instantiated (xbt_context_mod_init() was called) */
\r
243 if(NULL != context_factory)
\r
245 /* if the desired factory is different of the current factory, call xbt_context_mod_exit() */
\r
246 if(strcmp(context_factory->name,name))
\r
247 xbt_context_mod_exit();
\r
249 /* the same context factory is requested return directly */
\r
253 /* get the desired factory */
\r
254 xbt_context_init_factory_by_name(&context_factory,name);
\r
256 /* maestro context specialisation */
\r
257 (*(context_factory->create_maestro_context))(&maestro_context);
\r
259 /* the current context is the context of the maestro */
\r
260 current_context = maestro_context;
\r
262 /* the current context doesn't want to die */
\r
263 current_context->iwannadie = 0;
\r
265 /* intantiation of the lists containing the contexts to destroy and the contexts in use */
\r
266 context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
267 context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
269 /* insert the current context in the list of the contexts in use */
\r
270 xbt_swag_insert(current_context, context_living);
\r
276 xbt_context_init_factory_by_name(xbt_context_factory_t* factory, const char* name)
\r
278 if(!strcmp(name,"java"))
\r
279 xbt_ctx_java_factory_init(factory);
\r
280 #ifdef CONTEXT_THREADS
\r
281 else if(!strcmp(name,"thread"))
\r
282 xbt_ctx_thread_factory_init(factory);
\r
283 #elif !defined(WIN32)
\r
284 else if(!strcmp(name,"sysv"))
\r
285 xbt_ctx_sysv_factory_init(factory);
\r
288 THROW1(not_found_error, 0,"Factory '%s' does not exist",name);
\r
291 /** Garbage collection
\r
293 * Should be called some time to time to free the memory allocated for contexts
\r
294 * that have finished executing their main functions.
\r
297 xbt_context_empty_trash(void)
\r
299 xbt_context_t context = NULL;
\r
301 while((context = xbt_swag_extract(context_to_destroy)))
\r
302 (*(context->free))(context);
\r