Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Some more memleaks removed
[simgrid.git] / src / msg / msg_actions.c
1 /* Copyright (c) 2009 The SimGrid team. All rights reserved.                */
2
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. */
5
6 #include "simgrid_config.h"     /* getline */
7 #include "msg/private.h"
8 #include "xbt/str.h"
9 #include "xbt/dynar.h"
10
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_action,msg,"MSG actions for trace driven simulation");
12
13 static xbt_dict_t action_funs;
14 static xbt_dict_t action_queues;
15
16 static xbt_dynar_t action_get_action(char *name);
17
18 /** \ingroup msg_actions
19  * \brief Registers a function to handle a kind of action
20  *
21  * Registers a function to handle a kind of action
22  * This table is then used by #MSG_action_trace_run
23  *
24  * The argument of the function is the line describing the action, splitted on spaces with xbt_str_split_quoted()
25  *
26  * \param name the reference name of the action.
27  * \param code the function; prototype given by the type: void...(xbt_dynar_t action)
28  */
29 void MSG_action_register(const char *action_name, msg_action_fun function)
30 {
31   xbt_dict_set(action_funs, action_name, function, NULL);
32 }
33
34 /** \ingroup msg_actions
35  * \brief Unregisters a function, which handled a kind of action
36  *
37  * \param name the reference name of the action.
38  */
39 void MSG_action_unregister(const char *action_name)
40 {
41   xbt_dict_remove(action_funs, action_name);
42 }
43
44 static int MSG_action_runner(int argc, char *argv[])
45 {
46   xbt_dynar_t evt=NULL;
47
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 *));
51     (*function) (evt);
52     xbt_dynar_free(&evt);
53   }
54
55   return 0;
56 }
57
58 void _MSG_action_init()
59 {
60   action_funs = xbt_dict_new();
61   action_queues = xbt_dict_new();
62   MSG_function_register_default(MSG_action_runner);
63 }
64
65 void _MSG_action_exit() {
66   xbt_dict_free(&action_queues);
67   xbt_dict_free(&action_funs);
68 }
69
70 static FILE *action_fp=NULL;
71 static char *action_line = NULL;
72 static size_t action_len = 0;
73
74 static xbt_dynar_t action_get_action(char *name) {
75   ssize_t read;
76   xbt_dynar_t evt=NULL;
77
78
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
81
82     if (action_fp==NULL) { // File closed now. There's nothing more to read. I'm out of here
83       goto todo_done;
84     }
85
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, '#');
90       if (comment != NULL)
91         *comment = '\0';
92       xbt_str_trim(action_line, NULL);
93       if (action_line[0] == '\0')
94         continue;
95       evt = xbt_str_split_quoted(action_line);
96
97       // if it's for me, I'm done
98       char *evtname = xbt_dynar_get_as(evt, 0, char *);
99       if (!strcmp(name,evtname)) {
100         return evt;
101       } else {
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);
107         }
108         xbt_dynar_push(otherqueue,&evt);
109       }
110     }
111     goto todo_done; // end of file reached in vain while searching for more work
112   } else {
113     // Get something from my queue and return it
114     xbt_dynar_shift(myqueue,&evt);
115     return evt;
116   }
117
118
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);
123   }
124   return NULL;
125 }
126
127 /** \ingroup msg_actions
128  * \brief A trace loader
129  *
130  *  Load a trace file containing actions, and execute them.
131  */
132 MSG_error_t MSG_action_trace_run(char *path)
133 {
134   MSG_error_t res;
135
136   action_fp = fopen(path, "r");
137   xbt_assert2(action_fp != NULL, "Cannot open %s: %s", path, strerror(errno));
138
139   res = MSG_main();
140
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;
144     char *name;
145     xbt_dynar_t todo;
146
147     xbt_dict_foreach(action_queues,cursor,name,todo) {
148       WARN2("Still %lu actions for %s",xbt_dynar_length(todo),name);
149     }
150   }
151
152   if (action_line)
153     free(action_line);
154   fclose(action_fp);
155   xbt_dict_free(&action_queues);
156   action_queues = xbt_dict_new();
157
158   return res;
159 }