Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
On the fly parsing of the actions file. One idle process can still force the whole...
[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 static xbt_dict_t action_funs;
12 static xbt_dict_t action_queues;
13
14 static xbt_dynar_t action_get_action(char *name);
15
16 /** \ingroup msg_actions
17  * \brief Registers a function to handle a kind of action
18  *
19  * Registers a function to handle a kind of action
20  * This table is then used by #MSG_action_trace_run
21  *
22  * The argument of the function is the line describing the action, splitted on spaces with xbt_str_split_quoted()
23  *
24  * \param name the reference name of the action.
25  * \param code the function; prototype given by the type: void...(xbt_dynar_t action)
26  */
27 void MSG_action_register(const char *action_name, msg_action_fun function)
28 {
29   xbt_dict_set(action_funs, action_name, function, NULL);
30 }
31
32 /** \ingroup msg_actions
33  * \brief Unregisters a function, which handled a kind of action
34  *
35  * \param name the reference name of the action.
36  */
37 void MSG_action_unregister(const char *action_name)
38 {
39   xbt_dict_remove(action_funs, action_name);
40 }
41
42 static int MSG_action_runner(int argc, char *argv[])
43 {
44   xbt_dynar_t evt=NULL;
45
46   while ((evt = action_get_action(argv[0]))) {
47       msg_action_fun function =
48         xbt_dict_get(action_funs, xbt_dynar_get_as(evt, 1, char *));
49       (*function) (evt);
50       xbt_dynar_free(&evt);
51   }
52
53   return 0;
54 }
55
56 void _MSG_action_init()
57 {
58   action_funs = xbt_dict_new();
59   action_queues = xbt_dict_new();
60   MSG_function_register_default(MSG_action_runner);
61 }
62
63 void _MSG_action_exit() {
64   xbt_dict_free(&action_queues);
65   action_queues = xbt_dict_new();
66 }
67
68 static FILE *action_fp=NULL;
69 static char *action_line = NULL;
70 static size_t action_len = 0;
71
72 static xbt_dynar_t action_get_action(char *name) {
73   ssize_t read;
74   xbt_dynar_t evt=NULL;
75
76
77   xbt_dynar_t myqueue = xbt_dict_get_or_null(action_queues,name);
78   if (myqueue==NULL || xbt_dynar_length(myqueue)==0) { // nothing stored for me. Read the file further
79
80     if (action_fp==NULL) { // File closed now. There's nothing more to read. I'm out of here
81       return NULL;
82     }
83
84     // Read lines until I reach something for me (which breaks in loop body) or end of file
85     while ((read = getline(&action_line, &action_len, action_fp)) != -1) {
86       // cleanup and split the string I just read
87       char *comment = strchr(action_line, '#');
88       if (comment != NULL)
89         *comment = '\0';
90       xbt_str_trim(action_line, NULL);
91       if (action_line[0] == '\0')
92         continue;
93       evt = xbt_str_split_quoted(action_line);
94
95       // if it's for me, I'm done
96       char *evtname = xbt_dynar_get_as(evt, 0, char *);
97       if (!strcmp(name,evtname)) {
98         return evt;
99       } else {
100         // Else, I have to store it for the relevant colleague
101         xbt_dynar_t otherqueue = xbt_dict_get_or_null(action_queues,evtname);
102         if (otherqueue == NULL) { // Damn. Create the queue of that guy
103           otherqueue = xbt_dynar_new(sizeof(xbt_dynar_t), xbt_dynar_free_voidp);
104           xbt_dict_set(action_queues ,evtname, otherqueue, NULL/*xbt_dynar_free_voidp*/);
105         }
106         xbt_dynar_push(otherqueue,&evt);
107       }
108     }
109     return NULL; // end of file reached in vain while searching for more work
110   } else {
111     // Get something from my queue and return it
112     xbt_dynar_shift(myqueue,&evt);
113     return evt;
114   }
115 }
116
117 /** \ingroup msg_actions
118  * \brief A trace loader
119  *
120  *  Load a trace file containing actions, and execute them.
121  */
122 MSG_error_t MSG_action_trace_run(char *path)
123 {
124   MSG_error_t res;
125
126   action_fp = fopen(path, "r");
127   xbt_assert2(action_fp != NULL, "Cannot open %s: %s", path, strerror(errno));
128
129   res = MSG_main();
130
131   if (action_line)
132     free(action_line);
133   fclose(action_fp);
134
135   return res;
136 }