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_factory.h"
\r
15 /* the context associated with the current process */
\r
16 static xbt_context_t
\r
17 current_context = NULL;
\r
19 /* the context associated with the maestro */
\r
20 static xbt_context_t
\r
21 maestro_context = NULL;
\r
24 /* this list contains the contexts to destroy */
\r
26 context_to_destroy = NULL;
\r
28 /* this list contains the contexts in use */
\r
30 context_living = NULL;
\r
32 /* the context factory used to create the appropriate context
\r
33 * each context implementation define its own context factory
\r
34 * a context factory is responsable of the creation of the context
\r
35 * associated with the maestro and of all the context based on
\r
36 * the selected implementation.
\r
38 * for example, the context switch based on java thread use the
\r
39 * java implementation of the context and the java factory build
\r
40 * the context depending of this implementation.
\r
42 static xbt_context_factory_t
\r
43 context_factory = NULL;
\r
45 /* java implementation of the context */
\r
46 #include "xbt_jcontext.c"
\r
48 #ifdef CONTEXT_THREADS
\r
49 /* use the native thread implementation of the context */
\r
50 #include "xbt_thread_context.c"
\r
51 #elif !defined(WIN32)
\r
52 /* use the ucontext based context */
\r
53 # include "xbt_ucontext.c"
\r
58 * This function is call by the xbt_init() function to initialize the context module.
\r
61 xbt_context_mod_init(void)
\r
63 if(!context_factory)
\r
65 /* select context factory to use to create the context(depends of the macro definitions) */
\r
67 #ifdef CONTEXT_THREADS
\r
68 /* context switch based os thread */
\r
69 xbt_thread_context_factory_init(&context_factory);
\r
70 #elif !defined(WIN32)
\r
71 /* context switch based ucontext */
\r
72 xbt_ucontext_factory_init(&context_factory);
\r
74 /* context switch is not allowed on Windows */
\r
75 #error ERROR [__FILE__, line __LINE__]: no context based implementation specified.
\r
78 /* maestro context specialisation (this create the maestro with the good implementation */
\r
79 (*(context_factory->create_maestro_context))(&maestro_context);
\r
81 /* the current context is the context of the maestro */
\r
82 current_context = maestro_context;
\r
84 /* the current context doesn't want to die */
\r
85 current_context->iwannadie = 0;
\r
87 /* intantiation of the lists containing the contexts to destroy and the contexts in use */
\r
88 context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
89 context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
91 /* insert the current context in the list of the contexts in use */
\r
92 xbt_swag_insert(current_context, context_living);
\r
98 * This function is call by the xbt_exit() function to finalize the context module.
\r
101 xbt_context_mod_exit(void)
\r
103 if(context_factory)
\r
105 xbt_context_t context = NULL;
\r
106 xbt_pfn_context_factory_finalize_t finalize_factory;
\r
108 /* finalize the context factory */
\r
109 finalize_factory = context_factory->finalize;
\r
111 (*finalize_factory)(&context_factory);
\r
113 /* destroy all contexts in the list of contexts to destroy */
\r
114 xbt_context_empty_trash();
\r
116 /* remove the context of the scheduler from the list of the contexts in use */
\r
117 xbt_swag_remove(maestro_context, context_living);
\r
119 free(maestro_context);
\r
120 maestro_context = current_context = NULL;
\r
123 * kill all the contexts in use :
\r
124 * the killed contexts are added in the list of the contexts to destroy
\r
126 while((context = xbt_swag_extract(context_living)))
\r
127 (*(context->kill))(context);
\r
130 /* destroy all contexts in the list of contexts to destroy */
\r
131 xbt_context_empty_trash();
\r
133 /* destroy the lists */
\r
134 xbt_swag_free(context_to_destroy);
\r
135 xbt_swag_free(context_living);
\r
139 /*******************************/
\r
140 /* Object creation/destruction */
\r
141 /*******************************/
\r
143 * \param code a main function
\r
144 * \param startup_func a function to call when running the context for
\r
145 * the first time and just before the main function \a code
\r
146 * \param startup_arg the argument passed to the previous function (\a startup_func)
\r
147 * \param cleanup_func a function to call when running the context, just after
\r
148 the termination of the main function \a code
\r
149 * \param cleanup_arg the argument passed to the previous function (\a cleanup_func)
\r
150 * \param argc first argument of function \a code
\r
151 * \param argv seconde argument of function \a code
\r
154 xbt_context_new(const char *name,
\r
155 xbt_main_func_t code,
\r
156 void_f_pvoid_t startup_func,
\r
158 void_f_pvoid_t cleanup_func,
\r
159 void *cleanup_arg, int argc, char *argv[]
\r
162 /* use the appropriate context factory to create the appropriate context */
\r
163 xbt_context_t context = (*(context_factory->create_context))(name, code, startup_func, startup_arg, cleanup_func, cleanup_arg, argc, argv);
\r
165 /* add the context in the list of the contexts in use */
\r
166 xbt_swag_insert(context, context_living);
\r
171 /* Scenario for the end of a context:
\r
173 * CASE 1: death after end of function
\r
174 * __context_wrapper, called by os thread, calls xbt_context_stop after user code stops
\r
175 * xbt_context_stop calls user cleanup_func if any (in context settings),
\r
176 * add current to trashbin
\r
177 * yields back to maestro (destroy os thread on need)
\r
178 * From time to time, maestro calls xbt_context_empty_trash,
\r
179 * which maps xbt_context_free on the content
\r
180 * xbt_context_free frees some more memory,
\r
183 * CASE 2: brutal death
\r
184 * xbt_context_kill (from any context)
\r
185 * set context->wannadie to 1
\r
186 * yields to the context
\r
187 * the context is awaken in the middle of __yield.
\r
188 * At the end of it, it checks that wannadie == 1, and call xbt_context_stop
\r
189 * (same than first case afterward)
\r
193 /* Argument must be stopped first -- runs in maestro context */
\r
195 xbt_context_free(xbt_context_t context)
\r
197 (*(context->free))(context);
\r
202 xbt_context_kill(xbt_context_t context)
\r
204 (*(context->kill))(context);
\r
208 * \param context the context to start
\r
210 * Calling this function prepares \a context to be run. It will
\r
211 however run effectively only when calling #xbt_context_schedule
\r
214 xbt_context_start(xbt_context_t context)
\r
216 (*(context->start))(context);
\r
220 * Calling this function makes the current context yield. The context
\r
221 * that scheduled it returns from xbt_context_schedule as if nothing
\r
224 * Only the processes can call this function, giving back the control
\r
228 xbt_context_yield(void)
\r
230 (*(current_context->yield))();
\r
234 * \param context the winner
\r
236 * Calling this function blocks the current context and schedule \a context.
\r
237 * When \a context will call xbt_context_yield, it will return
\r
238 * to this function as if nothing had happened.
\r
240 * Only the maestro can call this function to run a given process.
\r
243 xbt_context_schedule(xbt_context_t context)
\r
245 (*(context->schedule))(context);
\r
249 xbt_context_stop(int exit_code)
\r
252 (*(current_context->stop))(exit_code);
\r
256 xbt_context_select_factory(const char* name)
\r
258 /* if a factory is already instantiated (xbt_context_mod_init() was called) */
\r
259 if(NULL != context_factory)
\r
261 /* if the desired factory is different of the current factory, call xbt_context_mod_exit() */
\r
262 if(strcmp(context_factory->name,name))
\r
264 xbt_context_mod_exit();
\r
269 /* the same context factory is requested return directly */
\r
274 /* get the desired factory */
\r
275 xbt_context_init_factory_by_name(&context_factory,name);
\r
277 /* maestro context specialisation */
\r
278 (*(context_factory->create_maestro_context))(&maestro_context);
\r
280 /* the current context is the context of the maestro */
\r
281 current_context = maestro_context;
\r
283 /* the current context doesn't want to die */
\r
284 current_context->iwannadie = 0;
\r
286 /* intantiation of the lists containing the contexts to destroy and the contexts in use */
\r
287 context_to_destroy = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
288 context_living = xbt_swag_new(xbt_swag_offset(*current_context, hookup));
\r
290 /* insert the current context in the list of the contexts in use */
\r
291 xbt_swag_insert(current_context, context_living);
\r
297 xbt_context_init_factory_by_name(xbt_context_factory_t* factory, const char* name)
\r
299 if(!strcmp(name,"jcontext_factory"))
\r
301 return xbt_jcontext_factory_init(factory);
\r
303 #ifdef CONTEXT_THREADS
\r
304 else if(!strcmp(name,"thread_context_factory"))
\r
306 return xbt_thread_context_factory_init(factory);
\r
308 #elif !defined(WIN32)
\r
309 else if(!strcmp(name,"ucontext_context_factory"))
\r
311 return xbt_ucontext_factory_init(factory);
\r
318 /** Garbage collection
\r
320 * Should be called some time to time to free the memory allocated for contexts
\r
321 * that have finished executing their main functions.
\r
324 xbt_context_empty_trash(void)
\r
326 xbt_context_t context = NULL;
\r
328 while((context = xbt_swag_extract(context_to_destroy)))
\r
329 (*(context->free))(context);
\r