move more configurables and add documentation
[model-checker.git] / nodestack.cc
1 #include "nodestack.h"
2 #include "action.h"
3 #include "common.h"
4 #include "model.h"
5
6 /**
7  * @brief Node constructor
8  *
9  * Constructs a single Node for use in a NodeStack. Each Node is associated
10  * with exactly one ModelAction (exception: the first Node should be created
11  * as an empty stub, to represent the first thread "choice") and up to one
12  * parent.
13  *
14  * @param act The ModelAction to associate with this Node. May be NULL.
15  * @param par The parent Node in the NodeStack. May be NULL if there is no
16  * parent.
17  * @param nthreads The number of threads which exist at this point in the
18  * execution trace.
19  */
20 Node::Node(ModelAction *act, Node *par, int nthreads)
21         : action(act),
22         parent(par),
23         num_threads(nthreads),
24         explored_children(num_threads),
25         backtrack(num_threads),
26         numBacktracks(0),
27         may_read_from(),
28         read_from_index(0)
29 {
30         if (act)
31                 act->set_node(this);
32 }
33
34 /** @brief Node desctructor */
35 Node::~Node()
36 {
37         if (action)
38                 delete action;
39 }
40
41 /** Prints debugging info for the ModelAction associated with this Node */
42 void Node::print()
43 {
44         if (action)
45                 action->print();
46         else
47                 printf("******** empty action ********\n");
48 }
49
50 /** @brief Prints info about may_read_from set */
51 void Node::print_may_read_from()
52 {
53         readfrom_set_t::iterator it;
54         for (it = may_read_from.begin(); it != may_read_from.end(); it++)
55                 (*it)->print();
56 }
57
58 /**
59  * Checks if the Thread associated with this thread ID has been explored from
60  * this Node already.
61  * @param tid is the thread ID to check
62  * @return true if this thread choice has been explored already, false
63  * otherwise
64  */
65 bool Node::has_been_explored(thread_id_t tid)
66 {
67         int id = id_to_int(tid);
68         return explored_children[id];
69 }
70
71 /**
72  * Checks if the backtracking set is empty.
73  * @return true if the backtracking set is empty
74  */
75 bool Node::backtrack_empty()
76 {
77         return (numBacktracks == 0);
78 }
79
80
81 /**
82  * Checks whether the readsfrom set for this node is empty.
83  * @return true if the readsfrom set is empty.
84  */
85 bool Node::readsfrom_empty() {
86         return ((read_from_index+1)>=may_read_from.size());
87 }
88
89 /**
90  * Mark the appropriate backtracking infromation for exploring a thread choice.
91  * @param act The ModelAction to explore
92  */
93 void Node::explore_child(ModelAction *act)
94 {
95         explore(act->get_tid());
96 }
97
98 /**
99  * Records a backtracking reference for a thread choice within this Node.
100  * Provides feedback as to whether this thread choice is already set for
101  * backtracking.
102  * @return false if the thread was already set to be backtracked, true
103  * otherwise
104  */
105 bool Node::set_backtrack(thread_id_t id)
106 {
107         int i = id_to_int(id);
108         if (backtrack[i])
109                 return false;
110         backtrack[i] = true;
111         numBacktracks++;
112         return true;
113 }
114
115 thread_id_t Node::get_next_backtrack()
116 {
117         /** @todo Find next backtrack */
118         unsigned int i;
119         for (i = 0; i < backtrack.size(); i++)
120                 if (backtrack[i] == true)
121                         break;
122         /* Backtrack set was empty? */
123         ASSERT(i != backtrack.size());
124
125         backtrack[i] = false;
126         numBacktracks--;
127         return int_to_id(i);
128 }
129
130 bool Node::is_enabled(Thread *t)
131 {
132         return id_to_int(t->get_id()) < num_threads;
133 }
134
135 /**
136  * Add an action to the may_read_from set.
137  * @param act is the action to add
138  */
139 void Node::add_read_from(const ModelAction *act)
140 {
141         may_read_from.push_back(act);
142 }
143
144 /**
145  * Gets the next 'may_read_from' action from this Node. Only valid for a node
146  * where this->action is a 'read'.
147  * @todo Perform reads_from backtracking/replay properly, so that this function
148  * may remove elements from may_read_from
149  * @return The first element in may_read_from
150  */
151 const ModelAction * Node::get_read_from() {
152         ASSERT(read_from_index<may_read_from.size());
153         return may_read_from[read_from_index];
154 }
155
156 /**
157  * Increments the index into the readsfrom set to explore the next item.
158  * @return Returns false if we have explored all items.
159  */
160 bool Node::increment_read_from() {
161         read_from_index++;
162         return (read_from_index<may_read_from.size());
163 }
164
165 void Node::explore(thread_id_t tid)
166 {
167         int i = id_to_int(tid);
168         if (backtrack[i]) {
169                 backtrack[i] = false;
170                 numBacktracks--;
171         }
172         explored_children[i] = true;
173 }
174
175 static void clear_node_list(node_list_t *list, node_list_t::iterator start,
176                                                node_list_t::iterator end)
177 {
178         node_list_t::iterator it;
179
180         for (it = start; it != end; it++)
181                 delete (*it);
182         list->erase(start, end);
183 }
184
185 NodeStack::NodeStack()
186         : total_nodes(0)
187 {
188         node_list.push_back(new Node());
189         total_nodes++;
190         iter = node_list.begin();
191 }
192
193 NodeStack::~NodeStack()
194 {
195         clear_node_list(&node_list, node_list.begin(), node_list.end());
196 }
197
198 void NodeStack::print()
199 {
200         node_list_t::iterator it;
201         printf("............................................\n");
202         printf("NodeStack printing node_list:\n");
203         for (it = node_list.begin(); it != node_list.end(); it++) {
204                 if (it == this->iter)
205                         printf("vvv following action is the current iterator vvv\n");
206                 (*it)->print();
207         }
208         printf("............................................\n");
209 }
210
211 ModelAction * NodeStack::explore_action(ModelAction *act)
212 {
213         DBG();
214
215         ASSERT(!node_list.empty());
216         node_list_t::iterator it=iter;
217         it++;
218
219         if (it != node_list.end()) {
220                 iter++;
221                 return (*iter)->get_action();
222         }
223
224         /* Record action */
225         get_head()->explore_child(act);
226         node_list.push_back(new Node(act, get_head(), model->get_num_threads()));
227         total_nodes++;
228         iter++;
229         return NULL;
230 }
231
232 /**
233  * Empties the stack of all trailing nodes after a given position and calls the
234  * destructor for each. This function is provided an offset which determines
235  * how many nodes (relative to the current replay state) to save before popping
236  * the stack.
237  * @param numAhead gives the number of Nodes (including this Node) to skip over
238  * before removing nodes.
239  */
240 void NodeStack::pop_restofstack(int numAhead)
241 {
242         /* Diverging from previous execution; clear out remainder of list */
243         node_list_t::iterator it = iter;
244         while (numAhead--)
245                 it++;
246         clear_node_list(&node_list, it, node_list.end());
247 }
248
249 Node * NodeStack::get_head()
250 {
251         if (node_list.empty())
252                 return NULL;
253         return *iter;
254 }
255
256 Node * NodeStack::get_next()
257 {
258         node_list_t::iterator it = iter;
259         if (node_list.empty()) {
260                 DEBUG("Empty\n");
261                 return NULL;
262         }
263         it++;
264         if (it == node_list.end()) {
265                 DEBUG("At end\n");
266                 return NULL;
267         }
268         return *it;
269 }
270
271 void NodeStack::reset_execution()
272 {
273         iter = node_list.begin();
274 }