Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
c1f1e656e2e1e1f2302cf47e2980bb106063ad8d
[simgrid.git] / src / simix / xbt_context.c
1 /* a fast and simple context switching library                              */
2
3 /* Copyright (c) 2004-2008 the SimGrid team.                                */
4 /* All rights reserved.                                                     */
5
6 /* This program is free software; you can redistribute it and/or modify it
7  * under the terms of the license (GNU LGPL) which comes with this package. */
8
9 #include "portable.h"
10 #include "xbt/log.h"
11 #include "xbt/swag.h"
12 #include "xbt_context_private.h"
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(xbt_context, xbt,
15                                 "Context switching mecanism");
16
17 /* the context factory used to create the appropriate context
18  * each context implementation define its own context factory
19  * a context factory is responsable of the creation of the context
20  * associated with the maestro and of all the context based on
21  * the selected implementation.
22  *
23  * for example, the context switch based on java thread use the
24  * java implementation of the context and the java factory build
25  * the context depending of this implementation.
26  */
27
28 /**
29  * This function is call by SIMIX_global_init() to initialize the context module.
30  */
31 void SIMIX_context_mod_init(void)
32 {
33   if (!simix_global->context_factory) {
34     /* select context factory to use to create the context(depends of the macro definitions) */
35
36 #ifdef CONTEXT_THREADS
37     /* context switch based os thread */
38     SIMIX_ctx_thread_factory_init(&simix_global->context_factory);
39 #elif !defined(WIN32)
40     /* context switch based ucontext */
41     SIMIX_ctx_sysv_factory_init(&simix_global->context_factory);
42 #else
43     /* context switch is not allowed on Windows */
44 #error ERROR [__FILE__, line __LINE__]: no context based implementation specified.
45 #endif
46   }
47 }
48
49 /**
50  * This function is call by SIMIX_clean() to finalize the context module.
51  */
52 void SIMIX_context_mod_exit(void)
53 {
54   if (simix_global->context_factory) {
55     smx_pfn_context_factory_finalize_t finalize_factory;
56
57     /* if there are living processes then kill them (except maestro) */
58     if(simix_global->process_list != NULL)
59       SIMIX_process_killall();
60     
61     /* finalize the context factory */
62     finalize_factory = simix_global->context_factory->finalize;
63     (*finalize_factory) (&simix_global->context_factory);
64   }
65 }
66
67 /*******************************/
68 /* Object creation/destruction */
69 /*******************************/
70 /**
71  * \param smx_process the simix process that contains this context
72  * \param code a main function
73  */
74 int SIMIX_context_new(smx_process_t *process, xbt_main_func_t code)
75 {
76   /* use the appropriate context factory to create the appropriate context */
77     return (*(simix_global->context_factory->create_context)) (process, code);
78 }
79
80
81 int SIMIX_context_create_maestro(smx_process_t *process)
82 {
83   return (*(simix_global->context_factory->create_maestro_context)) (process);
84 }
85
86 /* Scenario for the end of a context:
87  *
88  * CASE 1: death after end of function
89  *   __context_wrapper, called by os thread, calls xbt_context_stop after user code stops
90  *   xbt_context_stop calls user cleanup_func if any (in context settings),
91  *                    add current to trashbin
92  *                    yields back to maestro (destroy os thread on need)
93  *   From time to time, maestro calls xbt_context_empty_trash,
94  *       which maps xbt_context_free on the content
95  *   xbt_context_free frees some more memory,
96  *                    joins os thread
97  *
98  * CASE 2: brutal death
99  *   xbt_context_kill (from any context)
100  *                    set context->wannadie to 1
101  *                    yields to the context
102  *   the context is awaken in the middle of __yield.
103  *   At the end of it, it checks that wannadie == 1, and call xbt_context_stop
104  *   (same than first case afterward)
105  */
106
107
108 /* Argument must be stopped first -- runs in maestro context */
109 void SIMIX_context_free(smx_process_t process)
110 {
111   (*(simix_global->context_factory->free)) (process);
112 }
113
114 void SIMIX_context_kill(smx_process_t process)
115 {
116   (*(simix_global->context_factory->kill)) (process);
117 }
118
119 /**
120  * \param context the context to start
121  *
122  * Calling this function prepares \a process to be run. It will
123    however run effectively only when calling #SIMIX_context_schedule
124  */
125 void SIMIX_context_start(smx_process_t process)
126 {
127   (*(simix_global->context_factory->start)) (process);
128 }
129
130 /**
131  * Calling this function makes the current process yield. The process
132  * that scheduled it returns from SIMIX_context_schedule as if nothing
133  * had happened.
134  *
135  * Only the processes can call this function, giving back the control
136  * to the maestro
137  */
138 void SIMIX_context_yield(void)
139 {
140   (*(simix_global->context_factory->yield)) ();
141 }
142
143 /**
144  * \param process to be scheduled
145  *
146  * Calling this function blocks the current process and schedule \a process.
147  * When \a process would call SIMIX_context_yield, it will return
148  * to this function as if nothing had happened.
149  *
150  * Only the maestro can call this function to run a given process.
151  */
152 void SIMIX_context_schedule(smx_process_t process)
153 {
154   (*(simix_global->context_factory->schedule)) (process);
155 }
156
157 void SIMIX_context_stop(int exit_code)
158 {
159   (*(simix_global->context_factory->stop)) (exit_code);
160 }
161
162 int SIMIX_context_select_factory(const char *name)
163 {
164   /* if a factory is already instantiated (SIMIX_context_mod_init() was called) */
165   if (simix_global->context_factory != NULL) {
166     /* if the desired factory is different of the current factory, call SIMIX_context_mod_exit() */
167     if (strcmp(simix_global->context_factory->name, name))
168       SIMIX_context_mod_exit();
169     else
170       /* the same context factory is requested return directly */
171       return 0;
172   }
173
174   /* get the desired factory */
175   SIMIX_context_init_factory_by_name(&simix_global->context_factory, name);
176
177   /* maestro process specialisation */
178   (*(simix_global->context_factory->create_maestro_context)) (&simix_global->maestro_process);
179
180   /* the current process is the process of the maestro */
181   simix_global->current_process = simix_global->maestro_process;
182
183   /* the current context doesn't want to die */
184   simix_global->current_process->iwannadie = 0;
185
186   /* insert the current context in the list of the contexts in use */
187   xbt_swag_insert(simix_global->current_process, simix_global->process_list);
188
189   return 0;
190 }
191
192 void
193 SIMIX_context_init_factory_by_name(smx_context_factory_t * factory,
194                                    const char *name)
195 {
196   if (!strcmp(name, "java"))
197 #ifdef HAVE_JAVA     
198     SIMIX_ctx_java_factory_init(factory);
199 #else
200     THROW0(not_found_error, 0, "Factory 'Java' does not exist: Java support was not compiled in the SimGrid library");
201 #endif /* HAVE_JAVA */
202    
203   else if (!strcmp(name, "thread"))
204 #ifdef CONTEXT_THREADS
205     SIMIX_ctx_thread_factory_init(factory);
206 #else
207     THROW0(not_found_error, 0, "Factory 'thread' does not exist: thread support was not compiled in the SimGrid library");
208 #endif /* CONTEXT_THREADS */
209    
210   else if (!strcmp(name, "sysv"))
211 #if !defined(WIN32) && !defined(CONTEXT_THREADS)
212     SIMIX_ctx_sysv_factory_init(factory);
213 #else
214     THROW0(not_found_error, 0, "Factory 'sysv' does not exist: no System V thread support under Windows");
215 #endif   
216   else
217     THROW1(not_found_error, 0, "Factory '%s' does not exist", name);
218 }
219
220 /** Garbage collection
221  *
222  * Should be called some time to time to free the memory allocated for processes
223  * that have finished (or killed).
224  */
225 void SIMIX_context_empty_trash(void)
226
227   smx_process_t process = NULL;
228   int i;  
229
230   while ((process = xbt_swag_extract(simix_global->process_to_destroy))){
231     free(process->name);
232     process->name = NULL;
233   
234     if (process->argv) {
235       for (i = 0; i < process->argc; i++)
236         if (process->argv[i])
237           free(process->argv[i]);
238
239       free(process->argv);
240     }
241   
242     free(process);
243   }
244 }