action / threads: add THREAD_START action at start of each thread
[model-checker.git] / action.cc
index ec50807422cc4a8e6c9864e65c561896df579000..d9aae2d4958253977e9f0256fb87076174e94a67 100644 (file)
--- a/action.cc
+++ b/action.cc
@@ -5,19 +5,16 @@
 #include "clockvector.h"
 #include "common.h"
 
-ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, int value)
+ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, int value) :
+       type(type),
+       order(order),
+       location(loc),
+       value(value),
+       cv(NULL)
 {
        Thread *t = thread_current();
-       ModelAction *act = this;
-
-       act->type = type;
-       act->order = order;
-       act->location = loc;
-       act->tid = t->get_id();
-       act->value = value;
-       act->seq_number = model->get_next_seq_num();
-
-       cv = NULL;
+       this->tid = t->get_id();
+       this->seq_number = model->get_next_seq_num();
 }
 
 ModelAction::~ModelAction()
@@ -26,17 +23,27 @@ ModelAction::~ModelAction()
                delete cv;
 }
 
-bool ModelAction::is_read()
+bool ModelAction::is_read() const
 {
        return type == ATOMIC_READ;
 }
 
-bool ModelAction::is_write()
+bool ModelAction::is_write() const
+{
+       return type == ATOMIC_WRITE || type == ATOMIC_INIT;
+}
+
+bool ModelAction::is_rmw() const
+{
+       return type == ATOMIC_RMW;
+}
+
+bool ModelAction::is_initialization() const
 {
-       return type == ATOMIC_WRITE;
+       return type == ATOMIC_INIT;
 }
 
-bool ModelAction::is_acquire()
+bool ModelAction::is_acquire() const
 {
        switch (order) {
        case memory_order_acquire:
@@ -48,7 +55,7 @@ bool ModelAction::is_acquire()
        }
 }
 
-bool ModelAction::is_release()
+bool ModelAction::is_release() const
 {
        switch (order) {
        case memory_order_release:
@@ -60,32 +67,59 @@ bool ModelAction::is_release()
        }
 }
 
-bool ModelAction::same_var(ModelAction *act)
+bool ModelAction::is_seqcst() const
+{
+       return order==memory_order_seq_cst;
+}
+
+bool ModelAction::same_var(const ModelAction *act) const
 {
        return location == act->location;
 }
 
-bool ModelAction::same_thread(ModelAction *act)
+bool ModelAction::same_thread(const ModelAction *act) const
 {
        return tid == act->tid;
 }
 
-bool ModelAction::is_dependent(ModelAction *act)
+/** The is_synchronizing method should only explore interleavings if:
+ *  (1) the operations are seq_cst and don't commute or
+ *  (2) the reordering may establish or break a synchronization relation.
+ *  Other memory operations will be dealt with by using the reads_from
+ *  relation.
+ *
+ *  @param act is the action to consider exploring a reordering.
+ *  @return tells whether we have to explore a reordering.
+ */
+
+bool ModelAction::is_synchronizing(const ModelAction *act) const
 {
-       if (!is_read() && !is_write())
+       //Same thread can't be reordered
+       if (same_thread(act))
                return false;
-       if (!act->is_read() && !act->is_write())
+
+       // Different locations commute
+       if (!same_var(act))
                return false;
-       if (same_var(act) && !same_thread(act) &&
-                       (is_write() || act->is_write()))
+
+       // Explore interleavings of seqcst writes to guarantee total order
+       // of seq_cst operations that don't commute
+       if (is_write() && is_seqcst() && act->is_write() && act->is_seqcst())
+               return true;
+
+       // Explore synchronizing read/write pairs
+       if (is_read() && is_acquire() && act->is_write() && act->is_release())
                return true;
+       if (is_write() && is_release() && act->is_read() && act->is_acquire())
+               return true;
+
+       // Otherwise handle by reads_from relation
        return false;
 }
 
-void ModelAction::create_cv(ModelAction *parent)
+void ModelAction::create_cv(const ModelAction *parent)
 {
-       if (cv)
-               return;
+       ASSERT(cv == NULL);
 
        if (parent)
                cv = new ClockVector(parent->cv, this);
@@ -93,7 +127,7 @@ void ModelAction::create_cv(ModelAction *parent)
                cv = new ClockVector(NULL, this);
 }
 
-void ModelAction::read_from(ModelAction *act)
+void ModelAction::read_from(const ModelAction *act)
 {
        ASSERT(cv);
        if (act->is_release() && this->is_acquire())
@@ -101,13 +135,27 @@ void ModelAction::read_from(ModelAction *act)
        value = act->value;
 }
 
-void ModelAction::print(void)
+/**
+ * Check whether 'this' happens before act, according to the memory-model's
+ * happens before relation. This is checked via the ClockVector constructs.
+ * @return true if this action's thread has synchronized with act's thread
+ * since the execution of act, false otherwise.
+ */
+bool ModelAction::happens_before(const ModelAction *act) const
+{
+       return act->cv->synchronized_since(this);
+}
+
+void ModelAction::print(void) const
 {
        const char *type_str;
        switch (this->type) {
        case THREAD_CREATE:
                type_str = "thread create";
                break;
+       case THREAD_START:
+               type_str = "thread start";
+               break;
        case THREAD_YIELD:
                type_str = "thread yield";
                break;
@@ -123,6 +171,9 @@ void ModelAction::print(void)
        case ATOMIC_RMW:
                type_str = "atomic rmw";
                break;
+       case ATOMIC_INIT:
+               type_str = "init atomic";
+               break;
        default:
                type_str = "unknown type";
        }