Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
da0da65d9d2d1be5e9eef20364d09796941b023b
[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_process_t process = NULL;
56     smx_pfn_context_factory_finalize_t finalize_factory;
57
58     /* kill all the processes (except maestro)
59      * the killed processes are added in the list of the processes to destroy */
60     
61     while ((process = xbt_swag_extract(simix_global->process_list)))
62       (*(simix_global->context_factory->kill)) (process);
63
64     /* destroy all processes in the list of process to destroy */
65     SIMIX_context_empty_trash();
66
67     /* finalize the context factory */
68     finalize_factory = simix_global->context_factory->finalize;
69     (*finalize_factory) (&simix_global->context_factory);
70   }
71 }
72
73 /*******************************/
74 /* Object creation/destruction */
75 /*******************************/
76 /**
77  * \param smx_process the simix process that contains this context
78  * \param code a main function
79  */
80 int SIMIX_context_new(smx_process_t *process, xbt_main_func_t code)
81 {
82   /* use the appropriate context factory to create the appropriate context */
83     return (*(simix_global->context_factory->create_context)) (process, code);
84 }
85
86
87 int SIMIX_context_create_maestro(smx_process_t *process)
88 {
89   return (*(simix_global->context_factory->create_maestro_context)) (process);
90 }
91
92 /* Scenario for the end of a context:
93  *
94  * CASE 1: death after end of function
95  *   __context_wrapper, called by os thread, calls xbt_context_stop after user code stops
96  *   xbt_context_stop calls user cleanup_func if any (in context settings),
97  *                    add current to trashbin
98  *                    yields back to maestro (destroy os thread on need)
99  *   From time to time, maestro calls xbt_context_empty_trash,
100  *       which maps xbt_context_free on the content
101  *   xbt_context_free frees some more memory,
102  *                    joins os thread
103  *
104  * CASE 2: brutal death
105  *   xbt_context_kill (from any context)
106  *                    set context->wannadie to 1
107  *                    yields to the context
108  *   the context is awaken in the middle of __yield.
109  *   At the end of it, it checks that wannadie == 1, and call xbt_context_stop
110  *   (same than first case afterward)
111  */
112
113
114 /* Argument must be stopped first -- runs in maestro context */
115 void SIMIX_context_free(smx_process_t process)
116 {
117   (*(simix_global->context_factory->free)) (process);
118 }
119
120 void SIMIX_context_kill(smx_process_t process)
121 {
122   (*(simix_global->context_factory->kill)) (process);
123 }
124
125 /**
126  * \param context the context to start
127  *
128  * Calling this function prepares \a process to be run. It will
129    however run effectively only when calling #SIMIX_context_schedule
130  */
131 void SIMIX_context_start(smx_process_t process)
132 {
133   (*(simix_global->context_factory->start)) (process);
134 }
135
136 /**
137  * Calling this function makes the current process yield. The process
138  * that scheduled it returns from SIMIX_context_schedule as if nothing
139  * had happened.
140  *
141  * Only the processes can call this function, giving back the control
142  * to the maestro
143  */
144 void SIMIX_context_yield(void)
145 {
146   (*(simix_global->context_factory->yield)) ();
147 }
148
149 /**
150  * \param process to be scheduled
151  *
152  * Calling this function blocks the current process and schedule \a process.
153  * When \a process would call SIMIX_context_yield, it will return
154  * to this function as if nothing had happened.
155  *
156  * Only the maestro can call this function to run a given process.
157  */
158 void SIMIX_context_schedule(smx_process_t process)
159 {
160   (*(simix_global->context_factory->schedule)) (process);
161 }
162
163 void SIMIX_context_stop(int exit_code)
164 {
165   (*(simix_global->context_factory->stop)) (exit_code);
166 }
167
168 int SIMIX_context_select_factory(const char *name)
169 {
170   /* if a factory is already instantiated (SIMIX_context_mod_init() was called) */
171   if (simix_global->context_factory != NULL) {
172     /* if the desired factory is different of the current factory, call SIMIX_context_mod_exit() */
173     if (strcmp(simix_global->context_factory->name, name))
174       SIMIX_context_mod_exit();
175     else
176       /* the same context factory is requested return directly */
177       return 0;
178   }
179
180   /* get the desired factory */
181   SIMIX_context_init_factory_by_name(&simix_global->context_factory, name);
182
183   /* maestro process specialisation */
184   (*(simix_global->context_factory->create_maestro_context)) (&simix_global->maestro_process);
185
186   /* the current process is the process of the maestro */
187   simix_global->current_process = simix_global->maestro_process;
188
189   /* the current context doesn't want to die */
190   simix_global->current_process->iwannadie = 0;
191
192   /* insert the current context in the list of the contexts in use */
193   xbt_swag_insert(simix_global->current_process, simix_global->process_list);
194
195   return 0;
196 }
197
198 void
199 SIMIX_context_init_factory_by_name(smx_context_factory_t * factory,
200                                    const char *name)
201 {
202   if (!strcmp(name, "java"))
203 #ifdef HAVE_JAVA     
204     SIMIX_ctx_java_factory_init(factory);
205 #else
206     THROW0(not_found_error, 0, "Factory 'Java' does not exist: Java support was not compiled in the SimGrid library");
207 #endif /* HAVE_JAVA */
208    
209   else if (!strcmp(name, "thread"))
210 #ifdef CONTEXT_THREADS
211     SIMIX_ctx_thread_factory_init(factory);
212 #else
213     THROW0(not_found_error, 0, "Factory 'thread' does not exist: thread support was not compiled in the SimGrid library");
214 #endif /* CONTEXT_THREADS */
215    
216   else if (!strcmp(name, "sysv"))
217 #if !defined(WIN32) && !defined(CONTEXT_THREADS)
218     SIMIX_ctx_sysv_factory_init(factory);
219 #else
220     THROW0(not_found_error, 0, "Factory 'sysv' does not exist: no System V thread support under Windows");
221 #endif   
222   else
223     THROW1(not_found_error, 0, "Factory '%s' does not exist", name);
224 }
225
226 /** Garbage collection
227  *
228  * Should be called some time to time to free the memory allocated for processes
229  * that have finished (or killed).
230  */
231 void SIMIX_context_empty_trash(void)
232
233   smx_process_t process = NULL;
234   int i;  
235
236   while ((process = xbt_swag_extract(simix_global->process_to_destroy))){
237
238     free(process->name);
239     process->name = NULL;
240   
241     if (process->argv) {
242       for (i = 0; i < process->argc; i++)
243         if (process->argv[i])
244           free(process->argv[i]);
245
246       free(process->argv);
247     }
248   
249     free(process);
250   }
251 }