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