77e24398931a0a2ee3d9e7bb662813ae4f3f7231
[c11tester.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         future_values(),
30         future_index(-1)
31 {
32         if (act)
33                 act->set_node(this);
34 }
35
36 /** @brief Node desctructor */
37 Node::~Node()
38 {
39         if (action)
40                 delete action;
41 }
42
43 /** Prints debugging info for the ModelAction associated with this Node */
44 void Node::print()
45 {
46         if (action)
47                 action->print();
48         else
49                 printf("******** empty action ********\n");
50 }
51
52 /** @brief Prints info about may_read_from set */
53 void Node::print_may_read_from()
54 {
55         readfrom_set_t::iterator it;
56         for (it = may_read_from.begin(); it != may_read_from.end(); it++)
57                 (*it)->print();
58 }
59
60 /** This method sets a promise to explore meeting with the given
61  *  node. 
62  *  @param i is the promise index.
63  */
64
65 void Node::set_promise(uint32_t i) {
66         if (i>=promises.size())
67                 promises.resize(i+1,0);
68         promises[i]=1;
69 }
70
71 /** This method looks up whether a given promise should be satisfied
72  *  by this node.
73  *
74  * @param i is the promise index.
75  * @return true if the promise should be satisfied by the given model action.
76  */
77
78 bool Node::get_promise(uint32_t i) {
79         return (i<promises.size())&&(promises[i]==2);
80 }
81
82 /** This method increments to the next combination of promises.
83  *
84  * @return true if we have a valid combination.
85  */
86
87 bool Node::increment_promise() {
88         for (unsigned int i=0;i<promises.size();i++) {
89                 if (promises[i]==1) {
90                         promises[i]=2;
91                         while (i>0) {
92                                 i--;
93                                 if (promises[i]==2)
94                                         promises[i]=1;
95                         }
96                         return true;
97                 }
98         }
99         return false;
100 }
101
102 /** This method returns whether the promise set is empty. 
103  *
104  *  @return true if we have explored all promise combinations.
105  */
106
107 bool Node::promise_empty() {
108         for (unsigned int i=0;i<promises.size();i++)
109                 if (promises[i]==1)
110                         return false;
111         return true;
112 }
113
114 /**
115  * Adds a value from a weakly ordered future write to backtrack to.
116  * @param value is the value to backtrack to.
117  */
118
119 bool Node::add_future_value(uint64_t value) {
120         for(unsigned int i=0;i<future_values.size();i++)
121                 if (future_values[i]==value)
122                         return false;
123
124         future_values.push_back(value);
125         return true;
126 }
127
128 /** 
129  * Checks whether the future_values set for this node is empty.
130  * @return true if the future_values set is empty.
131  */
132
133 bool Node::future_value_empty() {
134         return ((future_index+1)>=future_values.size());
135 }
136
137
138 /**
139  * Checks if the Thread associated with this thread ID has been explored from
140  * this Node already.
141  * @param tid is the thread ID to check
142  * @return true if this thread choice has been explored already, false
143  * otherwise
144  */
145 bool Node::has_been_explored(thread_id_t tid)
146 {
147         int id = id_to_int(tid);
148         return explored_children[id];
149 }
150
151 /**
152  * Checks if the backtracking set is empty.
153  * @return true if the backtracking set is empty
154  */
155 bool Node::backtrack_empty()
156 {
157         return (numBacktracks == 0);
158 }
159
160
161 /**
162  * Checks whether the readsfrom set for this node is empty.
163  * @return true if the readsfrom set is empty.
164  */
165 bool Node::read_from_empty() {
166         return ((read_from_index+1)>=may_read_from.size());
167 }
168
169
170
171 /**
172  * Mark the appropriate backtracking information for exploring a thread choice.
173  * @param act The ModelAction to explore
174  */
175 void Node::explore_child(ModelAction *act)
176 {
177         explore(act->get_tid());
178 }
179
180 /**
181  * Records a backtracking reference for a thread choice within this Node.
182  * Provides feedback as to whether this thread choice is already set for
183  * backtracking.
184  * @return false if the thread was already set to be backtracked, true
185  * otherwise
186  */
187 bool Node::set_backtrack(thread_id_t id)
188 {
189         int i = id_to_int(id);
190         if (backtrack[i])
191                 return false;
192         backtrack[i] = true;
193         numBacktracks++;
194         return true;
195 }
196
197 thread_id_t Node::get_next_backtrack()
198 {
199         /** @todo Find next backtrack */
200         unsigned int i;
201         for (i = 0; i < backtrack.size(); i++)
202                 if (backtrack[i] == true)
203                         break;
204         /* Backtrack set was empty? */
205         ASSERT(i != backtrack.size());
206
207         backtrack[i] = false;
208         numBacktracks--;
209         return int_to_id(i);
210 }
211
212 bool Node::is_enabled(Thread *t)
213 {
214         return id_to_int(t->get_id()) < num_threads;
215 }
216
217 /**
218  * Add an action to the may_read_from set.
219  * @param act is the action to add
220  */
221 void Node::add_read_from(const ModelAction *act)
222 {
223         may_read_from.push_back(act);
224 }
225
226 /**
227  * Gets the next 'future_value' value from this Node. Only valid for a node
228  * where this->action is a 'read'.
229  * @return The first element in future_values
230  */
231
232 uint64_t Node::get_future_value() {
233         ASSERT(future_index<future_values.size());
234         return future_values[future_index];
235 }
236
237 /**
238  * Gets the next 'may_read_from' action from this Node. Only valid for a node
239  * where this->action is a 'read'.
240  * @todo Perform reads_from backtracking/replay properly, so that this function
241  * may remove elements from may_read_from
242  * @return The first element in may_read_from
243  */
244 const ModelAction * Node::get_read_from() {
245         if (read_from_index<may_read_from.size())
246                 return may_read_from[read_from_index];
247         else
248                 return NULL;
249 }
250
251 /**
252  * Increments the index into the readsfrom set to explore the next item.
253  * @return Returns false if we have explored all items.
254  */
255 bool Node::increment_read_from() {
256         read_from_index++;
257         return (read_from_index<may_read_from.size());
258 }
259
260 /**
261  * Increments the index into the future_values set to explore the next item.
262  * @return Returns false if we have explored all values.
263  */
264
265 bool Node::increment_future_value() {
266         future_index++;
267         return (future_index<future_values.size());
268 }
269
270 void Node::explore(thread_id_t tid)
271 {
272         int i = id_to_int(tid);
273         if (backtrack[i]) {
274                 backtrack[i] = false;
275                 numBacktracks--;
276         }
277         explored_children[i] = true;
278 }
279
280 static void clear_node_list(node_list_t *list, node_list_t::iterator start,
281                                                node_list_t::iterator end)
282 {
283         node_list_t::iterator it;
284
285         for (it = start; it != end; it++)
286                 delete (*it);
287         list->erase(start, end);
288 }
289
290 NodeStack::NodeStack()
291         : total_nodes(0)
292 {
293         node_list.push_back(new Node());
294         total_nodes++;
295         iter = node_list.begin();
296 }
297
298 NodeStack::~NodeStack()
299 {
300         clear_node_list(&node_list, node_list.begin(), node_list.end());
301 }
302
303 void NodeStack::print()
304 {
305         node_list_t::iterator it;
306         printf("............................................\n");
307         printf("NodeStack printing node_list:\n");
308         for (it = node_list.begin(); it != node_list.end(); it++) {
309                 if (it == this->iter)
310                         printf("vvv following action is the current iterator vvv\n");
311                 (*it)->print();
312         }
313         printf("............................................\n");
314 }
315
316 ModelAction * NodeStack::explore_action(ModelAction *act)
317 {
318         DBG();
319
320         ASSERT(!node_list.empty());
321         node_list_t::iterator it=iter;
322         it++;
323
324         if (it != node_list.end()) {
325                 iter++;
326                 return (*iter)->get_action();
327         }
328
329         /* Record action */
330         get_head()->explore_child(act);
331         node_list.push_back(new Node(act, get_head(), model->get_num_threads()));
332         total_nodes++;
333         iter++;
334         return NULL;
335 }
336
337 /**
338  * Empties the stack of all trailing nodes after a given position and calls the
339  * destructor for each. This function is provided an offset which determines
340  * how many nodes (relative to the current replay state) to save before popping
341  * the stack.
342  * @param numAhead gives the number of Nodes (including this Node) to skip over
343  * before removing nodes.
344  */
345 void NodeStack::pop_restofstack(int numAhead)
346 {
347         /* Diverging from previous execution; clear out remainder of list */
348         node_list_t::iterator it = iter;
349         while (numAhead--)
350                 it++;
351         clear_node_list(&node_list, it, node_list.end());
352 }
353
354 Node * NodeStack::get_head()
355 {
356         if (node_list.empty())
357                 return NULL;
358         return *iter;
359 }
360
361 Node * NodeStack::get_next()
362 {
363         node_list_t::iterator it = iter;
364         if (node_list.empty()) {
365                 DEBUG("Empty\n");
366                 return NULL;
367         }
368         it++;
369         if (it == node_list.end()) {
370                 DEBUG("At end\n");
371                 return NULL;
372         }
373         return *it;
374 }
375
376 void NodeStack::reset_execution()
377 {
378         iter = node_list.begin();
379 }