Merge branch 'datarace'
authorBrian Norris <banorris@uci.edu>
Sat, 7 Jul 2012 07:06:09 +0000 (00:06 -0700)
committerBrian Norris <banorris@uci.edu>
Sat, 7 Jul 2012 07:06:09 +0000 (00:06 -0700)
14 files changed:
action.cc
action.h
clockvector.cc
clockvector.h
cyclegraph.cc
cyclegraph.h
libatomic.cc
libatomic.h
model.cc
model.h
nodestack.cc
nodestack.h
threads.cc
threads.h

index 6627714e1089b2ad16c85cc7ef4abe43d77b6f95..f41b0eba7643e18a912b776c71470eddf71a1bf7 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()
@@ -33,7 +30,7 @@ bool ModelAction::is_read() const
 
 bool ModelAction::is_write() const
 {
-       return type == ATOMIC_WRITE;
+       return type == ATOMIC_WRITE || type == ATOMIC_INIT;
 }
 
 bool ModelAction::is_rmw() const
@@ -41,6 +38,11 @@ bool ModelAction::is_rmw() const
        return type == ATOMIC_RMW;
 }
 
+bool ModelAction::is_initialization() const
+{
+       return type == ATOMIC_INIT;
+}
+
 bool ModelAction::is_acquire() const
 {
        switch (order) {
@@ -115,7 +117,7 @@ bool ModelAction::is_synchronizing(const ModelAction *act) const
        return false;
 }
 
-void ModelAction::create_cv(ModelAction *parent)
+void ModelAction::create_cv(const ModelAction *parent)
 {
        ASSERT(cv == NULL);
 
@@ -125,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())
@@ -139,7 +141,7 @@ void ModelAction::read_from(ModelAction *act)
  * @return true if this action's thread has synchronized with act's thread
  * since the execution of act, false otherwise.
  */
-bool ModelAction::happens_before(ModelAction *act)
+bool ModelAction::happens_before(const ModelAction *act) const
 {
        return act->cv->synchronized_since(this);
 }
@@ -166,6 +168,9 @@ void ModelAction::print(void) const
        case ATOMIC_RMW:
                type_str = "atomic rmw";
                break;
+       case ATOMIC_INIT:
+               type_str = "init atomic";
+               break;
        default:
                type_str = "unknown type";
        }
index 0200111df387e586c4346c1858c0f139a6c6f4ce..111ac31124ef89d796e8d163c1b39a097c9a2c7c 100644 (file)
--- a/action.h
+++ b/action.h
 
 #define VALUE_NONE -1
 
+/** @brief Represents an action type, identifying one of several types of
+ * ModelAction */
 typedef enum action_type {
-       THREAD_CREATE,
-       THREAD_YIELD,
-       THREAD_JOIN,
-       ATOMIC_READ,
-       ATOMIC_WRITE,
-       ATOMIC_RMW
+       THREAD_CREATE,        /**< A thread creation action */
+       THREAD_YIELD,         /**< A thread yield action */
+       THREAD_JOIN,          /**< A thread join action */
+       ATOMIC_READ,          /**< An atomic read action */
+       ATOMIC_WRITE,         /**< An atomic write action */
+       ATOMIC_RMW,           /**< An atomic read-modify-write action */
+       ATOMIC_INIT           /**< Initialization of an atomic object (e.g.,
+                              *   atomic_init()) */
 } action_type_t;
 
 /* Forward declaration */
@@ -51,6 +55,7 @@ public:
        bool is_read() const;
        bool is_write() const;
        bool is_rmw() const;
+       bool is_initialization() const;
        bool is_acquire() const;
        bool is_release() const;
        bool is_seqcst() const;
@@ -58,11 +63,11 @@ public:
        bool same_thread(const ModelAction *act) const;
        bool is_synchronizing(const ModelAction *act) const;
 
-       void create_cv(ModelAction *parent = NULL);
+       void create_cv(const ModelAction *parent = NULL);
        ClockVector * get_cv() const { return cv; }
-       void read_from(ModelAction *act);
+       void read_from(const ModelAction *act);
 
-       bool happens_before(ModelAction *act);
+       bool happens_before(const ModelAction *act) const;
 
        inline bool operator <(const ModelAction& act) const {
                return get_seq_number() < act.get_seq_number();
@@ -101,6 +106,6 @@ private:
        ClockVector *cv;
 };
 
-typedef std::list<class ModelAction *> action_list_t;
+typedef std::list<ModelAction *> action_list_t;
 
 #endif /* __ACTION_H__ */
index e0ced522a14f88520f072248d54c7d3de9cee630..cfd99c66177568a642947c2959d87582010282c8 100644 (file)
@@ -75,7 +75,7 @@ void ClockVector::merge(ClockVector *cv)
  * thread, false otherwise. That is, this function returns:
  * <BR><CODE>act <= cv[act->tid]</CODE>
  */
-bool ClockVector::synchronized_since(ModelAction *act) const
+bool ClockVector::synchronized_since(const ModelAction *act) const
 {
        int i = id_to_int(act->get_tid());
 
index 82f1e3774608229f33f1379e9037e37fff5b87a2..1428886c80f692891a8103be8e721bc07644cdf7 100644 (file)
@@ -17,7 +17,7 @@ public:
        ClockVector(ClockVector *parent = NULL, ModelAction *act = NULL);
        ~ClockVector();
        void merge(ClockVector *cv);
-       bool synchronized_since(ModelAction *act) const;
+       bool synchronized_since(const ModelAction *act) const;
 
        void print() const;
        modelclock_t getClock(thread_id_t thread);
index c1fea4f3d0a96f14de433b6aac8b61e6f6479131..8788bfeba6c33140c0544a4ed39f8475864f3e8c 100644 (file)
@@ -1,4 +1,5 @@
 #include "cyclegraph.h"
+#include "action.h"
 
 CycleGraph::CycleGraph() {
        hasCycles=false;
@@ -24,17 +25,17 @@ void CycleGraph::addEdge(ModelAction *from, ModelAction *to) {
 }
 
 bool CycleGraph::checkReachable(CycleNode *from, CycleNode *to) {
-       std::vector<class CycleNode *> queue;
-       HashTable<class CycleNode *, class CycleNode *, uintptr_t, 4> discovered;
-       
+       std::vector<CycleNode *> queue;
+       HashTable<CycleNode *, CycleNode *, uintptr_t, 4> discovered;
+
        queue.push_back(from);
        discovered.put(from, from);
        while(!queue.empty()) {
-               class CycleNode * node=queue.back();
+               CycleNode * node=queue.back();
                queue.pop_back();
                if (node==to)
                        return true;
-               
+
                for(unsigned int i=0;i<node->getEdges()->size();i++) {
                        CycleNode *next=(*node->getEdges())[i];
                        if (!discovered.contains(next)) {
@@ -50,7 +51,7 @@ CycleNode::CycleNode(ModelAction *modelaction) {
        action=modelaction;
 }
 
-std::vector<class CycleNode *> * CycleNode::getEdges() {
+std::vector<CycleNode *> * CycleNode::getEdges() {
        return &edges;
 }
 
index 818a3e88f3afca519cbff27e8d4310f485e130ff..df9d46c17d108c51af33862cb1777a6b150ab515 100644 (file)
@@ -2,11 +2,11 @@
 #define CYCLEGRAPH_H
 
 #include "hashtable.h"
-#include "action.h"
 #include <vector>
 #include <inttypes.h>
 
 class CycleNode;
+class ModelAction;
 
 /** @brief A graph of Model Actions for tracking cycles. */
 class CycleGraph {
@@ -17,9 +17,9 @@ class CycleGraph {
 
  private:
        CycleNode * getNode(ModelAction *);
-       HashTable<class ModelAction *, class CycleNode *, uintptr_t, 4> actionToNode;
+       HashTable<ModelAction *, CycleNode *, uintptr_t, 4> actionToNode;
        bool checkReachable(CycleNode *from, CycleNode *to);
-       
+
        bool hasCycles;
 
 };
@@ -28,11 +28,11 @@ class CycleNode {
  public:
        CycleNode(ModelAction *action);
        void addEdge(CycleNode * node);
-       std::vector<class CycleNode *> * getEdges();
+       std::vector<CycleNode *> * getEdges();
 
  private:
        ModelAction *action;
-       std::vector<class CycleNode *> edges;
+       std::vector<CycleNode *> edges;
 };
 
 #endif
index 507f6853ca503e75664a86a5711f8f03c5cbc10a..a07653303c86348dfc5fe16fee790f137e478a11 100644 (file)
@@ -19,5 +19,7 @@ int atomic_load_explicit(struct atomic_object *obj, memory_order order)
 
 void atomic_init(struct atomic_object *obj, int value)
 {
+       DBG();
        obj->value = value;
+       model->switch_to_master(new ModelAction(ATOMIC_INIT, memory_order_relaxed, obj, value));
 }
index f24b5fbff35a10a3dcc2c88beca108ecb9093e75..71482c3d0a505d050fafc912951d8c084ee7fac6 100644 (file)
@@ -9,6 +9,7 @@
 extern "C" {
 #endif
 
+       /** @brief The memory orders specified by the C11/C++11 memory models */
        typedef enum memory_order {
                memory_order_relaxed,
                memory_order_consume,
index 4e2bb0250f05480ca3ccde1f6b99c26afe344a8b..884ed64d0b30b51ec73954e3797f10a2e70fe793 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -26,7 +26,7 @@ ModelChecker::ModelChecker()
        diverge(NULL),
        nextThread(THREAD_ID_T_NONE),
        action_trace(new action_list_t()),
-       thread_map(new std::map<int, class Thread *>),
+       thread_map(new std::map<int, Thread *>),
        obj_thrd_map(new std::map<void *, std::vector<action_list_t> >()),
        thrd_last_action(new std::vector<ModelAction *>(1)),
        node_stack(new NodeStack()),
@@ -37,7 +37,7 @@ ModelChecker::ModelChecker()
 /** @brief Destructor */
 ModelChecker::~ModelChecker()
 {
-       std::map<int, class Thread *>::iterator it;
+       std::map<int, Thread *>::iterator it;
        for (it = thread_map->begin(); it != thread_map->end(); it++)
                delete (*it).second;
        delete thread_map;
@@ -323,6 +323,9 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
 
        ASSERT(curr->is_read());
 
+       /* Track whether this object has been initialized */
+       bool initialized = false;
+
        for (i = 0; i < thrd_lists->size(); i++) {
                action_list_t *list = &(*thrd_lists)[i];
                action_list_t::reverse_iterator rit;
@@ -340,11 +343,28 @@ void ModelChecker::build_reads_from_past(ModelAction *curr)
                        }
                        curr->get_node()->add_read_from(act);
 
-                       /* Include at most one act that "happens before" curr */
-                       if (act->happens_before(curr))
+                       /* Include at most one act per-thread that "happens before" curr */
+                       if (act->happens_before(curr)) {
+                               initialized = true;
                                break;
+                       }
                }
        }
+
+       if (!initialized) {
+               /* TODO: need a more informative way of reporting errors */
+               printf("ERROR: may read from uninitialized atomic\n");
+       }
+
+       if (DBG_ENABLED() || !initialized) {
+               printf("Reached read action:\n");
+               curr->print();
+               printf("Printing may_read_from\n");
+               curr->get_node()->print_may_read_from();
+               printf("End printing may_read_from\n");
+       }
+
+       ASSERT(initialized);
 }
 
 static void print_list(action_list_t *list)
diff --git a/model.h b/model.h
index 22430378298aaa60c7755e40be665fe68d1bd275..fbf1b3f0909ff3fd67fbb10e905d1c0b7ff9003b 100644 (file)
--- a/model.h
+++ b/model.h
@@ -30,7 +30,7 @@ public:
        ~ModelChecker();
 
        /** The scheduler to use: tracks the running/ready Threads */
-       class Scheduler *scheduler;
+       Scheduler *scheduler;
 
        /** Stores the context for the main model-checking system thread (call
         * once)
@@ -41,13 +41,6 @@ public:
        /** @returns the context for the main model-checking system thread */
        ucontext_t * get_system_context(void) { return system_context; }
 
-       /**
-        * Stores the ModelAction for the current thread action.  Call this
-        * immediately before switching from user- to system-context to pass
-        * data between them.
-        * @param act The ModelAction created by the user-thread action
-        */
-       void set_current_action(ModelAction *act) { current_action = act; }
        void check_current_action(void);
        void print_summary(void);
        Thread * schedule_next_thread();
@@ -70,6 +63,14 @@ private:
        modelclock_t used_sequence_numbers;
        int num_executions;
 
+       /**
+        * Stores the ModelAction for the current thread action.  Call this
+        * immediately before switching from user- to system-context to pass
+        * data between them.
+        * @param act The ModelAction created by the user-thread action
+        */
+       void set_current_action(ModelAction *act) { current_action = act; }
+
        ModelAction * get_last_conflict(ModelAction *act);
        void set_backtracking(ModelAction *act);
        thread_id_t get_next_replay_thread();
@@ -87,10 +88,10 @@ private:
 
        ucontext_t *system_context;
        action_list_t *action_trace;
-       std::map<int, class Thread *> *thread_map;
+       std::map<int, Thread *> *thread_map;
        std::map<void *, std::vector<action_list_t> > *obj_thrd_map;
        std::vector<ModelAction *> *thrd_last_action;
-       class NodeStack *node_stack;
+       NodeStack *node_stack;
        ModelAction *next_backtrack;
 };
 
index d3b7c104316161d0268c8ae1b2db7a116fbbac74..10f7a72b5ef3ff5705fdbe29771def18212ecf11 100644 (file)
@@ -46,6 +46,14 @@ void Node::print()
                printf("******** empty action ********\n");
 }
 
+/** @brief Prints info about may_read_from set */
+void Node::print_may_read_from()
+{
+       readfrom_set_t::iterator it;
+       for (it = may_read_from.begin(); it != may_read_from.end(); it++)
+               (*it)->print();
+}
+
 /**
  * Checks if the Thread associated with this thread ID has been explored from
  * this Node already.
@@ -117,9 +125,9 @@ bool Node::is_enabled(Thread *t)
  * Add an action to the may_read_from set.
  * @param act is the action to add
  */
-void Node::add_read_from(ModelAction *act)
+void Node::add_read_from(const ModelAction *act)
 {
-       may_read_from.insert(act);
+       may_read_from.push_back(act);
 }
 
 void Node::explore(thread_id_t tid)
index 37f9261149bc49a9d0a99182e21102be39e1161a..c09b628b4ffc9a8f91a7997f628f3234c1e6b7df 100644 (file)
@@ -7,14 +7,13 @@
 
 #include <list>
 #include <vector>
-#include <set>
 #include <cstddef>
 #include "threads.h"
 #include "mymemory.h"
 
 class ModelAction;
 
-typedef std::set< ModelAction *, std::less< ModelAction *>, MyAlloc< ModelAction * > > action_set_t;
+typedef std::list< const ModelAction *, MyAlloc< const ModelAction * > > readfrom_set_t;
 
 /**
  * @brief A single node in a NodeStack
@@ -44,9 +43,10 @@ public:
         * occurred previously in the stack. */
        Node * get_parent() const { return parent; }
 
-       void add_read_from(ModelAction *act);
+       void add_read_from(const ModelAction *act);
 
        void print();
+       void print_may_read_from();
 
        MEMALLOC
 private:
@@ -61,10 +61,10 @@ private:
 
        /** The set of ModelActions that this the action at this Node may read
         *  from. Only meaningful if this Node represents a 'read' action. */
-       action_set_t may_read_from;
+       readfrom_set_t may_read_from;
 };
 
-typedef std::list<class Node *, MyAlloc< class Node * > > node_list_t;
+typedef std::list< Node *, MyAlloc< Node * > > node_list_t;
 
 /**
  * @brief A stack of nodes
index 37b0f1a87ee6fb9ac975a84c8df9adf018d808c5..b6eaee4ea18cb511b9d4e37edc78814669e152c8 100644 (file)
@@ -19,6 +19,7 @@ static void stack_free(void *stack)
 
 Thread * thread_current(void)
 {
+       ASSERT(model);
        return model->scheduler->get_current_thread();
 }
 
@@ -68,7 +69,9 @@ void Thread::complete()
        }
 }
 
-Thread::Thread(thrd_t *t, void (*func)(void *), void *a) {
+Thread::Thread(thrd_t *t, void (*func)(void *), void *a) :
+       last_action_val(VALUE_NONE)
+{
        int ret;
 
        user_thread = t;
index a97a04c704449963981fe443a711c64abc716fb3..0f39a836f49efae34c63415f433e37715a43d258 100644 (file)
--- a/threads.h
+++ b/threads.h
@@ -13,10 +13,19 @@ typedef int thread_id_t;
 
 #define THREAD_ID_T_NONE       -1
 
+/** @brief Represents the state of a user Thread */
 typedef enum thread_state {
+       /** Thread was just created and hasn't run yet */
        THREAD_CREATED,
+       /** Thread is running */
        THREAD_RUNNING,
+       /**
+        * Thread has yielded to the model-checker but is ready to run. Used
+        * during an action that caused a context switch to the model-checking
+        * context.
+        */
        THREAD_READY,
+       /** Thread has completed its execution */
        THREAD_COMPLETED
 } thread_state;
 
@@ -41,6 +50,21 @@ public:
        void set_creation(ModelAction *act) { creation = act; }
        ModelAction * get_creation() { return creation; }
 
+       /**
+        * Set a return value for the last action in this thread (e.g., for an
+        * atomic read).
+        * @param value The value to return
+        */
+       void set_return_value(int value) { last_action_val = value; }
+
+       /**
+        * Retrieve a return value for the last action in this thread. Used,
+        * for instance, for an atomic read to return the 'read' value. Should
+        * be called from a user context.
+        * @return The value 'returned' by the action
+        */
+       int get_return_value() { return last_action_val; }
+
        friend void thread_startup();
 
        SNAPSHOTALLOC
@@ -56,6 +80,13 @@ private:
        thrd_t *user_thread;
        thread_id_t id;
        thread_state state;
+
+       /**
+        * The value returned by the last action in this thread
+        * @see Thread::set_return_value()
+        * @see Thread::get_return_value()
+        */
+       int last_action_val;
 };
 
 Thread * thread_current();