action: refactor ATOMIC_READ printing
[model-checker.git] / action.cc
index 486e89ee54aaddc8ea302c64b3a1eccef786a28c..a11467587901f258a03b9e11623403f60f3d1263 100644 (file)
--- a/action.cc
+++ b/action.cc
@@ -31,13 +31,14 @@ ModelAction::ModelAction(action_type_t type, memory_order order, void *loc,
        location(loc),
        value(value),
        reads_from(NULL),
+       last_fence_release(NULL),
        node(NULL),
        seq_number(ACTION_INITIAL_CLOCK),
        cv(NULL),
        sleep_flag(false)
 {
        /* References to NULL atomic variables can end up here */
-       ASSERT(loc || type == MODEL_FIXUP_RELSEQ);
+       ASSERT(loc || type == ATOMIC_FENCE || type == MODEL_FIXUP_RELSEQ);
 
        Thread *t = thread ? thread : thread_current();
        this->tid = t->get_id();
@@ -65,10 +66,17 @@ void ModelAction::copy_from_new(ModelAction *newaction)
 
 void ModelAction::set_seq_number(modelclock_t num)
 {
+       /* ATOMIC_UNINIT actions should never have non-zero clock */
+       ASSERT(!is_uninitialized());
        ASSERT(seq_number == ACTION_INITIAL_CLOCK);
        seq_number = num;
 }
 
+bool ModelAction::is_thread_start() const
+{
+       return type == THREAD_START;
+}
+
 bool ModelAction::is_relseq_fixup() const
 {
        return type == MODEL_FIXUP_RELSEQ;
@@ -116,6 +124,17 @@ bool ModelAction::is_failed_trylock() const
        return (type == ATOMIC_TRYLOCK && value == VALUE_TRYFAILED);
 }
 
+/** @return True if this operation is performed on a C/C++ atomic variable */
+bool ModelAction::is_atomic_var() const
+{
+       return is_read() || could_be_write();
+}
+
+bool ModelAction::is_uninitialized() const
+{
+       return type == ATOMIC_UNINIT;
+}
+
 bool ModelAction::is_read() const
 {
        return type == ATOMIC_READ || type == ATOMIC_RMWR || type == ATOMIC_RMW;
@@ -123,7 +142,7 @@ bool ModelAction::is_read() const
 
 bool ModelAction::is_write() const
 {
-       return type == ATOMIC_WRITE || type == ATOMIC_RMW || type == ATOMIC_INIT;
+       return type == ATOMIC_WRITE || type == ATOMIC_RMW || type == ATOMIC_INIT || type == ATOMIC_UNINIT;
 }
 
 bool ModelAction::could_be_write() const
@@ -156,6 +175,11 @@ bool ModelAction::is_initialization() const
        return type == ATOMIC_INIT;
 }
 
+bool ModelAction::is_relaxed() const
+{
+       return order == std::memory_order_relaxed;
+}
+
 bool ModelAction::is_acquire() const
 {
        switch (order) {
@@ -240,7 +264,7 @@ void ModelAction::process_rmw(ModelAction * act) {
  */
 bool ModelAction::could_synchronize_with(const ModelAction *act) const
 {
-       //Same thread can't be reordered
+       // Same thread can't be reordered
        if (same_thread(act))
                return false;
 
@@ -248,24 +272,26 @@ bool ModelAction::could_synchronize_with(const ModelAction *act) const
        if (!same_var(act))
                return false;
 
-       // Explore interleavings of seqcst writes to guarantee total order
-       // of seq_cst operations that don't commute
-       if ((could_be_write() || act->could_be_write()) && is_seqcst() && act->is_seqcst())
+       // Explore interleavings of seqcst writes/fences to guarantee total
+       // order of seq_cst operations that don't commute
+       if ((could_be_write() || act->could_be_write() || is_fence() || act->is_fence())
+                       && is_seqcst() && act->is_seqcst())
                return true;
 
-       // Explore synchronizing read/write pairs
-       if (is_read() && is_acquire() && act->could_be_write() && act->is_release())
+       // Explore synchronizing read/write/fence pairs
+       if (is_acquire() && act->is_release() && (is_read() || is_fence()) &&
+                       (act->could_be_write() || act->is_fence()))
                return true;
 
-       //lock just released...we can grab lock
+       // lock just released...we can grab lock
        if ((is_lock() ||is_trylock()) && (act->is_unlock()||act->is_wait()))
                return true;
 
-       //lock just acquired...we can fail to grab lock
+       // lock just acquired...we can fail to grab lock
        if (is_trylock() && act->is_success_lock())
                return true;
 
-       //other thread stalling on lock...we can release lock
+       // other thread stalling on lock...we can release lock
        if (is_unlock() && (act->is_trylock()||act->is_lock()))
                return true;
 
@@ -284,19 +310,19 @@ bool ModelAction::could_synchronize_with(const ModelAction *act) const
 
 bool ModelAction::is_conflicting_lock(const ModelAction *act) const
 {
-       //Must be different threads to reorder
+       // Must be different threads to reorder
        if (same_thread(act))
                return false;
        
-       //Try to reorder a lock past a successful lock
+       // Try to reorder a lock past a successful lock
        if (act->is_success_lock())
                return true;
        
-       //Try to push a successful trylock past an unlock
+       // Try to push a successful trylock past an unlock
        if (act->is_unlock() && is_trylock() && value == VALUE_TRYSUCCESS)
                return true;
 
-       //Try to push a successful trylock past a wait
+       // Try to push a successful trylock past a wait
        if (act->is_wait() && is_trylock() && value == VALUE_TRYSUCCESS)
                return true;
 
@@ -326,27 +352,23 @@ void ModelAction::set_try_lock(bool obtainedlock) {
                value=VALUE_TRYFAILED;
 }
 
+/** @return The Node associated with this ModelAction */
+Node * ModelAction::get_node() const
+{
+       /* UNINIT actions do not have a Node */
+       ASSERT(!is_uninitialized());
+       return node;
+}
+
 /**
  * Update the model action's read_from action
  * @param act The action to read from; should be a write
- * @return True if this read established synchronization
  */
-bool ModelAction::read_from(const ModelAction *act)
+void ModelAction::set_read_from(const ModelAction *act)
 {
-       ASSERT(cv);
        reads_from = act;
-       if (act != NULL && this->is_acquire()) {
-               rel_heads_list_t release_heads;
-               model->get_release_seq_heads(this, &release_heads);
-               int num_heads = release_heads.size();
-               for (unsigned int i = 0; i < release_heads.size(); i++)
-                       if (!synchronize_with(release_heads[i])) {
-                               model->set_bad_synchronization();
-                               num_heads--;
-                       }
-               return num_heads > 0;
-       }
-       return false;
+       if (act && act->is_uninitialized())
+               model->assert_bug("May read from uninitialized atomic\n");
 }
 
 /**
@@ -402,6 +424,9 @@ void ModelAction::print() const
        case THREAD_FINISH:
                type_str = "thread finish";
                break;
+       case ATOMIC_UNINIT:
+               type_str = "uninitialized";
+               break;
        case ATOMIC_READ:
                type_str = "atomic read";
                break;
@@ -445,7 +470,11 @@ void ModelAction::print() const
                type_str = "unknown type";
        }
 
-       uint64_t valuetoprint=type==ATOMIC_READ?(reads_from!=NULL?reads_from->value:VALUE_NONE):value;
+       uint64_t valuetoprint;
+       if (type == ATOMIC_READ && reads_from != NULL)
+               valuetoprint = reads_from->value;
+       else
+               valuetoprint = value;
 
        switch (this->order) {
        case std::memory_order_relaxed: