nodestack: don't perform linear search to check if backtrack is empty
[model-checker.git] / nodestack.cc
1 #include "nodestack.h"
2 #include "action.h"
3 #include "common.h"
4 #include "model.h"
5
6 /** @brief Node constructor */
7 Node::Node(ModelAction *act, int nthreads)
8         : action(act),
9         num_threads(nthreads),
10         explored_children(num_threads),
11         backtrack(num_threads),
12         numBacktracks(0)
13 {
14 }
15
16 /** @brief Node desctructor */
17 Node::~Node()
18 {
19         if (action)
20                 delete action;
21 }
22
23 /** Prints debugging info for the ModelAction associated with this Node */
24 void Node::print()
25 {
26         if (action)
27                 action->print();
28         else
29                 printf("******** empty action ********\n");
30 }
31
32 /**
33  * Checks if the Thread associated with this thread ID has been explored from
34  * this Node already.
35  * @param tid is the thread ID to check
36  * @return true if this thread choice has been explored already, false
37  * otherwise
38  */
39 bool Node::has_been_explored(thread_id_t tid)
40 {
41         int id = id_to_int(tid);
42         return explored_children[id];
43 }
44
45 /**
46  * Checks if the backtracking set is empty.
47  * @return true if the backtracking set is empty
48  */
49 bool Node::backtrack_empty()
50 {
51         return numBacktracks == 0;
52 }
53
54 /**
55  * Explore a child Node using a given ModelAction. This updates both the
56  * Node-internal and the ModelAction data to associate the ModelAction with
57  * this Node.
58  * @param act is the ModelAction to explore
59  */
60 void Node::explore_child(ModelAction *act)
61 {
62         act->set_node(this);
63         explore(act->get_tid());
64 }
65
66 /**
67  * Records a backtracking reference for a thread choice within this Node.
68  * Provides feedback as to whether this thread choice is already set for
69  * backtracking.
70  * @return false if the thread was already set to be backtracked, true
71  * otherwise
72  */
73 bool Node::set_backtrack(thread_id_t id)
74 {
75         int i = id_to_int(id);
76         if (backtrack[i])
77                 return false;
78         backtrack[i] = true;
79         numBacktracks++;
80         return true;
81 }
82
83 thread_id_t Node::get_next_backtrack()
84 {
85         /* TODO: find next backtrack */
86         unsigned int i;
87         for (i = 0; i < backtrack.size(); i++)
88                 if (backtrack[i] == true)
89                         break;
90         if (i >= backtrack.size())
91                 return THREAD_ID_T_NONE;
92         backtrack[i] = false;
93         numBacktracks--;
94         return int_to_id(i);
95 }
96
97 bool Node::is_enabled(Thread *t)
98 {
99         return id_to_int(t->get_id()) < num_threads;
100 }
101
102 void Node::explore(thread_id_t tid)
103 {
104         int i = id_to_int(tid);
105         if (backtrack[i]) {
106                 backtrack[i] = false;
107                 numBacktracks--;
108         }
109         explored_children[i] = true;
110 }
111
112 static void clear_node_list(node_list_t *list, node_list_t::iterator start,
113                                                node_list_t::iterator end)
114 {
115         node_list_t::iterator it;
116
117         for (it = start; it != end; it++)
118                 delete (*it);
119         list->erase(start, end);
120 }
121
122 NodeStack::NodeStack()
123         : total_nodes(0)
124 {
125         node_list.push_back(new Node());
126         total_nodes++;
127         iter = node_list.begin();
128 }
129
130 NodeStack::~NodeStack()
131 {
132         clear_node_list(&node_list, node_list.begin(), node_list.end());
133 }
134
135 void NodeStack::print()
136 {
137         node_list_t::iterator it;
138         printf("............................................\n");
139         printf("NodeStack printing node_list:\n");
140         for (it = node_list.begin(); it != node_list.end(); it++) {
141                 if (it == this->iter)
142                         printf("vvv following action is the current iterator vvv\n");
143                 (*it)->print();
144         }
145         printf("............................................\n");
146 }
147
148 ModelAction * NodeStack::explore_action(ModelAction *act)
149 {
150         DBG();
151
152         ASSERT(!node_list.empty());
153
154         if (get_head()->has_been_explored(act->get_tid())) {
155                 iter++;
156                 return (*iter)->get_action();
157         }
158
159         /* Diverging from previous execution; clear out remainder of list */
160         node_list_t::iterator it = iter;
161         it++;
162         clear_node_list(&node_list, it, node_list.end());
163
164         /* Record action */
165         get_head()->explore_child(act);
166         node_list.push_back(new Node(act, model->get_num_threads()));
167         total_nodes++;
168         iter++;
169         return NULL;
170 }
171
172 Node * NodeStack::get_head()
173 {
174         if (node_list.empty())
175                 return NULL;
176         return *iter;
177 }
178
179 Node * NodeStack::get_next()
180 {
181         node_list_t::iterator it = iter;
182         if (node_list.empty()) {
183                 DEBUG("Empty\n");
184                 return NULL;
185         }
186         it++;
187         if (it == node_list.end()) {
188                 DEBUG("At end\n");
189                 return NULL;
190         }
191         return *it;
192 }
193
194 void NodeStack::reset_execution()
195 {
196         iter = node_list.begin();
197 }