model: maintain a count of the pending lazy synchronizations
[c11tester.git] / model.cc
1 #include <stdio.h>
2 #include <algorithm>
3
4 #include "model.h"
5 #include "action.h"
6 #include "nodestack.h"
7 #include "schedule.h"
8 #include "snapshot-interface.h"
9 #include "common.h"
10 #include "clockvector.h"
11 #include "cyclegraph.h"
12 #include "promise.h"
13 #include "datarace.h"
14
15 #define INITIAL_THREAD_ID       0
16
17 ModelChecker *model;
18
19 /** @brief Constructor */
20 ModelChecker::ModelChecker(struct model_params params) :
21         /* Initialize default scheduler */
22         scheduler(new Scheduler()),
23         num_executions(0),
24         params(params),
25         diverge(NULL),
26         action_trace(new action_list_t()),
27         thread_map(new HashTable<int, Thread *, int>()),
28         obj_map(new HashTable<const void *, action_list_t, uintptr_t, 4>()),
29         obj_thrd_map(new HashTable<void *, std::vector<action_list_t>, uintptr_t, 4 >()),
30         promises(new std::vector<Promise *>()),
31         lazy_sync_with_release(new HashTable<void *, std::list<ModelAction *>, uintptr_t, 4>()),
32         thrd_last_action(new std::vector<ModelAction *>(1)),
33         node_stack(new NodeStack()),
34         mo_graph(new CycleGraph()),
35         failed_promise(false),
36         asserted(false)
37 {
38         /* Allocate this "size" on the snapshotting heap */
39         priv = (struct model_snapshot_members *)calloc(1, sizeof(*priv));
40         /* First thread created will have id INITIAL_THREAD_ID */
41         priv->next_thread_id = INITIAL_THREAD_ID;
42
43         lazy_sync_size = &priv->lazy_sync_size;
44 }
45
46 /** @brief Destructor */
47 ModelChecker::~ModelChecker()
48 {
49         for (int i = 0; i < get_num_threads(); i++)
50                 delete thread_map->get(i);
51         delete thread_map;
52
53         delete obj_thrd_map;
54         delete obj_map;
55         delete action_trace;
56
57         for (unsigned int i = 0; i < promises->size(); i++)
58                 delete (*promises)[i];
59         delete promises;
60
61         delete lazy_sync_with_release;
62
63         delete thrd_last_action;
64         delete node_stack;
65         delete scheduler;
66         delete mo_graph;
67 }
68
69 /**
70  * Restores user program to initial state and resets all model-checker data
71  * structures.
72  */
73 void ModelChecker::reset_to_initial_state()
74 {
75         DEBUG("+++ Resetting to initial state +++\n");
76         node_stack->reset_execution();
77         failed_promise = false;
78         reset_asserted();
79         snapshotObject->backTrackBeforeStep(0);
80 }
81
82 /** @returns a thread ID for a new Thread */
83 thread_id_t ModelChecker::get_next_id()
84 {
85         return priv->next_thread_id++;
86 }
87
88 /** @returns the number of user threads created during this execution */
89 int ModelChecker::get_num_threads()
90 {
91         return priv->next_thread_id;
92 }
93
94 /** @returns a sequence number for a new ModelAction */
95 modelclock_t ModelChecker::get_next_seq_num()
96 {
97         return ++priv->used_sequence_numbers;
98 }
99
100 /**
101  * Choose the next thread in the replay sequence.
102  *
103  * If the replay sequence has reached the 'diverge' point, returns a thread
104  * from the backtracking set. Otherwise, simply returns the next thread in the
105  * sequence that is being replayed.
106  */
107 Thread * ModelChecker::get_next_replay_thread()
108 {
109         thread_id_t tid;
110
111         /* Have we completed exploring the preselected path? */
112         if (diverge == NULL)
113                 return NULL;
114
115         /* Else, we are trying to replay an execution */
116         ModelAction *next = node_stack->get_next()->get_action();
117
118         if (next == diverge) {
119                 Node *nextnode = next->get_node();
120                 /* Reached divergence point */
121                 if (nextnode->increment_promise()) {
122                         /* The next node will try to satisfy a different set of promises. */
123                         tid = next->get_tid();
124                         node_stack->pop_restofstack(2);
125                 } else if (nextnode->increment_read_from()) {
126                         /* The next node will read from a different value. */
127                         tid = next->get_tid();
128                         node_stack->pop_restofstack(2);
129                 } else if (nextnode->increment_future_value()) {
130                         /* The next node will try to read from a different future value. */
131                         tid = next->get_tid();
132                         node_stack->pop_restofstack(2);
133                 } else {
134                         /* Make a different thread execute for next step */
135                         Node *node = nextnode->get_parent();
136                         tid = node->get_next_backtrack();
137                         node_stack->pop_restofstack(1);
138                 }
139                 DEBUG("*** Divergence point ***\n");
140                 diverge = NULL;
141         } else {
142                 tid = next->get_tid();
143         }
144         DEBUG("*** ModelChecker chose next thread = %d ***\n", tid);
145         ASSERT(tid != THREAD_ID_T_NONE);
146         return thread_map->get(id_to_int(tid));
147 }
148
149 /**
150  * Queries the model-checker for more executions to explore and, if one
151  * exists, resets the model-checker state to execute a new execution.
152  *
153  * @return If there are more executions to explore, return true. Otherwise,
154  * return false.
155  */
156 bool ModelChecker::next_execution()
157 {
158         DBG();
159
160         num_executions++;
161
162         if (isfinalfeasible() || DBG_ENABLED())
163                 print_summary();
164
165         if ((diverge = get_next_backtrack()) == NULL)
166                 return false;
167
168         if (DBG_ENABLED()) {
169                 printf("Next execution will diverge at:\n");
170                 diverge->print();
171         }
172
173         reset_to_initial_state();
174         return true;
175 }
176
177 ModelAction * ModelChecker::get_last_conflict(ModelAction *act)
178 {
179         action_type type = act->get_type();
180
181         switch (type) {
182                 case ATOMIC_READ:
183                 case ATOMIC_WRITE:
184                 case ATOMIC_RMW:
185                         break;
186                 default:
187                         return NULL;
188         }
189         /* linear search: from most recent to oldest */
190         action_list_t *list = obj_map->get_safe_ptr(act->get_location());
191         action_list_t::reverse_iterator rit;
192         for (rit = list->rbegin(); rit != list->rend(); rit++) {
193                 ModelAction *prev = *rit;
194                 if (act->is_synchronizing(prev))
195                         return prev;
196         }
197         return NULL;
198 }
199
200 void ModelChecker::set_backtracking(ModelAction *act)
201 {
202         ModelAction *prev;
203         Node *node;
204         Thread *t = get_thread(act->get_tid());
205
206         prev = get_last_conflict(act);
207         if (prev == NULL)
208                 return;
209
210         node = prev->get_node()->get_parent();
211
212         while (!node->is_enabled(t))
213                 t = t->get_parent();
214
215         /* Check if this has been explored already */
216         if (node->has_been_explored(t->get_id()))
217                 return;
218
219         /* Cache the latest backtracking point */
220         if (!priv->next_backtrack || *prev > *priv->next_backtrack)
221                 priv->next_backtrack = prev;
222
223         /* If this is a new backtracking point, mark the tree */
224         if (!node->set_backtrack(t->get_id()))
225                 return;
226         DEBUG("Setting backtrack: conflict = %d, instead tid = %d\n",
227                         prev->get_tid(), t->get_id());
228         if (DBG_ENABLED()) {
229                 prev->print();
230                 act->print();
231         }
232 }
233
234 /**
235  * Returns last backtracking point. The model checker will explore a different
236  * path for this point in the next execution.
237  * @return The ModelAction at which the next execution should diverge.
238  */
239 ModelAction * ModelChecker::get_next_backtrack()
240 {
241         ModelAction *next = priv->next_backtrack;
242         priv->next_backtrack = NULL;
243         return next;
244 }
245
246 /**
247  * This is the heart of the model checker routine. It performs model-checking
248  * actions corresponding to a given "current action." Among other processes, it
249  * calculates reads-from relationships, updates synchronization clock vectors,
250  * forms a memory_order constraints graph, and handles replay/backtrack
251  * execution when running permutations of previously-observed executions.
252  *
253  * @param curr The current action to process
254  * @return The next Thread that must be executed. May be NULL if ModelChecker
255  * makes no choice (e.g., according to replay execution, combining RMW actions,
256  * etc.)
257  */
258 Thread * ModelChecker::check_current_action(ModelAction *curr)
259 {
260         bool already_added = false;
261
262         ASSERT(curr);
263
264         if (curr->is_rmwc() || curr->is_rmw()) {
265                 ModelAction *tmp = process_rmw(curr);
266                 already_added = true;
267                 delete curr;
268                 curr = tmp;
269         } else {
270                 ModelAction *tmp = node_stack->explore_action(curr);
271                 if (tmp) {
272                         /* Discard duplicate ModelAction; use action from NodeStack */
273                         /* First restore type and order in case of RMW operation */
274                         if (curr->is_rmwr())
275                                 tmp->copy_typeandorder(curr);
276
277                         /* If we have diverged, we need to reset the clock vector. */
278                         if (diverge == NULL)
279                                 tmp->create_cv(get_parent_action(tmp->get_tid()));
280
281                         delete curr;
282                         curr = tmp;
283                 } else {
284                         /*
285                          * Perform one-time actions when pushing new ModelAction onto
286                          * NodeStack
287                          */
288                         curr->create_cv(get_parent_action(curr->get_tid()));
289                         /* Build may_read_from set */
290                         if (curr->is_read())
291                                 build_reads_from_past(curr);
292                         if (curr->is_write())
293                                 compute_promises(curr);
294                 }
295         }
296
297         /* Assign 'creation' parent */
298         if (curr->get_type() == THREAD_CREATE) {
299                 Thread *th = (Thread *)curr->get_location();
300                 th->set_creation(curr);
301         } else if (curr->get_type() == THREAD_JOIN) {
302                 Thread *wait, *join;
303                 wait = get_thread(curr->get_tid());
304                 join = (Thread *)curr->get_location();
305                 if (!join->is_complete())
306                         scheduler->wait(wait, join);
307         } else if (curr->get_type() == THREAD_FINISH) {
308                 Thread *th = get_thread(curr->get_tid());
309                 while (!th->wait_list_empty()) {
310                         Thread *wake = th->pop_wait_list();
311                         scheduler->wake(wake);
312                 }
313                 th->complete();
314         }
315
316         /* Deal with new thread */
317         if (curr->get_type() == THREAD_START)
318                 check_promises(NULL, curr->get_cv());
319
320         /* Assign reads_from values */
321         Thread *th = get_thread(curr->get_tid());
322         uint64_t value = VALUE_NONE;
323         bool updated = false;
324         if (curr->is_read()) {
325                 const ModelAction *reads_from = curr->get_node()->get_read_from();
326                 if (reads_from != NULL) {
327                         value = reads_from->get_value();
328                         /* Assign reads_from, perform release/acquire synchronization */
329                         curr->read_from(reads_from);
330                         if (r_modification_order(curr,reads_from))
331                                 updated = true;
332                 } else {
333                         /* Read from future value */
334                         value = curr->get_node()->get_future_value();
335                         curr->read_from(NULL);
336                         Promise *valuepromise = new Promise(curr, value);
337                         promises->push_back(valuepromise);
338                 }
339         } else if (curr->is_write()) {
340                 if (w_modification_order(curr))
341                         updated = true;
342                 if (resolve_promises(curr))
343                         updated = true;
344         }
345
346         if (updated)
347                 resolve_release_sequences(curr->get_location());
348
349         th->set_return_value(value);
350
351         /* Add action to list.  */
352         if (!already_added)
353                 add_action_to_lists(curr);
354
355         Node *currnode = curr->get_node();
356         Node *parnode = currnode->get_parent();
357
358         if (!parnode->backtrack_empty() || !currnode->read_from_empty() ||
359                   !currnode->future_value_empty() || !currnode->promise_empty())
360                 if (!priv->next_backtrack || *curr > *priv->next_backtrack)
361                         priv->next_backtrack = curr;
362
363         set_backtracking(curr);
364
365         /* Do not split atomic actions. */
366         if (curr->is_rmwr())
367                 return thread_current();
368         /* The THREAD_CREATE action points to the created Thread */
369         else if (curr->get_type() == THREAD_CREATE)
370                 return (Thread *)curr->get_location();
371         else
372                 return get_next_replay_thread();
373 }
374
375 /** @returns whether the current partial trace must be a prefix of a
376  * feasible trace. */
377 bool ModelChecker::isfeasibleprefix() {
378         return promises->size() == 0 && *lazy_sync_size == 0;
379 }
380
381 /** @returns whether the current partial trace is feasible. */
382 bool ModelChecker::isfeasible() {
383         return !mo_graph->checkForCycles() && !failed_promise;
384 }
385
386 /** Returns whether the current completed trace is feasible. */
387 bool ModelChecker::isfinalfeasible() {
388         return isfeasible() && promises->size() == 0;
389 }
390
391 /** Close out a RMWR by converting previous RMWR into a RMW or READ. */
392 ModelAction * ModelChecker::process_rmw(ModelAction *act) {
393         int tid = id_to_int(act->get_tid());
394         ModelAction *lastread = get_last_action(tid);
395         lastread->process_rmw(act);
396         if (act->is_rmw())
397                 mo_graph->addRMWEdge(lastread->get_reads_from(), lastread);
398         return lastread;
399 }
400
401 /**
402  * Updates the mo_graph with the constraints imposed from the current read.
403  * @param curr The current action. Must be a read.
404  * @param rf The action that curr reads from. Must be a write.
405  * @return True if modification order edges were added; false otherwise
406  */
407 bool ModelChecker::r_modification_order(ModelAction *curr, const ModelAction *rf)
408 {
409         std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(curr->get_location());
410         unsigned int i;
411         bool added = false;
412         ASSERT(curr->is_read());
413
414         /* Iterate over all threads */
415         for (i = 0; i < thrd_lists->size(); i++) {
416                 /* Iterate over actions in thread, starting from most recent */
417                 action_list_t *list = &(*thrd_lists)[i];
418                 action_list_t::reverse_iterator rit;
419                 for (rit = list->rbegin(); rit != list->rend(); rit++) {
420                         ModelAction *act = *rit;
421
422                         /* Include at most one act per-thread that "happens before" curr */
423                         if (act->happens_before(curr)) {
424                                 if (act->is_read()) {
425                                         const ModelAction *prevreadfrom = act->get_reads_from();
426                                         if (prevreadfrom != NULL && rf != prevreadfrom) {
427                                                 mo_graph->addEdge(prevreadfrom, rf);
428                                                 added = true;
429                                         }
430                                 } else if (rf != act) {
431                                         mo_graph->addEdge(act, rf);
432                                         added = true;
433                                 }
434                                 break;
435                         }
436                 }
437         }
438
439         return added;
440 }
441
442 /** Updates the mo_graph with the constraints imposed from the current read. */
443 void ModelChecker::post_r_modification_order(ModelAction *curr, const ModelAction *rf)
444 {
445         std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(curr->get_location());
446         unsigned int i;
447         ASSERT(curr->is_read());
448
449         /* Iterate over all threads */
450         for (i = 0; i < thrd_lists->size(); i++) {
451                 /* Iterate over actions in thread, starting from most recent */
452                 action_list_t *list = &(*thrd_lists)[i];
453                 action_list_t::reverse_iterator rit;
454                 ModelAction *lastact = NULL;
455
456                 /* Find last action that happens after curr */
457                 for (rit = list->rbegin(); rit != list->rend(); rit++) {
458                         ModelAction *act = *rit;
459                         if (curr->happens_before(act)) {
460                                 lastact = act;
461                         } else
462                                 break;
463                 }
464
465                         /* Include at most one act per-thread that "happens before" curr */
466                 if (lastact != NULL) {
467                         if (lastact->is_read()) {
468                                 const ModelAction *postreadfrom = lastact->get_reads_from();
469                                 if (postreadfrom != NULL&&rf != postreadfrom)
470                                         mo_graph->addEdge(rf, postreadfrom);
471                         } else if (rf != lastact) {
472                                 mo_graph->addEdge(rf, lastact);
473                         }
474                         break;
475                 }
476         }
477 }
478
479 /**
480  * Updates the mo_graph with the constraints imposed from the current write.
481  * @param curr The current action. Must be a write.
482  * @return True if modification order edges were added; false otherwise
483  */
484 bool ModelChecker::w_modification_order(ModelAction *curr)
485 {
486         std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(curr->get_location());
487         unsigned int i;
488         bool added = false;
489         ASSERT(curr->is_write());
490
491         if (curr->is_seqcst()) {
492                 /* We have to at least see the last sequentially consistent write,
493                          so we are initialized. */
494                 ModelAction *last_seq_cst = get_last_seq_cst(curr->get_location());
495                 if (last_seq_cst != NULL) {
496                         mo_graph->addEdge(last_seq_cst, curr);
497                         added = true;
498                 }
499         }
500
501         /* Iterate over all threads */
502         for (i = 0; i < thrd_lists->size(); i++) {
503                 /* Iterate over actions in thread, starting from most recent */
504                 action_list_t *list = &(*thrd_lists)[i];
505                 action_list_t::reverse_iterator rit;
506                 for (rit = list->rbegin(); rit != list->rend(); rit++) {
507                         ModelAction *act = *rit;
508
509                         /* Include at most one act per-thread that "happens before" curr */
510                         if (act->happens_before(curr)) {
511                                 if (act->is_read())
512                                         mo_graph->addEdge(act->get_reads_from(), curr);
513                                 else
514                                         mo_graph->addEdge(act, curr);
515                                 added = true;
516                                 break;
517                         } else if (act->is_read() && !act->is_synchronizing(curr) &&
518                                                      !act->same_thread(curr)) {
519                                 /* We have an action that:
520                                    (1) did not happen before us
521                                    (2) is a read and we are a write
522                                    (3) cannot synchronize with us
523                                    (4) is in a different thread
524                                    =>
525                                    that read could potentially read from our write.
526                                  */
527                                 if (act->get_node()->add_future_value(curr->get_value()) &&
528                                                 (!priv->next_backtrack || *act > *priv->next_backtrack))
529                                         priv->next_backtrack = act;
530                         }
531                 }
532         }
533
534         return added;
535 }
536
537 /**
538  * Finds the head(s) of the release sequence(s) containing a given ModelAction.
539  * The ModelAction under consideration is expected to be taking part in
540  * release/acquire synchronization as an object of the "reads from" relation.
541  * Note that this can only provide release sequence support for RMW chains
542  * which do not read from the future, as those actions cannot be traced until
543  * their "promise" is fulfilled. Similarly, we may not even establish the
544  * presence of a release sequence with certainty, as some modification order
545  * constraints may be decided further in the future. Thus, this function
546  * "returns" two pieces of data: a pass-by-reference vector of @a release_heads
547  * and a boolean representing certainty.
548  *
549  * @todo Finish lazy updating, when promises are fulfilled in the future
550  * @param rf The action that might be part of a release sequence. Must be a
551  * write.
552  * @param release_heads A pass-by-reference style return parameter.  After
553  * execution of this function, release_heads will contain the heads of all the
554  * relevant release sequences, if any exists
555  * @return true, if the ModelChecker is certain that release_heads is complete;
556  * false otherwise
557  */
558 bool ModelChecker::release_seq_head(const ModelAction *rf,
559                 std::vector<const ModelAction *> *release_heads) const
560 {
561         ASSERT(rf->is_write());
562         if (!rf) {
563                 /* read from future: need to settle this later */
564                 return false; /* incomplete */
565         }
566         if (rf->is_release())
567                 release_heads->push_back(rf);
568         if (rf->is_rmw()) {
569                 if (rf->is_acquire())
570                         return true; /* complete */
571                 return release_seq_head(rf->get_reads_from(), release_heads);
572         }
573         if (rf->is_release())
574                 return true; /* complete */
575
576         /* else relaxed write; check modification order for contiguous subsequence
577          * -> rf must be same thread as release */
578         int tid = id_to_int(rf->get_tid());
579         std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(rf->get_location());
580         action_list_t *list = &(*thrd_lists)[tid];
581         action_list_t::const_reverse_iterator rit;
582
583         /* Find rf in the thread list */
584         rit = std::find(list->rbegin(), list->rend(), rf);
585         ASSERT(rit != list->rend());
586
587         /* Find the last write/release */
588         for (; rit != list->rend(); rit++)
589                 if ((*rit)->is_release())
590                         break;
591         if (rit == list->rend()) {
592                 /* No write-release in this thread */
593                 return true; /* complete */
594         }
595         ModelAction *release = *rit;
596
597         ASSERT(rf->same_thread(release));
598
599         bool certain = true;
600         for (unsigned int i = 0; i < thrd_lists->size(); i++) {
601                 if (id_to_int(rf->get_tid()) == (int)i)
602                         continue;
603                 list = &(*thrd_lists)[i];
604
605                 /* Can we ensure no future writes from this thread may break
606                  * the release seq? */
607                 bool future_ordered = false;
608
609                 for (rit = list->rbegin(); rit != list->rend(); rit++) {
610                         const ModelAction *act = *rit;
611                         if (!act->is_write())
612                                 continue;
613                         /* Reach synchronization -> this thread is complete */
614                         if (act->happens_before(release))
615                                 break;
616                         if (rf->happens_before(act)) {
617                                 future_ordered = true;
618                                 continue;
619                         }
620
621                         /* Check modification order */
622                         if (mo_graph->checkReachable(rf, act)) {
623                                 /* rf --mo--> act */
624                                 future_ordered = true;
625                                 continue;
626                         }
627                         if (mo_graph->checkReachable(act, release))
628                                 /* act --mo--> release */
629                                 break;
630                         if (mo_graph->checkReachable(release, act) &&
631                                       mo_graph->checkReachable(act, rf)) {
632                                 /* release --mo-> act --mo--> rf */
633                                 return true; /* complete */
634                         }
635                         certain = false;
636                 }
637                 if (!future_ordered)
638                         return false; /* This thread is uncertain */
639         }
640
641         if (certain)
642                 release_heads->push_back(release);
643         return certain;
644 }
645
646 /**
647  * A public interface for getting the release sequence head(s) with which a
648  * given ModelAction must synchronize. This function only returns a non-empty
649  * result when it can locate a release sequence head with certainty. Otherwise,
650  * it may mark the internal state of the ModelChecker so that it will handle
651  * the release sequence at a later time, causing @a act to update its
652  * synchronization at some later point in execution.
653  * @param act The 'acquire' action that may read from a release sequence
654  * @param release_heads A pass-by-reference return parameter. Will be filled
655  * with the head(s) of the release sequence(s), if they exists with certainty.
656  * @see ModelChecker::release_seq_head
657  */
658 void ModelChecker::get_release_seq_heads(ModelAction *act,
659                 std::vector<const ModelAction *> *release_heads)
660 {
661         const ModelAction *rf = act->get_reads_from();
662         bool complete;
663         complete = release_seq_head(rf, release_heads);
664         if (!complete) {
665                 /* add act to 'lazy checking' list */
666                 std::list<ModelAction *> *list;
667                 list = lazy_sync_with_release->get_safe_ptr(act->get_location());
668                 list->push_back(act);
669                 (*lazy_sync_size)++;
670         }
671 }
672
673 /**
674  * Attempt to resolve all stashed operations that might synchronize with a
675  * release sequence for a given location. This implements the "lazy" portion of
676  * determining whether or not a release sequence was contiguous, since not all
677  * modification order information is present at the time an action occurs.
678  *
679  * @param location The location/object that should be checked for release
680  * sequence resolutions
681  * @return True if any updates occurred (new synchronization, new mo_graph edges)
682  */
683 bool ModelChecker::resolve_release_sequences(void *location)
684 {
685         std::list<ModelAction *> *list;
686         list = lazy_sync_with_release->getptr(location);
687         if (!list)
688                 return false;
689
690         bool updated = false;
691         std::list<ModelAction *>::iterator it = list->begin();
692         while (it != list->end()) {
693                 ModelAction *act = *it;
694                 const ModelAction *rf = act->get_reads_from();
695                 std::vector<const ModelAction *> release_heads;
696                 bool complete;
697                 complete = release_seq_head(rf, &release_heads);
698                 for (unsigned int i = 0; i < release_heads.size(); i++) {
699                         if (!act->has_synchronized_with(release_heads[i])) {
700                                 updated = true;
701                                 act->synchronize_with(release_heads[i]);
702                         }
703                 }
704
705                 if (updated) {
706                         /* propagate synchronization to later actions */
707                         action_list_t::reverse_iterator it = action_trace->rbegin();
708                         while ((*it) != act) {
709                                 ModelAction *propagate = *it;
710                                 if (act->happens_before(propagate))
711                                         /** @todo new mo_graph edges along with
712                                          * this synchronization? */
713                                         propagate->synchronize_with(act);
714                         }
715                 }
716                 if (complete) {
717                         it = list->erase(it);
718                         (*lazy_sync_size)--;
719                 } else
720                         it++;
721         }
722
723         // If we resolved promises or data races, see if we have realized a data race.
724         if (checkDataRaces()) {
725                 set_assert();
726         }
727
728         return updated;
729 }
730
731 /**
732  * Performs various bookkeeping operations for the current ModelAction. For
733  * instance, adds action to the per-object, per-thread action vector and to the
734  * action trace list of all thread actions.
735  *
736  * @param act is the ModelAction to add.
737  */
738 void ModelChecker::add_action_to_lists(ModelAction *act)
739 {
740         int tid = id_to_int(act->get_tid());
741         action_trace->push_back(act);
742
743         obj_map->get_safe_ptr(act->get_location())->push_back(act);
744
745         std::vector<action_list_t> *vec = obj_thrd_map->get_safe_ptr(act->get_location());
746         if (tid >= (int)vec->size())
747                 vec->resize(priv->next_thread_id);
748         (*vec)[tid].push_back(act);
749
750         if ((int)thrd_last_action->size() <= tid)
751                 thrd_last_action->resize(get_num_threads());
752         (*thrd_last_action)[tid] = act;
753 }
754
755 ModelAction * ModelChecker::get_last_action(thread_id_t tid)
756 {
757         int nthreads = get_num_threads();
758         if ((int)thrd_last_action->size() < nthreads)
759                 thrd_last_action->resize(nthreads);
760         return (*thrd_last_action)[id_to_int(tid)];
761 }
762
763 /**
764  * Gets the last memory_order_seq_cst action (in the total global sequence)
765  * performed on a particular object (i.e., memory location).
766  * @param location The object location to check
767  * @return The last seq_cst action performed
768  */
769 ModelAction * ModelChecker::get_last_seq_cst(const void *location)
770 {
771         action_list_t *list = obj_map->get_safe_ptr(location);
772         /* Find: max({i in dom(S) | seq_cst(t_i) && isWrite(t_i) && samevar(t_i, t)}) */
773         action_list_t::reverse_iterator rit;
774         for (rit = list->rbegin(); rit != list->rend(); rit++)
775                 if ((*rit)->is_write() && (*rit)->is_seqcst())
776                         return *rit;
777         return NULL;
778 }
779
780 ModelAction * ModelChecker::get_parent_action(thread_id_t tid)
781 {
782         ModelAction *parent = get_last_action(tid);
783         if (!parent)
784                 parent = get_thread(tid)->get_creation();
785         return parent;
786 }
787
788 /**
789  * Returns the clock vector for a given thread.
790  * @param tid The thread whose clock vector we want
791  * @return Desired clock vector
792  */
793 ClockVector * ModelChecker::get_cv(thread_id_t tid)
794 {
795         return get_parent_action(tid)->get_cv();
796 }
797
798 /**
799  * Resolve a set of Promises with a current write. The set is provided in the
800  * Node corresponding to @a write.
801  * @param write The ModelAction that is fulfilling Promises
802  * @return True if promises were resolved; false otherwise
803  */
804 bool ModelChecker::resolve_promises(ModelAction *write)
805 {
806         bool resolved = false;
807         for (unsigned int i = 0, promise_index = 0; promise_index < promises->size(); i++) {
808                 Promise *promise = (*promises)[promise_index];
809                 if (write->get_node()->get_promise(i)) {
810                         ModelAction *read = promise->get_action();
811                         read->read_from(write);
812                         r_modification_order(read, write);
813                         post_r_modification_order(read, write);
814                         promises->erase(promises->begin() + promise_index);
815                         resolved = true;
816                 } else
817                         promise_index++;
818         }
819
820         return resolved;
821 }
822
823 /**
824  * Compute the set of promises that could potentially be satisfied by this
825  * action. Note that the set computation actually appears in the Node, not in
826  * ModelChecker.
827  * @param curr The ModelAction that may satisfy promises
828  */
829 void ModelChecker::compute_promises(ModelAction *curr)
830 {
831         for (unsigned int i = 0; i < promises->size(); i++) {
832                 Promise *promise = (*promises)[i];
833                 const ModelAction *act = promise->get_action();
834                 if (!act->happens_before(curr) &&
835                                 act->is_read() &&
836                                 !act->is_synchronizing(curr) &&
837                                 !act->same_thread(curr) &&
838                                 promise->get_value() == curr->get_value()) {
839                         curr->get_node()->set_promise(i);
840                 }
841         }
842 }
843
844 /** Checks promises in response to change in ClockVector Threads. */
845 void ModelChecker::check_promises(ClockVector *old_cv, ClockVector *merge_cv)
846 {
847         for (unsigned int i = 0; i < promises->size(); i++) {
848                 Promise *promise = (*promises)[i];
849                 const ModelAction *act = promise->get_action();
850                 if ((old_cv == NULL || !old_cv->synchronized_since(act)) &&
851                                 merge_cv->synchronized_since(act)) {
852                         //This thread is no longer able to send values back to satisfy the promise
853                         int num_synchronized_threads = promise->increment_threads();
854                         if (num_synchronized_threads == get_num_threads()) {
855                                 //Promise has failed
856                                 failed_promise = true;
857                                 return;
858                         }
859                 }
860         }
861 }
862
863 /**
864  * Build up an initial set of all past writes that this 'read' action may read
865  * from. This set is determined by the clock vector's "happens before"
866  * relationship.
867  * @param curr is the current ModelAction that we are exploring; it must be a
868  * 'read' operation.
869  */
870 void ModelChecker::build_reads_from_past(ModelAction *curr)
871 {
872         std::vector<action_list_t> *thrd_lists = obj_thrd_map->get_safe_ptr(curr->get_location());
873         unsigned int i;
874         ASSERT(curr->is_read());
875
876         ModelAction *last_seq_cst = NULL;
877
878         /* Track whether this object has been initialized */
879         bool initialized = false;
880
881         if (curr->is_seqcst()) {
882                 last_seq_cst = get_last_seq_cst(curr->get_location());
883                 /* We have to at least see the last sequentially consistent write,
884                          so we are initialized. */
885                 if (last_seq_cst != NULL)
886                         initialized = true;
887         }
888
889         /* Iterate over all threads */
890         for (i = 0; i < thrd_lists->size(); i++) {
891                 /* Iterate over actions in thread, starting from most recent */
892                 action_list_t *list = &(*thrd_lists)[i];
893                 action_list_t::reverse_iterator rit;
894                 for (rit = list->rbegin(); rit != list->rend(); rit++) {
895                         ModelAction *act = *rit;
896
897                         /* Only consider 'write' actions */
898                         if (!act->is_write())
899                                 continue;
900
901                         /* Don't consider more than one seq_cst write if we are a seq_cst read. */
902                         if (!act->is_seqcst() || !curr->is_seqcst() || act == last_seq_cst) {
903                                 DEBUG("Adding action to may_read_from:\n");
904                                 if (DBG_ENABLED()) {
905                                         act->print();
906                                         curr->print();
907                                 }
908                                 curr->get_node()->add_read_from(act);
909                         }
910
911                         /* Include at most one act per-thread that "happens before" curr */
912                         if (act->happens_before(curr)) {
913                                 initialized = true;
914                                 break;
915                         }
916                 }
917         }
918
919         if (!initialized) {
920                 /** @todo Need a more informative way of reporting errors. */
921                 printf("ERROR: may read from uninitialized atomic\n");
922         }
923
924         if (DBG_ENABLED() || !initialized) {
925                 printf("Reached read action:\n");
926                 curr->print();
927                 printf("Printing may_read_from\n");
928                 curr->get_node()->print_may_read_from();
929                 printf("End printing may_read_from\n");
930         }
931
932         ASSERT(initialized);
933 }
934
935 static void print_list(action_list_t *list)
936 {
937         action_list_t::iterator it;
938
939         printf("---------------------------------------------------------------------\n");
940         printf("Trace:\n");
941
942         for (it = list->begin(); it != list->end(); it++) {
943                 (*it)->print();
944         }
945         printf("---------------------------------------------------------------------\n");
946 }
947
948 void ModelChecker::print_summary()
949 {
950         printf("\n");
951         printf("Number of executions: %d\n", num_executions);
952         printf("Total nodes created: %d\n", node_stack->get_total_nodes());
953
954         scheduler->print();
955
956         if (!isfinalfeasible())
957                 printf("INFEASIBLE EXECUTION!\n");
958         print_list(action_trace);
959         printf("\n");
960 }
961
962 /**
963  * Add a Thread to the system for the first time. Should only be called once
964  * per thread.
965  * @param t The Thread to add
966  */
967 void ModelChecker::add_thread(Thread *t)
968 {
969         thread_map->put(id_to_int(t->get_id()), t);
970         scheduler->add_thread(t);
971 }
972
973 void ModelChecker::remove_thread(Thread *t)
974 {
975         scheduler->remove_thread(t);
976 }
977
978 /**
979  * Switch from a user-context to the "master thread" context (a.k.a. system
980  * context). This switch is made with the intention of exploring a particular
981  * model-checking action (described by a ModelAction object). Must be called
982  * from a user-thread context.
983  * @param act The current action that will be explored. Must not be NULL.
984  * @return Return status from the 'swap' call (i.e., success/fail, 0/-1)
985  */
986 int ModelChecker::switch_to_master(ModelAction *act)
987 {
988         DBG();
989         Thread *old = thread_current();
990         set_current_action(act);
991         old->set_state(THREAD_READY);
992         return Thread::swap(old, &system_context);
993 }
994
995 /**
996  * Takes the next step in the execution, if possible.
997  * @return Returns true (success) if a step was taken and false otherwise.
998  */
999 bool ModelChecker::take_step() {
1000         Thread *curr, *next;
1001
1002         if (has_asserted())
1003                 return false;
1004
1005         curr = thread_current();
1006         if (curr) {
1007                 if (curr->get_state() == THREAD_READY) {
1008                         ASSERT(priv->current_action);
1009                         priv->nextThread = check_current_action(priv->current_action);
1010                         priv->current_action = NULL;
1011                         if (!curr->is_blocked() && !curr->is_complete())
1012                                 scheduler->add_thread(curr);
1013                 } else {
1014                         ASSERT(false);
1015                 }
1016         }
1017         next = scheduler->next_thread(priv->nextThread);
1018
1019         /* Infeasible -> don't take any more steps */
1020         if (!isfeasible())
1021                 return false;
1022
1023         if (next)
1024                 next->set_state(THREAD_RUNNING);
1025         DEBUG("(%d, %d)\n", curr ? curr->get_id() : -1, next ? next->get_id() : -1);
1026
1027         /* next == NULL -> don't take any more steps */
1028         if (!next)
1029                 return false;
1030         /* Return false only if swap fails with an error */
1031         return (Thread::swap(&system_context, next) == 0);
1032 }
1033
1034 /** Runs the current execution until threre are no more steps to take. */
1035 void ModelChecker::finish_execution() {
1036         DBG();
1037
1038         while (take_step());
1039 }