1 /* Copyright (c) 2009 The SimGrid team. All rights reserved. */
3 /* This program is free software; you can redistribute it and/or modify it
4 * under the terms of the license (GNU LGPL) which comes with this package. */
6 #include "simgrid_config.h" /* getline */
7 #include "msg/private.h"
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_action,msg,"MSG actions for trace driven simulation");
13 static xbt_dict_t action_funs;
14 static xbt_dict_t action_queues;
16 static xbt_dynar_t action_get_action(char *name);
18 /** \ingroup msg_actions
19 * \brief Registers a function to handle a kind of action
21 * Registers a function to handle a kind of action
22 * This table is then used by #MSG_action_trace_run
24 * The argument of the function is the line describing the action, splitted on spaces with xbt_str_split_quoted()
26 * \param name the reference name of the action.
27 * \param code the function; prototype given by the type: void...(xbt_dynar_t action)
29 void MSG_action_register(const char *action_name, msg_action_fun function)
31 xbt_dict_set(action_funs, action_name, function, NULL);
34 /** \ingroup msg_actions
35 * \brief Unregisters a function, which handled a kind of action
37 * \param name the reference name of the action.
39 void MSG_action_unregister(const char *action_name)
41 xbt_dict_remove(action_funs, action_name);
44 static int MSG_action_runner(int argc, char *argv[])
48 while ((evt = action_get_action(argv[0]))) {
49 msg_action_fun function =
50 xbt_dict_get(action_funs, xbt_dynar_get_as(evt, 1, char *));
58 void _MSG_action_init()
60 action_funs = xbt_dict_new();
61 action_queues = xbt_dict_new();
62 MSG_function_register_default(MSG_action_runner);
65 void _MSG_action_exit() {
66 xbt_dict_free(&action_queues);
67 xbt_dict_free(&action_funs);
70 static FILE *action_fp=NULL;
71 static char *action_line = NULL;
72 static size_t action_len = 0;
74 static xbt_dynar_t action_get_action(char *name) {
79 xbt_dynar_t myqueue = xbt_dict_get_or_null(action_queues,name);
80 if (myqueue==NULL || xbt_dynar_length(myqueue)==0) { // nothing stored for me. Read the file further
82 if (action_fp==NULL) { // File closed now. There's nothing more to read. I'm out of here
86 // Read lines until I reach something for me (which breaks in loop body) or end of file
87 while ((read = getline(&action_line, &action_len, action_fp)) != -1) {
88 // cleanup and split the string I just read
89 char *comment = strchr(action_line, '#');
92 xbt_str_trim(action_line, NULL);
93 if (action_line[0] == '\0')
95 evt = xbt_str_split_quoted(action_line);
97 // if it's for me, I'm done
98 char *evtname = xbt_dynar_get_as(evt, 0, char *);
99 if (!strcmp(name,evtname)) {
102 // Else, I have to store it for the relevant colleague
103 xbt_dynar_t otherqueue = xbt_dict_get_or_null(action_queues,evtname);
104 if (otherqueue == NULL) { // Damn. Create the queue of that guy
105 otherqueue = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
106 xbt_dict_set(action_queues ,evtname, otherqueue, NULL);
108 xbt_dynar_push(otherqueue,&evt);
111 goto todo_done; // end of file reached in vain while searching for more work
113 // Get something from my queue and return it
114 xbt_dynar_shift(myqueue,&evt);
119 todo_done: // I did all my actions for me in the file. cleanup before leaving
120 if (myqueue != NULL) {
121 xbt_dynar_free(&myqueue);
122 xbt_dict_remove(action_queues,name);
127 /** \ingroup msg_actions
128 * \brief A trace loader
130 * Load a trace file containing actions, and execute them.
132 MSG_error_t MSG_action_trace_run(char *path)
136 action_fp = fopen(path, "r");
137 xbt_assert2(action_fp != NULL, "Cannot open %s: %s", path, strerror(errno));
141 if (xbt_dict_size(action_queues)) {
142 WARN0("Not all actions got consumed. If the simulation ended successfully (without deadlock), you may want to add new processes to your deployment file.");
143 xbt_dict_cursor_t cursor;
147 xbt_dict_foreach(action_queues,cursor,name,todo) {
148 WARN2("Still %lu actions for %s",xbt_dynar_length(todo),name);
155 xbt_dict_free(&action_queues);
156 action_queues = xbt_dict_new();