nodestack: rename 'iter' to 'head_idx'
[model-checker.git] / model.cc
index dbca58e7394f5e3eb9a4f7b68a54c67aff4a5346..90b2c2fcd55d47a779c9dc23d133e663b394071f 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -1,6 +1,7 @@
 #include <stdio.h>
 #include <algorithm>
 #include <mutex>
+#include <new>
 
 #include "model.h"
 #include "action.h"
@@ -128,19 +129,21 @@ ModelChecker::~ModelChecker()
        delete priv;
 }
 
-static action_list_t * get_safe_ptr_action(HashTable<const void *, action_list_t *, uintptr_t, 4> * hash, void * ptr) {
-       action_list_t * tmp=hash->get(ptr);
-       if (tmp==NULL) {
-               tmp=new action_list_t();
+static action_list_t * get_safe_ptr_action(HashTable<const void *, action_list_t *, uintptr_t, 4> * hash, void * ptr)
+{
+       action_list_t *tmp = hash->get(ptr);
+       if (tmp == NULL) {
+               tmp = new action_list_t();
                hash->put(ptr, tmp);
        }
        return tmp;
 }
 
-static std::vector<action_list_t> * get_safe_ptr_vect_action(HashTable<void *, std::vector<action_list_t> *, uintptr_t, 4> * hash, void * ptr) {
-       std::vector<action_list_t> * tmp=hash->get(ptr);
-       if (tmp==NULL) {
-               tmp=new std::vector<action_list_t>();
+static std::vector<action_list_t> * get_safe_ptr_vect_action(HashTable<void *, std::vector<action_list_t> *, uintptr_t, 4> * hash, void * ptr)
+{
+       std::vector<action_list_t> *tmp = hash->get(ptr);
+       if (tmp == NULL) {
+               tmp = new std::vector<action_list_t>();
                hash->put(ptr, tmp);
        }
        return tmp;
@@ -207,7 +210,7 @@ Thread * ModelChecker::get_next_thread(ModelAction *curr)
 {
        thread_id_t tid;
 
-       if (curr!=NULL) {
+       if (curr != NULL) {
                /* Do not split atomic actions. */
                if (curr->is_rmwr())
                        return thread_current();
@@ -225,7 +228,7 @@ Thread * ModelChecker::get_next_thread(ModelAction *curr)
 
        if (next == diverge) {
                if (earliest_diverge == NULL || *diverge < *earliest_diverge)
-                       earliest_diverge=diverge;
+                       earliest_diverge = diverge;
 
                Node *nextnode = next->get_node();
                Node *prevnode = nextnode->get_parent();
@@ -258,8 +261,8 @@ Thread * ModelChecker::get_next_thread(ModelAction *curr)
                        tid = prevnode->get_next_backtrack();
                        /* Make sure the backtracked thread isn't sleeping. */
                        node_stack->pop_restofstack(1);
-                       if (diverge==earliest_diverge) {
-                               earliest_diverge=prevnode->get_action();
+                       if (diverge == earliest_diverge) {
+                               earliest_diverge = prevnode->get_action();
                        }
                }
                /* The correct sleep set is in the parent node. */
@@ -282,12 +285,12 @@ Thread * ModelChecker::get_next_thread(ModelAction *curr)
  * the corresponding thread object's pending action.
  */
 
-void ModelChecker::execute_sleep_set() {
-       for(unsigned int i=0;i<get_num_threads();i++) {
-               thread_id_t tid=int_to_id(i);
-               Thread *thr=get_thread(tid);
-               if ( scheduler->get_enabled(thr) == THREAD_SLEEP_SET &&
-                                thr->get_pending() == NULL ) {
+void ModelChecker::execute_sleep_set()
+{
+       for (unsigned int i = 0; i < get_num_threads(); i++) {
+               thread_id_t tid = int_to_id(i);
+               Thread *thr = get_thread(tid);
+               if (scheduler->is_sleep_set(thr) && thr->get_pending() == NULL) {
                        thr->set_state(THREAD_RUNNING);
                        scheduler->next_thread(thr);
                        Thread::swap(&system_context, thr);
@@ -298,16 +301,15 @@ void ModelChecker::execute_sleep_set() {
        priv->current_action = NULL;
 }
 
-void ModelChecker::wake_up_sleeping_actions(ModelAction * curr) {
-       for(unsigned int i=0;i<get_num_threads();i++) {
-               thread_id_t tid=int_to_id(i);
-               Thread *thr=get_thread(tid);
-               if ( scheduler->get_enabled(thr) == THREAD_SLEEP_SET ) {
-                       ModelAction *pending_act=thr->get_pending();
-                       if ((!curr->is_rmwr())&&pending_act->could_synchronize_with(curr)) {
+void ModelChecker::wake_up_sleeping_actions(ModelAction *curr)
+{
+       for (unsigned int i = 0; i < get_num_threads(); i++) {
+               Thread *thr = get_thread(int_to_id(i));
+               if (scheduler->is_sleep_set(thr)) {
+                       ModelAction *pending_act = thr->get_pending();
+                       if ((!curr->is_rmwr()) && pending_act->could_synchronize_with(curr))
                                //Remove this thread from sleep set
                                scheduler->remove_sleep(thr);
-                       }
                }
        }
 }
@@ -603,16 +605,16 @@ ModelAction * ModelChecker::get_last_conflict(ModelAction *act)
 void ModelChecker::set_backtracking(ModelAction *act)
 {
        Thread *t = get_thread(act);
-       ModelAction * prev = get_last_conflict(act);
+       ModelAction *prev = get_last_conflict(act);
        if (prev == NULL)
                return;
 
-       Node * node = prev->get_node()->get_parent();
+       Node *node = prev->get_node()->get_parent();
 
        int low_tid, high_tid;
        if (node->is_enabled(t)) {
                low_tid = id_to_int(act->get_tid());
-               high_tid = low_tid+1;
+               high_tid = low_tid + 1;
        } else {
                low_tid = 0;
                high_tid = get_num_threads();
@@ -626,7 +628,7 @@ void ModelChecker::set_backtracking(ModelAction *act)
                        break;
 
                /* Don't backtrack into a point where the thread is disabled or sleeping. */
-               if (node->enabled_status(tid)!=THREAD_ENABLED)
+               if (node->enabled_status(tid) != THREAD_ENABLED)
                        continue;
 
                /* Check if this has been explored already */
@@ -635,11 +637,11 @@ void ModelChecker::set_backtracking(ModelAction *act)
 
                /* See if fairness allows */
                if (model->params.fairwindow != 0 && !node->has_priority(tid)) {
-                       bool unfair=false;
-                       for(int t=0;t<node->get_num_threads();t++) {
-                               thread_id_t tother=int_to_id(t);
+                       bool unfair = false;
+                       for (int t = 0; t < node->get_num_threads(); t++) {
+                               thread_id_t tother = int_to_id(t);
                                if (node->is_enabled(tother) && node->has_priority(tother)) {
-                                       unfair=true;
+                                       unfair = true;
                                        break;
                                }
                        }
@@ -714,7 +716,7 @@ bool ModelChecker::process_read(ModelAction *curr, bool second_part_of_rmw)
                        /* Read from future value */
                        value = curr->get_node()->get_future_value();
                        modelclock_t expiration = curr->get_node()->get_future_value_expiration();
-                       read_from(curr, NULL);
+                       curr->set_read_from(NULL);
                        Promise *valuepromise = new Promise(curr, value, expiration);
                        promises->push_back(valuepromise);
                }
@@ -739,9 +741,10 @@ bool ModelChecker::process_read(ModelAction *curr, bool second_part_of_rmw)
  *
  * @return True if synchronization was updated; false otherwise
  */
-bool ModelChecker::process_mutex(ModelAction *curr) {
-       std::mutex *mutex=NULL;
-       struct std::mutex_state *state=NULL;
+bool ModelChecker::process_mutex(ModelAction *curr)
+{
+       std::mutex *mutex = NULL;
+       struct std::mutex_state *state = NULL;
 
        if (curr->is_trylock() || curr->is_lock() || curr->is_unlock()) {
                mutex = (std::mutex *)curr->get_location();
@@ -797,7 +800,7 @@ bool ModelChecker::process_mutex(ModelAction *curr) {
                }
                waiters->clear();
                //check whether we should go to sleep or not...simulate spurious failures
-               if (curr->get_node()->get_misc()==0) {
+               if (curr->get_node()->get_misc() == 0) {
                        get_safe_ptr_action(condvar_waiters_map, curr->get_location())->push_back(curr);
                        //disable us
                        scheduler->sleep(get_current_thread());
@@ -815,7 +818,7 @@ bool ModelChecker::process_mutex(ModelAction *curr) {
        }
        case ATOMIC_NOTIFY_ONE: {
                action_list_t *waiters = get_safe_ptr_action(condvar_waiters_map, curr->get_location());
-               int wakeupthread=curr->get_node()->get_misc();
+               int wakeupthread = curr->get_node()->get_misc();
                action_list_t::iterator it = waiters->begin();
                advance(it, wakeupthread);
                scheduler->wake(get_thread(*it));
@@ -858,6 +861,56 @@ bool ModelChecker::process_write(ModelAction *curr)
        return updated_mod_order || updated_promises;
 }
 
+/**
+ * Process a fence ModelAction
+ * @param curr The ModelAction to process
+ * @return True if synchronization was updated
+ */
+bool ModelChecker::process_fence(ModelAction *curr)
+{
+       /*
+        * fence-relaxed: no-op
+        * fence-release: only log the occurence (not in this function), for
+        *   use in later synchronization
+        * fence-acquire (this function): search for hypothetical release
+        *   sequences
+        */
+       bool updated = false;
+       if (curr->is_acquire()) {
+               action_list_t *list = action_trace;
+               action_list_t::reverse_iterator rit;
+               /* Find X : is_read(X) && X --sb-> curr */
+               for (rit = list->rbegin(); rit != list->rend(); rit++) {
+                       ModelAction *act = *rit;
+                       if (act == curr)
+                               continue;
+                       if (act->get_tid() != curr->get_tid())
+                               continue;
+                       /* Stop at the beginning of the thread */
+                       if (act->is_thread_start())
+                               break;
+                       /* Stop once we reach a prior fence-acquire */
+                       if (act->is_fence() && act->is_acquire())
+                               break;
+                       if (!act->is_read())
+                               continue;
+                       /* read-acquire will find its own release sequences */
+                       if (act->is_acquire())
+                               continue;
+
+                       /* Establish hypothetical release sequences */
+                       rel_heads_list_t release_heads;
+                       get_release_seq_heads(curr, act, &release_heads);
+                       for (unsigned int i = 0; i < release_heads.size(); i++)
+                               if (!curr->synchronize_with(release_heads[i]))
+                                       set_bad_synchronization();
+                       if (release_heads.size() != 0)
+                               updated = true;
+               }
+       }
+       return updated;
+}
+
 /**
  * @brief Process the current action for thread-related activity
  *
@@ -1087,8 +1140,8 @@ bool ModelChecker::read_from(ModelAction *act, const ModelAction *rf)
  */
 bool ModelChecker::check_action_enabled(ModelAction *curr) {
        if (curr->is_lock()) {
-               std::mutex * lock = (std::mutex *)curr->get_location();
-               struct std::mutex_state * state = lock->get_state();
+               std::mutex *lock = (std::mutex *)curr->get_location();
+               struct std::mutex_state *state = lock->get_state();
                if (state->islocked) {
                        //Stick the action in the appropriate waiting queue
                        get_safe_ptr_action(lock_waiters_map, curr->get_location())->push_back(curr);
@@ -1173,6 +1226,9 @@ Thread * ModelChecker::check_current_action(ModelAction *curr)
                        if (act->is_write() && process_write(act))
                                update = true;
 
+                       if (act->is_fence() && process_fence(act))
+                               update_all = true;
+
                        if (act->is_mutex_op() && process_mutex(act))
                                update_all = true;
 
@@ -1219,7 +1275,8 @@ Thread * ModelChecker::check_current_action(ModelAction *curr)
        return get_next_thread(curr);
 }
 
-void ModelChecker::check_curr_backtracking(ModelAction * curr) {
+void ModelChecker::check_curr_backtracking(ModelAction *curr)
+{
        Node *currnode = curr->get_node();
        Node *parnode = currnode->get_parent();
 
@@ -1237,11 +1294,10 @@ void ModelChecker::check_curr_backtracking(ModelAction * curr) {
 
 bool ModelChecker::promises_expired() const
 {
-       for (unsigned int promise_index = 0; promise_index < promises->size(); promise_index++) {
-               Promise *promise = (*promises)[promise_index];
-               if (promise->get_expiration()<priv->used_sequence_numbers) {
+       for (unsigned int i = 0; i < promises->size(); i++) {
+               Promise *promise = (*promises)[i];
+               if (promise->get_expiration() < priv->used_sequence_numbers)
                        return true;
-               }
        }
        return false;
 }
@@ -1313,7 +1369,7 @@ bool ModelChecker::is_infeasible_ignoreRMW() const
 ModelAction * ModelChecker::process_rmw(ModelAction *act) {
        ModelAction *lastread = get_last_action(act->get_tid());
        lastread->process_rmw(act);
-       if (act->is_rmw() && lastread->get_reads_from()!=NULL) {
+       if (act->is_rmw() && lastread->get_reads_from() != NULL) {
                mo_graph->addRMWEdge(lastread->get_reads_from(), lastread);
                mo_graph->commitChanges();
        }
@@ -1331,9 +1387,9 @@ ModelAction * ModelChecker::process_rmw(ModelAction *act) {
  *
  * If so, we decide that the execution is no longer feasible.
  */
-void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf) {
+void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf)
+{
        if (params.maxreads != 0) {
-
                if (curr->get_node()->get_read_from_size() <= 1)
                        return;
                //Must make sure that execution is currently feasible...  We could
@@ -1359,7 +1415,7 @@ void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf) {
                //See if we have enough reads from the same value
                int count = 0;
                for (; count < params.maxreads; rit++,count++) {
-                       if (rit==list->rend())
+                       if (rit == list->rend())
                                return;
                        ModelAction *act = *rit;
                        if (!act->is_read())
@@ -1370,12 +1426,12 @@ void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf) {
                        if (act->get_node()->get_read_from_size() <= 1)
                                return;
                }
-               for (int i = 0; i<curr->get_node()->get_read_from_size(); i++) {
-                       //Get write
-                       const ModelAction * write = curr->get_node()->get_read_from_at(i);
+               for (int i = 0; i < curr->get_node()->get_read_from_size(); i++) {
+                       /* Get write */
+                       const ModelAction *write = curr->get_node()->get_read_from_at(i);
 
-                       //Need a different write
-                       if (write==rf)
+                       /* Need a different write */
+                       if (write == rf)
                                continue;
 
                        /* Test to see whether this is a feasible write to read from*/
@@ -1392,10 +1448,10 @@ void ModelChecker::check_recency(ModelAction *curr, const ModelAction *rf) {
                        //new we need to see if this write works for everyone
 
                        for (int loop = count; loop>0; loop--,rit++) {
-                               ModelAction *act=*rit;
+                               ModelAction *act = *rit;
                                bool foundvalue = false;
                                for (int j = 0; j<act->get_node()->get_read_from_size(); j++) {
-                                       if (act->get_node()->get_read_from_at(j)==write) {
+                                       if (act->get_node()->get_read_from_at(j) == write) {
                                                foundvalue = true;
                                                break;
                                        }
@@ -1464,18 +1520,21 @@ bool ModelChecker::r_modification_order(ModelAction *curr, const ModelAction *rf
                                                *act < *last_sc_fence_thread_local) {
                                        mo_graph->addEdge(act, rf);
                                        added = true;
+                                       break;
                                }
                                /* C++, Section 29.3 statement 4 */
                                else if (act->is_seqcst() && last_sc_fence_local &&
                                                *act < *last_sc_fence_local) {
                                        mo_graph->addEdge(act, rf);
                                        added = true;
+                                       break;
                                }
                                /* C++, Section 29.3 statement 6 */
                                else if (last_sc_fence_thread_before &&
                                                *act < *last_sc_fence_thread_before) {
                                        mo_graph->addEdge(act, rf);
                                        added = true;
+                                       break;
                                }
                        }
 
@@ -1547,7 +1606,7 @@ void ModelChecker::post_r_modification_order(ModelAction *curr, const ModelActio
 
                        /* Include at most one act per-thread that "happens before" curr */
                if (lastact != NULL) {
-                       if (lastact==curr) {
+                       if (lastact== curr) {
                                //Case 1: The resolved read is a RMW, and we need to make sure
                                //that the write portion of the RMW mod order after rf
 
@@ -1558,13 +1617,13 @@ void ModelChecker::post_r_modification_order(ModelAction *curr, const ModelActio
                                //is mod ordered after rf
 
                                const ModelAction *postreadfrom = lastact->get_reads_from();
-                               if (postreadfrom != NULL&&rf != postreadfrom)
+                               if (postreadfrom != NULL && rf != postreadfrom)
                                        mo_graph->addEdge(rf, postreadfrom);
                        } else {
                                //Case 3: The resolved read is a normal read and the next
                                //operation is a write, and we need to make sure that the
                                //write is mod ordered after rf
-                               if (lastact!=rf)
+                               if (lastact != rf)
                                        mo_graph->addEdge(rf, lastact);
                        }
                        break;
@@ -1639,7 +1698,7 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
                                 * continue processing list.
                                 */
                                if (curr->is_rmw()) {
-                                       if (curr->get_reads_from()!=NULL)
+                                       if (curr->get_reads_from() != NULL)
                                                break;
                                        else
                                                continue;
@@ -1652,6 +1711,7 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
                                        *act < *last_sc_fence_thread_before) {
                                mo_graph->addEdge(act, curr);
                                added = true;
+                               break;
                        }
 
                        /*
@@ -1706,7 +1766,8 @@ bool ModelChecker::w_modification_order(ModelAction *curr)
 /** Arbitrary reads from the future are not allowed.  Section 29.3
  * part 9 places some constraints.  This method checks one result of constraint
  * constraint.  Others require compiler support. */
-bool ModelChecker::thin_air_constraint_may_allow(const ModelAction * writer, const ModelAction *reader) {
+bool ModelChecker::thin_air_constraint_may_allow(const ModelAction *writer, const ModelAction *reader)
+{
        if (!writer->is_rmw())
                return true;
 
@@ -1754,7 +1815,7 @@ bool ModelChecker::mo_may_allow(const ModelAction *writer, const ModelAction *re
                        }
                }
 
-               if (write_after_read && write_after_read!=writer && mo_graph->checkReachable(write_after_read, writer))
+               if (write_after_read && write_after_read != writer && mo_graph->checkReachable(write_after_read, writer))
                        return false;
        }
        return true;
@@ -2046,18 +2107,32 @@ bool ModelChecker::resolve_release_sequences(void *location, work_queue_t *work_
 void ModelChecker::add_action_to_lists(ModelAction *act)
 {
        int tid = id_to_int(act->get_tid());
-       action_trace->push_back(act);
+       ModelAction *uninit = NULL;
+       int uninit_id = -1;
+       action_list_t *list = get_safe_ptr_action(obj_map, act->get_location());
+       if (list->empty() && act->is_atomic_var()) {
+               uninit = new_uninitialized_action(act->get_location());
+               uninit_id = id_to_int(uninit->get_tid());
+               list->push_back(uninit);
+       }
+       list->push_back(act);
 
-       get_safe_ptr_action(obj_map, act->get_location())->push_back(act);
+       action_trace->push_back(act);
+       if (uninit)
+               action_trace->push_front(uninit);
 
        std::vector<action_list_t> *vec = get_safe_ptr_vect_action(obj_thrd_map, act->get_location());
        if (tid >= (int)vec->size())
                vec->resize(priv->next_thread_id);
        (*vec)[tid].push_back(act);
+       if (uninit)
+               (*vec)[uninit_id].push_front(uninit);
 
        if ((int)thrd_last_action->size() <= tid)
                thrd_last_action->resize(get_num_threads());
        (*thrd_last_action)[tid] = act;
+       if (uninit)
+               (*thrd_last_action)[uninit_id] = uninit;
 
        if (act->is_fence() && act->is_release()) {
                if ((int)thrd_last_fence_release->size() <= tid)
@@ -2066,7 +2141,7 @@ void ModelChecker::add_action_to_lists(ModelAction *act)
        }
 
        if (act->is_wait()) {
-               void *mutex_loc=(void *) act->get_value();
+               void *mutex_loc = (void *) act->get_value();
                get_safe_ptr_action(obj_map, mutex_loc)->push_back(act);
 
                std::vector<action_list_t> *vec = get_safe_ptr_vect_action(obj_thrd_map, mutex_loc);
@@ -2231,7 +2306,7 @@ bool ModelChecker::resolve_promises(ModelAction *write)
        //Check whether reading these writes has made threads unable to
        //resolve promises
 
-       for(unsigned int i=0;i<threads_to_check.size();i++)
+       for (unsigned int i = 0; i < threads_to_check.size(); i++)
                mo_check_promises(threads_to_check[i], write);
 
        return resolved;
@@ -2307,14 +2382,14 @@ void ModelChecker::check_promises_thread_disabled() {
  * cannot perform a future write that will resolve the promise due to
  * modificatin order constraints.
  *
- *     @parem tid The thread that either read from the model action
+ *     @param tid The thread that either read from the model action
  *     write, or actually did the model action write.
  *
- *     @parem write The ModelAction representing the relevant write.
+ *     @param write The ModelAction representing the relevant write.
  */
-
-void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write) {
-       void * location = write->get_location();
+void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write)
+{
+       void *location = write->get_location();
        for (unsigned int i = 0; i < promises->size(); i++) {
                Promise *promise = (*promises)[i];
                const ModelAction *act = promise->get_action();
@@ -2324,7 +2399,7 @@ void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write)
                        continue;
 
                //same thread as the promise
-               if ( act->get_tid()==tid ) {
+               if ( act->get_tid() == tid ) {
 
                        //do we have a pwrite for the promise, if not, set it
                        if (promise->get_write() == NULL ) {
@@ -2392,16 +2467,8 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
 
        ModelAction *last_sc_write = NULL;
 
-       /* Track whether this object has been initialized */
-       bool initialized = false;
-
-       if (curr->is_seqcst()) {
+       if (curr->is_seqcst())
                last_sc_write = get_last_seq_cst_write(curr);
-               /* We have to at least see the last sequentially consistent write,
-                        so we are initialized. */
-               if (last_sc_write != NULL)
-                       initialized = true;
-       }
 
        /* Iterate over all threads */
        for (i = 0; i < thrd_lists->size(); i++) {
@@ -2433,17 +2500,12 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
                        }
 
                        /* Include at most one act per-thread that "happens before" curr */
-                       if (act->happens_before(curr)) {
-                               initialized = true;
+                       if (act->happens_before(curr))
                                break;
-                       }
                }
        }
 
-       if (!initialized)
-               assert_bug("May read from uninitialized atomic");
-
-       if (DBG_ENABLED() || !initialized) {
+       if (DBG_ENABLED()) {
                model_print("Reached read action:\n");
                curr->print();
                model_print("Printing may_read_from\n");
@@ -2452,22 +2514,39 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
        }
 }
 
-bool ModelChecker::sleep_can_read_from(ModelAction * curr, const ModelAction *write) {
-       while(true) {
-               Node *prevnode=write->get_node()->get_parent();
+bool ModelChecker::sleep_can_read_from(ModelAction *curr, const ModelAction *write)
+{
+       while (true) {
+               /* UNINIT actions don't have a Node, and they never sleep */
+               if (write->is_uninitialized())
+                       return true;
+               Node *prevnode = write->get_node()->get_parent();
 
-               bool thread_sleep=prevnode->enabled_status(curr->get_tid())==THREAD_SLEEP_SET;
-               if (write->is_release()&&thread_sleep)
+               bool thread_sleep = prevnode->enabled_status(curr->get_tid()) == THREAD_SLEEP_SET;
+               if (write->is_release() && thread_sleep)
                        return true;
                if (!write->is_rmw()) {
                        return false;
                }
-               if (write->get_reads_from()==NULL)
+               if (write->get_reads_from() == NULL)
                        return true;
-               write=write->get_reads_from();
+               write = write->get_reads_from();
        }
 }
 
+/**
+ * @brief Create a new action representing an uninitialized atomic
+ * @param location The memory location of the atomic object
+ * @return A pointer to a new ModelAction
+ */
+ModelAction * ModelChecker::new_uninitialized_action(void *location) const
+{
+       ModelAction *act = (ModelAction *)snapshot_malloc(sizeof(class ModelAction));
+       act = new (act) ModelAction(ATOMIC_UNINIT, std::memory_order_relaxed, location, 0, model_thread);
+       act->create_cv(NULL);
+       return act;
+}
+
 static void print_list(action_list_t *list, int exec_num = -1)
 {
        action_list_t::iterator it;
@@ -2476,11 +2555,11 @@ static void print_list(action_list_t *list, int exec_num = -1)
        if (exec_num >= 0)
                model_print("Execution %d:\n", exec_num);
 
-       unsigned int hash=0;
+       unsigned int hash = 0;
 
        for (it = list->begin(); it != list->end(); it++) {
                (*it)->print();
-               hash=hash^(hash<<3)^((*it)->hash());
+               hash = hash^(hash<<3)^((*it)->hash());
        }
        model_print("HASH %u\n", hash);
        model_print("---------------------------------------------------------------------\n");
@@ -2490,23 +2569,23 @@ static void print_list(action_list_t *list, int exec_num = -1)
 void ModelChecker::dumpGraph(char *filename) {
        char buffer[200];
        sprintf(buffer, "%s.dot",filename);
-       FILE *file=fopen(buffer, "w");
+       FILE *file = fopen(buffer, "w");
        fprintf(file, "digraph %s {\n",filename);
        mo_graph->dumpNodes(file);
-       ModelAction ** thread_array=(ModelAction **)model_calloc(1, sizeof(ModelAction *)*get_num_threads());
+       ModelAction **thread_array = (ModelAction **)model_calloc(1, sizeof(ModelAction *)*get_num_threads());
 
        for (action_list_t::iterator it = action_trace->begin(); it != action_trace->end(); it++) {
-               ModelAction *action=*it;
+               ModelAction *action = *it;
                if (action->is_read()) {
                        fprintf(file, "N%u [label=\"%u, T%u\"];\n", action->get_seq_number(),action->get_seq_number(), action->get_tid());
-                       if (action->get_reads_from()!=NULL)
+                       if (action->get_reads_from() != NULL)
                                fprintf(file, "N%u -> N%u[label=\"rf\", color=red];\n", action->get_seq_number(), action->get_reads_from()->get_seq_number());
                }
                if (thread_array[action->get_tid()] != NULL) {
                        fprintf(file, "N%u -> N%u[label=\"sb\", color=blue];\n", thread_array[action->get_tid()]->get_seq_number(), action->get_seq_number());
                }
 
-               thread_array[action->get_tid()]=action;
+               thread_array[action->get_tid()] = action;
        }
        fprintf(file,"}\n");
        model_free(thread_array);
@@ -2601,15 +2680,19 @@ bool ModelChecker::is_enabled(thread_id_t tid) const
  * @param act The current action that will be explored. May be NULL only if
  * trace is exiting via an assertion (see ModelChecker::set_assert and
  * ModelChecker::has_asserted).
- * @return Return status from the 'swap' call (i.e., success/fail, 0/-1)
+ * @return Return the value returned by the current action
  */
-int ModelChecker::switch_to_master(ModelAction *act)
+uint64_t ModelChecker::switch_to_master(ModelAction *act)
 {
        DBG();
        Thread *old = thread_current();
        set_current_action(act);
        old->set_state(THREAD_READY);
-       return Thread::swap(old, &system_context);
+       if (Thread::swap(old, &system_context) < 0) {
+               perror("swap threads");
+               exit(EXIT_FAILURE);
+       }
+       return old->get_return_value();
 }
 
 /**