3 /* Copyright (c) 2007 Arnaud Legrand, Bruno Donassolo.
4 All rights reserved. */
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. */
10 #include "xbt/sysdep.h"
13 #include "xbt/ex.h" /* ex_backtrace_display */
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_kernel, simix,
15 "Logging specific to SIMIX (kernel)");
17 SIMIX_Global_t simix_global = NULL;
19 /********************************* SIMIX **************************************/
20 static void __simix_config_helper(const char *name, ...)
25 SIMIX_config(name, pa);
30 static void simix_cfg_control_set(const char *control_string)
32 /* To split the string in commands, and the cursors */
33 xbt_dynar_t set_strings;
39 DEBUG1("Parse log settings '%s'", control_string);
41 /* split the string, and remove empty entries */
42 set_strings = xbt_str_split_quoted(control_string);
44 if (xbt_dynar_length(set_strings) == 0) { /* vicious user! */
45 xbt_dynar_free(&set_strings);
48 /* Parse each entry and either use it right now (if the category was already
49 created), or store it for further use */
50 xbt_dynar_foreach(set_strings, cpt, str) {
51 char *control_string, *control_string_sav, *name, *value;
54 control_string = control_string_sav = strdup(str);
55 control_string += strspn(control_string, " ");
56 name = control_string;
57 control_string += strcspn(str, ":=");
58 value = control_string;
62 xbt_assert1(strlen(name) != 0, "Invalid name for configuration: '%s'",
64 xbt_assert1(strlen(value) != 0,
65 "Invalid value for configuration: '%s'", value);
66 INFO2("setting '%s' to '%s'", name, value);
68 __simix_config_helper(name, value);
70 free(control_string_sav);
72 xbt_dynar_free(&set_strings);
75 static void simix_cfg_init(int *argc, char **argv)
80 for (i = 1; i < *argc; i++) {
81 if (!strncmp(argv[i], "--cfg=", strlen("--cfg="))) {
82 opt = strchr(argv[i], '=');
85 simix_cfg_control_set(opt);
86 DEBUG1("Did apply '%s' as config setting", opt);
87 /*remove this from argv */
89 for (j = i + 1; j < *argc; j++) {
90 argv[j - 1] = argv[j];
95 i--; /* compensate effect of next loop incrementation */
100 /* FIXME: Yeah, I'll do it in a portable maner one day [Mt] */
103 static void _XBT_CALL inthandler(int ignored)
105 INFO0("CTRL-C pressed. Displaying status and bailing out");
106 SIMIX_display_process_status();
112 * \brief Initialize some SIMIX internal data.
117 void SIMIX_global_init(int *argc, char **argv)
119 s_smx_process_t proc;
122 surf_init(argc, argv); /* Initialize some common structures. Warning, it sets simix_global=NULL */
123 simix_cfg_init(argc, argv);
125 simix_global = xbt_new0(s_SIMIX_Global_t, 1);
127 simix_global->host = xbt_dict_new();
128 simix_global->process_to_run =
129 xbt_swag_new(xbt_swag_offset(proc, synchro_hookup));
130 simix_global->process_list =
131 xbt_swag_new(xbt_swag_offset(proc, process_hookup));
132 simix_global->current_process = NULL;
133 simix_global->registered_functions = xbt_dict_new();
135 simix_global->create_process_function = NULL;
136 simix_global->kill_process_function = NULL;
137 simix_global->cleanup_process_function = SIMIX_process_cleanup;
139 /* Prepare to display some more info when dying on Ctrl-C pressing */
140 signal(SIGINT, inthandler);
144 /* Debug purpose, incomplete */
145 void SIMIX_display_process_status(void)
147 smx_process_t process = NULL;
148 xbt_fifo_item_t item = NULL;
150 int nbprocess = xbt_swag_size(simix_global->process_list);
152 INFO1("%d processes are still running, waiting for something.", nbprocess);
153 /* List the process and their state */
155 ("Legend of the following listing: \"<process> on <host>: <status>.\"");
156 xbt_swag_foreach(process, simix_global->process_list) {
157 smx_simdata_process_t p_simdata =
158 (smx_simdata_process_t) process->simdata;
159 // simdata_host_t h_simdata=(simdata_host_t)p_simdata->host->simdata;
162 asprintf(&who, "%s on %s: %s",
164 p_simdata->smx_host->name,
165 (process->simdata->blocked) ? "[BLOCKED] "
166 : ((process->simdata->suspended) ? "[SUSPENDED] " : ""));
168 if (p_simdata->mutex) {
170 bprintf("%s Blocked on mutex %p", who,
171 (XBT_LOG_ISENABLED(simix_kernel, xbt_log_priority_verbose)) ?
172 p_simdata->mutex : (void *) 0xdead);
175 } else if (p_simdata->cond) {
178 ("%s Blocked on condition %p; Waiting for the following actions:",
180 (XBT_LOG_ISENABLED(simix_kernel, xbt_log_priority_verbose)) ?
181 p_simdata->cond : (void *) 0xdead);
184 xbt_fifo_foreach(p_simdata->cond->actions, item, act, smx_action_t) {
186 bprintf("%s '%s'(%p)", who, act->name,
187 (XBT_LOG_ISENABLED(simix_kernel, xbt_log_priority_verbose))
188 ? act : (void *) 0xdead);
195 ("%s Blocked in an unknown status (please report this bug)", who);
206 * \brief Launch the SIMIX simulation, debug purpose
208 void __SIMIX_main(void)
210 smx_process_t process = NULL;
211 smx_cond_t cond = NULL;
212 smx_action_t smx_action;
213 xbt_fifo_t actions_done = xbt_fifo_new();
214 xbt_fifo_t actions_failed = xbt_fifo_new();
216 /* Clean IO before the run */
220 //surf_solve(); /* Takes traces into account. Returns 0.0 */
221 /* xbt_fifo_size(msg_global->process_to_run) */
223 while (SIMIX_solve(actions_done, actions_failed) != -1.0) {
225 while ((smx_action = xbt_fifo_pop(actions_failed))) {
227 xbt_fifo_item_t _cursor;
229 DEBUG1("** %s failed **", smx_action->name);
230 xbt_fifo_foreach(smx_action->cond_list, _cursor, cond, smx_cond_t) {
231 xbt_swag_foreach(process, cond->sleeping) {
232 DEBUG2("\t preparing to wake up %s on %s",
233 process->name, process->simdata->smx_host->name);
235 SIMIX_cond_broadcast(cond);
236 /* remove conditional from action */
237 SIMIX_unregister_action_to_condition(smx_action, cond);
241 while ((smx_action = xbt_fifo_pop(actions_done))) {
242 xbt_fifo_item_t _cursor;
244 DEBUG1("** %s done **", smx_action->name);
245 xbt_fifo_foreach(smx_action->cond_list, _cursor, cond, smx_cond_t) {
246 xbt_swag_foreach(process, cond->sleeping) {
247 DEBUG2("\t preparing to wake up %s on %s",
248 process->name, process->simdata->smx_host->name);
250 SIMIX_cond_broadcast(cond);
251 /* remove conditional from action */
252 SIMIX_unregister_action_to_condition(smx_action, cond);
260 * \brief Kill all running process
263 void SIMIX_process_killall()
265 smx_process_t p = NULL;
266 smx_process_t self = SIMIX_process_self();
268 while ((p = xbt_swag_extract(simix_global->process_list))) {
270 SIMIX_process_kill(p);
273 xbt_context_empty_trash();
283 * \brief Clean the SIMIX simulation
285 * This functions remove all memories needed to the SIMIX execution
287 void SIMIX_clean(void)
289 smx_process_t p = NULL;
291 while ((p = xbt_swag_extract(simix_global->process_list))) {
292 SIMIX_process_kill(p);
295 xbt_dict_free(&(simix_global->host));
296 xbt_swag_free(simix_global->process_to_run);
297 xbt_swag_free(simix_global->process_list);
298 xbt_dict_free(&(simix_global->registered_functions));
299 simix_config_finalize();
310 * \brief A clock (in second).
312 * \return Return the clock.
314 double SIMIX_get_clock(void)
316 return surf_get_clock();
320 * \brief Finish the simulation initialization
322 * Must be called before the first call to SIMIX_solve()
324 void SIMIX_init(void)
330 * \brief Does a turn of the simulation
332 * Executes a step in the surf simulation, adding to the two lists all the actions that finished on this turn. Schedules all processus in the process_to_run list.
333 * \param actions_done List of actions done
334 * \param actions_failed List of actions failed
335 * \return The time spent to execute the simulation or -1 if the simulation ended
337 double SIMIX_solve(xbt_fifo_t actions_done, xbt_fifo_t actions_failed)
340 smx_process_t process = NULL;
342 double elapsed_time = 0.0;
343 static int state_modifications = 1;
345 xbt_context_empty_trash();
346 if (xbt_swag_size(simix_global->process_to_run) && (elapsed_time > 0)) {
347 DEBUG0("**************************************************");
350 while ((process = xbt_swag_extract(simix_global->process_to_run))) {
351 DEBUG2("Scheduling %s on %s",
352 process->name, process->simdata->smx_host->name);
353 simix_global->current_process = process;
354 xbt_context_schedule(process->simdata->context);
356 simix_global->current_process = NULL;
360 surf_action_t action = NULL;
361 surf_model_t model = NULL;
362 smx_action_t smx_action = NULL;
367 xbt_dynar_foreach(model_list, iter, model) {
368 if (xbt_swag_size(model->common_public->states.failed_action_set)
369 || xbt_swag_size(model->common_public->states.done_action_set)) {
370 state_modifications = 1;
375 if (!state_modifications) {
376 DEBUG1("%f : Calling surf_solve", SIMIX_get_clock());
377 elapsed_time = surf_solve();
378 DEBUG1("Elapsed_time %f", elapsed_time);
381 while (surf_timer_model->extension_public->get(&fun, (void *) &arg)) {
382 DEBUG2("got %p %p", fun, arg);
383 if (fun == SIMIX_process_create) {
384 smx_process_arg_t args = arg;
385 DEBUG2("Launching %s on %s", args->name, args->hostname);
386 process = SIMIX_process_create(args->name, args->code,
387 args->data, args->hostname,
388 args->argc, args->argv,
390 if (process && args->kill_time > SIMIX_get_clock()) {
391 surf_timer_model->extension_public->set(args->kill_time, (void *)
397 if (fun == SIMIX_process_kill) {
399 DEBUG2("Killing %s on %s", process->name,
400 process->simdata->smx_host->name);
401 SIMIX_process_kill(process);
405 /* Wake up all process waiting for the action finish */
406 xbt_dynar_foreach(model_list, iter, model) {
408 xbt_swag_extract(model->common_public->
409 states.failed_action_set))) {
410 smx_action = action->data;
412 xbt_fifo_unshift(actions_failed, smx_action);
416 xbt_swag_extract(model->common_public->
417 states.done_action_set))) {
418 smx_action = action->data;
420 xbt_fifo_unshift(actions_done, smx_action);
425 state_modifications = 0;
427 if (elapsed_time == -1) {
428 if (xbt_swag_size(simix_global->process_list) == 0) {
429 /* INFO0("Congratulations ! Simulation terminated : all processes are over"); */
431 INFO0("Oops ! Deadlock or code not perfectly clean.");
432 SIMIX_display_process_status();
433 if (XBT_LOG_ISENABLED(simix, xbt_log_priority_debug) ||
434 XBT_LOG_ISENABLED(simix_kernel, xbt_log_priority_debug)) {
438 INFO0("Return a Warning.");
445 * \brief Set the date to execute a function
447 * Set the date to execute the function on the surf.
448 * \param date Date to execute function
449 * \param function Function to be executed
450 * \param arg Parameters of the function
453 void SIMIX_timer_set(double date, void *function, void *arg)
455 surf_timer_model->extension_public->set(date, function, arg);
458 int SIMIX_timer_get(void **function, void **arg)
460 return surf_timer_model->extension_public->get(function, arg);
464 * \brief Registers a function to create a process.
466 * This function registers an user function to be called when a new process is created. The user function have to call the SIMIX_create_process function.
467 * \param function Create process function
470 void SIMIX_function_register_process_create(smx_creation_func_t function)
472 xbt_assert0((simix_global->create_process_function == NULL),
475 simix_global->create_process_function = function;
479 * \brief Registers a function to kill a process.
481 * This function registers an user function to be called when a new process is killed. The user function have to call the SIMIX_kill_process function.
482 * \param function Kill process function
485 void SIMIX_function_register_process_kill(void_f_pvoid_t function)
487 xbt_assert0((simix_global->kill_process_function == NULL),
490 simix_global->kill_process_function = function;
494 * \brief Registers a function to cleanup a process.
496 * This function registers an user function to be called when a new process ends properly.
497 * \param function cleanup process function
500 void SIMIX_function_register_process_cleanup(void_f_pvoid_t function)
502 simix_global->cleanup_process_function = function;