7 #include "snapshot-interface.h"
10 #define INITIAL_THREAD_ID 0
14 /** @brief Constructor */
15 ModelChecker::ModelChecker()
17 /* Initialize default scheduler */
18 scheduler(new Scheduler()),
19 /* First thread created will have id INITIAL_THREAD_ID */
20 next_thread_id(INITIAL_THREAD_ID),
21 used_sequence_numbers(0),
26 nextThread(THREAD_ID_T_NONE),
27 action_trace(new action_list_t()),
28 thread_map(new std::map<int, class Thread *>),
29 obj_thrd_map(new std::map<void *, std::vector<action_list_t> >()),
30 thrd_last_action(new std::vector<ModelAction *>(1)),
31 node_stack(new NodeStack()),
36 /** @brief Destructor */
37 ModelChecker::~ModelChecker()
39 std::map<int, class Thread *>::iterator it;
40 for (it = thread_map->begin(); it != thread_map->end(); it++)
46 delete thrd_last_action;
52 * Restores user program to initial state and resets all model-checker data
55 void ModelChecker::reset_to_initial_state()
57 DEBUG("+++ Resetting to initial state +++\n");
58 node_stack->reset_execution();
59 current_action = NULL;
60 next_thread_id = INITIAL_THREAD_ID;
61 used_sequence_numbers = 0;
63 next_backtrack = NULL;
64 snapshotObject->backTrackBeforeStep(0);
67 /** @returns a thread ID for a new Thread */
68 thread_id_t ModelChecker::get_next_id()
70 return next_thread_id++;
73 /** @returns the number of user threads created during this execution */
74 int ModelChecker::get_num_threads()
76 return next_thread_id;
79 /** @returns a sequence number for a new ModelAction */
80 int ModelChecker::get_next_seq_num()
82 return ++used_sequence_numbers;
86 * Performs the "scheduling" for the model-checker. That is, it checks if the
87 * model-checker has selected a "next thread to run" and returns it, if
88 * available. This function should be called from the Scheduler routine, where
89 * the Scheduler falls back to a default scheduling routine if needed.
91 * @return The next thread chosen by the model-checker. If the model-checker
92 * makes no selection, retuns NULL.
94 Thread * ModelChecker::schedule_next_thread()
97 if (nextThread == THREAD_ID_T_NONE)
99 t = (*thread_map)[id_to_int(nextThread)];
107 * Choose the next thread in the replay sequence.
109 * If the replay sequence has reached the 'diverge' point, returns a thread
110 * from the backtracking set. Otherwise, simply returns the next thread in the
111 * sequence that is being replayed.
113 thread_id_t ModelChecker::get_next_replay_thread()
118 /* Have we completed exploring the preselected path? */
120 return THREAD_ID_T_NONE;
122 /* Else, we are trying to replay an execution */
123 next = node_stack->get_next()->get_action();
125 if (next == diverge) {
126 Node *node = next->get_node();
128 /* Reached divergence point */
129 DEBUG("*** Divergence point ***\n");
130 tid = node->get_next_backtrack();
133 tid = next->get_tid();
135 DEBUG("*** ModelChecker chose next thread = %d ***\n", tid);
140 * Queries the model-checker for more executions to explore and, if one
141 * exists, resets the model-checker state to execute a new execution.
143 * @return If there are more executions to explore, return true. Otherwise,
146 bool ModelChecker::next_execution()
152 if ((diverge = model->get_next_backtrack()) == NULL)
156 printf("Next execution will diverge at:\n");
160 model->reset_to_initial_state();
164 ModelAction * ModelChecker::get_last_conflict(ModelAction *act)
166 action_type type = act->get_type();
178 /* linear search: from most recent to oldest */
179 action_list_t::reverse_iterator rit;
180 for (rit = action_trace->rbegin(); rit != action_trace->rend(); rit++) {
181 ModelAction *prev = *rit;
182 if (act->is_synchronizing(prev))
188 void ModelChecker::set_backtracking(ModelAction *act)
192 Thread *t = get_thread(act->get_tid());
194 prev = get_last_conflict(act);
198 node = prev->get_node();
200 while (!node->is_enabled(t))
203 /* Check if this has been explored already */
204 if (node->has_been_explored(t->get_id()))
207 if (!next_backtrack || *prev > *next_backtrack)
208 next_backtrack = prev;
210 /* If this is a new backtracking point, mark the tree */
211 if (!node->set_backtrack(t->get_id()))
213 DEBUG("Setting backtrack: conflict = %d, instead tid = %d\n",
214 prev->get_tid(), t->get_id());
221 ModelAction * ModelChecker::get_next_backtrack()
223 ModelAction *next = next_backtrack;
224 next_backtrack = NULL;
228 void ModelChecker::check_current_action(void)
232 ModelAction *curr = this->current_action;
234 current_action = NULL;
236 DEBUG("trying to push NULL action...\n");
240 tmp = node_stack->explore_action(curr);
242 /* Discard duplicate ModelAction */
246 curr->create_cv(get_parent_action(curr->get_tid()));
249 /* Assign 'creation' parent */
250 if (curr->get_type() == THREAD_CREATE) {
251 Thread *th = (Thread *)curr->get_location();
252 th->set_creation(curr);
255 nextThread = get_next_replay_thread();
257 currnode = curr->get_node();
259 if (!currnode->backtrack_empty())
260 if (!next_backtrack || *curr > *next_backtrack)
261 next_backtrack = curr;
263 set_backtracking(curr);
265 add_action_to_lists(curr);
270 * Adds an action to the per-object, per-thread action vector.
271 * @param act is the ModelAction to add.
274 void ModelChecker::add_action_to_lists(ModelAction *act)
276 action_trace->push_back(act);
278 std::vector<action_list_t> *vec = &(*obj_thrd_map)[act->get_location()];
279 if (id_to_int(act->get_tid()) >= (int)vec->size())
280 vec->resize(next_thread_id);
281 (*vec)[id_to_int(act->get_tid())].push_back(act);
283 (*thrd_last_action)[id_to_int(act->get_tid())] = act;
286 ModelAction * ModelChecker::get_last_action(thread_id_t tid)
288 int nthreads = get_num_threads();
289 if ((int)thrd_last_action->size() < nthreads)
290 thrd_last_action->resize(nthreads);
291 return (*thrd_last_action)[id_to_int(tid)];
294 ModelAction * ModelChecker::get_parent_action(thread_id_t tid)
296 ModelAction *parent = get_last_action(tid);
298 parent = get_thread(tid)->get_creation();
302 void ModelChecker::print_summary(void)
305 printf("Number of executions: %d\n", num_executions);
306 printf("Total nodes created: %d\n", node_stack->get_total_nodes());
310 print_list(action_trace);
314 void ModelChecker::print_list(action_list_t *list)
316 action_list_t::iterator it;
318 printf("---------------------------------------------------------------------\n");
321 for (it = list->begin(); it != list->end(); it++) {
324 printf("---------------------------------------------------------------------\n");
327 int ModelChecker::add_thread(Thread *t)
329 (*thread_map)[id_to_int(t->get_id())] = t;
330 scheduler->add_thread(t);
334 void ModelChecker::remove_thread(Thread *t)
336 scheduler->remove_thread(t);
339 int ModelChecker::switch_to_master(ModelAction *act)
344 old = thread_current();
345 set_current_action(act);
346 old->set_state(THREAD_READY);
347 return Thread::swap(old, get_system_context());