Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Move all XBT_LOG_CONNECT into one place.
[simgrid.git] / src / simix / smx_global.c
1 /* Copyright (c) 2007, 2008, 2009, 2010. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "smx_private.h"
8 #include "xbt/heap.h"
9 #include "xbt/sysdep.h"
10 #include "xbt/log.h"
11 #include "xbt/str.h"
12 #include "xbt/ex.h"             /* ex_backtrace_display */
13 #include "mc/mc.h"
14
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_kernel, simix,
16                                 "Logging specific to SIMIX (kernel)");
17
18 smx_global_t simix_global = NULL;
19 static xbt_heap_t simix_timers = NULL;
20
21 static void* SIMIX_action_mallocator_new_f(void);
22 static void SIMIX_action_mallocator_free_f(void* action);
23 static void SIMIX_action_mallocator_reset_f(void* action);
24
25 extern void smx_ctx_raw_new_sr(void);
26
27 /* FIXME: Yeah, I'll do it in a portable maner one day [Mt] */
28 #include <signal.h>
29
30 int _surf_do_verbose_exit = 1;
31 static void _XBT_CALL inthandler(int ignored)
32 {
33   if ( _surf_do_verbose_exit ) {
34      XBT_INFO("CTRL-C pressed. Displaying status and bailing out");
35      SIMIX_display_process_status();
36   }
37   else {
38      XBT_INFO("CTRL-C pressed. bailing out without displaying because verbose-exit is disabled");
39   }
40   exit(1);
41 }
42
43 /********************************* SIMIX **************************************/
44
45 XBT_INLINE double SIMIX_timer_next(void)
46 {
47   return xbt_heap_size(simix_timers) > 0 ? xbt_heap_maxkey(simix_timers) : -1.0;
48 }
49
50 /**
51  * \brief Initialize SIMIX internal data.
52  *
53  * \param argc Argc
54  * \param argv Argv
55  */
56 void SIMIX_global_init(int *argc, char **argv)
57 {
58   s_smx_process_t proc;
59
60   if (!simix_global) {
61     simix_global = xbt_new0(s_smx_global_t, 1);
62
63     simix_global->process_to_run = xbt_dynar_new(sizeof(smx_process_t), NULL);
64     simix_global->process_that_ran = xbt_dynar_new(sizeof(smx_process_t), NULL);
65     simix_global->process_list =
66         xbt_swag_new(xbt_swag_offset(proc, process_hookup));
67     simix_global->process_to_destroy =
68         xbt_swag_new(xbt_swag_offset(proc, destroy_hookup));
69
70     simix_global->maestro_process = NULL;
71     simix_global->registered_functions = xbt_dict_new_homogeneous(NULL);
72
73     simix_global->create_process_function = SIMIX_process_create;
74     simix_global->kill_process_function = SIMIX_process_kill;
75     simix_global->cleanup_process_function = SIMIX_process_cleanup;
76     simix_global->action_mallocator = xbt_mallocator_new(65536,
77         SIMIX_action_mallocator_new_f, SIMIX_action_mallocator_free_f,
78         SIMIX_action_mallocator_reset_f);
79
80     surf_init(argc, argv);      /* Initialize SURF structures */
81     SIMIX_context_mod_init();
82     SIMIX_create_maestro_process();
83
84     /* context exception handlers */
85     __xbt_running_ctx_fetch = SIMIX_process_get_running_context;
86     __xbt_ex_terminate = SIMIX_process_exception_terminate;
87
88     /* Initialize the SIMIX network module */
89     SIMIX_network_init();
90
91     /* Prepare to display some more info when dying on Ctrl-C pressing */
92     signal(SIGINT, inthandler);
93   }
94   if (!simix_timers) {
95     simix_timers = xbt_heap_new(8, &free);
96   }
97
98   XBT_DEBUG("ADD SIMIX LEVELS");
99   SIMIX_HOST_LEVEL = xbt_lib_add_level(host_lib,SIMIX_host_destroy);
100 }
101
102 /**
103  * \brief Clean the SIMIX simulation
104  *
105  * This functions remove the memory used by SIMIX
106  */
107 void SIMIX_clean(void)
108 {
109 #ifdef TIME_BENCH
110   smx_ctx_raw_new_sr();
111 #endif
112
113   /* Kill everyone (except maestro) */
114   SIMIX_process_killall(simix_global->maestro_process);
115
116   /* Exit the SIMIX network module */
117   SIMIX_network_exit();
118
119   xbt_heap_free(simix_timers);
120   simix_timers = NULL;
121   /* Free the remaining data structures */
122   xbt_dynar_free(&simix_global->process_to_run);
123   xbt_dynar_free(&simix_global->process_that_ran);
124   xbt_swag_free(simix_global->process_to_destroy);
125   xbt_swag_free(simix_global->process_list);
126   simix_global->process_list = NULL;
127   simix_global->process_to_destroy = NULL;
128   xbt_dict_free(&(simix_global->registered_functions));
129
130   /* Let's free maestro now */
131   SIMIX_context_free(simix_global->maestro_process->context);
132   xbt_free(simix_global->maestro_process->running_ctx);
133   xbt_free(simix_global->maestro_process);
134   simix_global->maestro_process = NULL;
135
136   /* Restore the default exception setup */
137   __xbt_running_ctx_fetch = &__xbt_ex_ctx_default;
138   __xbt_ex_terminate = &__xbt_ex_terminate_default;
139
140   /* Finish context module and SURF */
141   SIMIX_context_mod_exit();
142
143   surf_exit();
144
145   xbt_mallocator_free(simix_global->action_mallocator);
146   xbt_free(simix_global);
147   simix_global = NULL;
148
149   return;
150 }
151
152
153 /**
154  * \brief A clock (in second).
155  *
156  * \return Return the clock.
157  */
158 XBT_INLINE double SIMIX_get_clock(void)
159 {
160   if(MC_IS_ENABLED){
161     return MC_process_clock_get(SIMIX_process_self());
162   }else{
163     return surf_get_clock();
164   }
165 }
166
167 void SIMIX_run(void)
168 {
169   double time = 0;
170   smx_process_t process;
171   xbt_swag_t set;
172   surf_action_t action;
173   smx_timer_t timer;
174   surf_model_t model;
175   unsigned int iter;
176
177   do {
178     XBT_DEBUG("New Schedule Round; size(queue)=%lu",
179         xbt_dynar_length(simix_global->process_to_run));
180 #ifdef TIME_BENCH
181     smx_ctx_raw_new_sr();
182 #endif
183     while (!xbt_dynar_is_empty(simix_global->process_to_run)) {
184       XBT_DEBUG("New Sub-Schedule Round; size(queue)=%lu",
185               xbt_dynar_length(simix_global->process_to_run));
186       SIMIX_process_runall();
187       xbt_dynar_foreach(simix_global->process_that_ran, iter, process) {
188         if (process->simcall.call != SIMCALL_NONE) {
189           SIMIX_simcall_pre(&process->simcall, 0);
190         }
191       }
192     }
193
194     time = SIMIX_timer_next();
195     if (time != -1.0 || xbt_swag_size(simix_global->process_list) != 0)
196       time = surf_solve(time);
197
198     /* Notify all the hosts that have failed */
199     /* FIXME: iterate through the list of failed host and mark each of them */
200     /* as failed. On each host, signal all the running processes with host_fail */
201
202     /* Handle any pending timer */
203     while (xbt_heap_size(simix_timers) > 0 && SIMIX_get_clock() >= SIMIX_timer_next()) {
204        //FIXME: make the timers being real callbacks
205        // (i.e. provide dispatchers that read and expand the args) 
206        timer = xbt_heap_pop(simix_timers);
207        if (timer->func)
208          ((void (*)(void*))timer->func)(timer->args);
209     }
210     /* Wake up all processes waiting for a Surf action to finish */
211     xbt_dynar_foreach(model_list, iter, model) {
212       set = model->states.failed_action_set;
213       while ((action = xbt_swag_extract(set)))
214         SIMIX_simcall_post((smx_action_t) action->data);
215       set = model->states.done_action_set;
216       while ((action = xbt_swag_extract(set)))
217         SIMIX_simcall_post((smx_action_t) action->data);
218     }
219
220     /* Clean processes to destroy */
221     SIMIX_process_empty_trash();
222
223   } while (time != -1.0 || !xbt_dynar_is_empty(simix_global->process_to_run));
224
225   if (xbt_swag_size(simix_global->process_list) != 0) {
226
227 #ifdef HAVE_TRACING
228     TRACE_end();
229 #endif
230
231     XBT_WARN("Oops ! Deadlock or code not perfectly clean.");
232     SIMIX_display_process_status();
233     xbt_abort();
234   }
235 }
236
237 /**
238  *      \brief Set the date to execute a function
239  *
240  * Set the date to execute the function on the surf.
241  *      \param date Date to execute function
242  *      \param function Function to be executed
243  *      \param arg Parameters of the function
244  *
245  */
246 XBT_INLINE void SIMIX_timer_set(double date, void *function, void *arg)
247 {
248   smx_timer_t timer = xbt_new0(s_smx_timer_t, 1);
249
250   timer->date = date;
251   timer->func = function;
252   timer->args = arg;
253   xbt_heap_push(simix_timers, timer, date);
254 }
255
256 /**
257  * \brief Registers a function to create a process.
258  *
259  * This function registers a function to be called
260  * when a new process is created. The function has
261  * to call SIMIX_process_create().
262  * \param function create process function
263  */
264 XBT_INLINE void SIMIX_function_register_process_create(smx_creation_func_t
265                                                        function)
266 {
267   simix_global->create_process_function = function;
268 }
269
270 /**
271  * \brief Registers a function to kill a process.
272  *
273  * This function registers a function to be called when a
274  * process is killed. The function has to call the SIMIX_process_kill().
275  *
276  * \param function Kill process function
277  */
278 XBT_INLINE void SIMIX_function_register_process_kill(void_pfn_smxprocess_t
279                                                      function)
280 {
281   simix_global->kill_process_function = function;
282 }
283
284 /**
285  * \brief Registers a function to cleanup a process.
286  *
287  * This function registers a user function to be called when
288  * a process ends properly.
289  *
290  * \param function cleanup process function
291  */
292 XBT_INLINE void SIMIX_function_register_process_cleanup(void_pfn_smxprocess_t
293                                                         function)
294 {
295   simix_global->cleanup_process_function = function;
296 }
297
298
299 void SIMIX_display_process_status(void)
300 {
301   if (simix_global->process_list == NULL) {
302     return;
303   }
304
305   smx_process_t process = NULL;
306   int nbprocess = xbt_swag_size(simix_global->process_list);
307
308   XBT_INFO("%d processes are still running, waiting for something.", nbprocess);
309   /*  List the process and their state */
310   XBT_INFO
311     ("Legend of the following listing: \"Process <pid> (<name>@<host>): <status>\"");
312   xbt_swag_foreach(process, simix_global->process_list) {
313
314     if (process->waiting_action) {
315
316       const char* action_description = "unknown";
317       switch (process->waiting_action->type) {
318
319       case SIMIX_ACTION_EXECUTE:
320         action_description = "execution";
321         break;
322
323       case SIMIX_ACTION_PARALLEL_EXECUTE:
324         action_description = "parallel execution";
325         break;
326
327       case SIMIX_ACTION_COMMUNICATE:
328         action_description = "communication";
329         break;
330
331       case SIMIX_ACTION_SLEEP:
332         action_description = "sleeping";
333         break;
334
335       case SIMIX_ACTION_SYNCHRO:
336         action_description = "synchronization";
337         break;
338
339       case SIMIX_ACTION_IO:
340         action_description = "I/O";
341         break;
342       }
343       XBT_INFO("Process %lu (%s@%s): waiting for %s action %p (%s) in state %d to finish",
344           process->pid, process->name, process->smx_host->name,
345           action_description, process->waiting_action,
346           process->waiting_action->name, (int)process->waiting_action->state);
347     }
348     else {
349       XBT_INFO("Process %lu (%s@%s)", process->pid, process->name, process->smx_host->name);
350     }
351   }
352 }
353
354 static void* SIMIX_action_mallocator_new_f(void) {
355   smx_action_t action = xbt_new(s_smx_action_t, 1);
356   action->simcalls = xbt_fifo_new();
357   return action;
358 }
359
360 static void SIMIX_action_mallocator_free_f(void* action) {
361   xbt_fifo_free(((smx_action_t) action)->simcalls);
362   xbt_free(action);
363 }
364
365 static void SIMIX_action_mallocator_reset_f(void* action) {
366
367   // we also recycle the simcall list
368   xbt_fifo_t fifo = ((smx_action_t) action)->simcalls;
369   xbt_fifo_reset(fifo);
370   memset(action, 0, sizeof(s_smx_action_t));
371   ((smx_action_t) action)->simcalls = fifo;
372 }