fix conflict
authorroot <root@dw-6.eecs.uci.edu>
Mon, 22 Jul 2019 23:04:26 +0000 (16:04 -0700)
committerroot <root@dw-6.eecs.uci.edu>
Mon, 22 Jul 2019 23:04:26 +0000 (16:04 -0700)
14 files changed:
action.h
cmodelint.cc
execution.cc
execution.h
funcnode.cc
funcnode.h
history.cc
history.h
include/cmodelint.h
include/memoryorder.h
include/mypthread.h
model.cc
model.h
pthread.cc

index 7c79f435cff8aba9b248fba38af5ee40b8aac84c..0ecb5c365b080ec5d9dee4827ece1a959080cfc5 100644 (file)
--- a/action.h
+++ b/action.h
@@ -25,6 +25,7 @@ using std::memory_order_acquire;
 using std::memory_order_release;
 using std::memory_order_acq_rel;
 using std::memory_order_seq_cst;
+using std::volatile_order;
 
 /**
  * @brief A recognizable don't-care value for use in the ModelAction::value
@@ -72,6 +73,8 @@ typedef enum action_type {
        ATOMIC_NOTIFY_ALL,      // < A notify all action
        ATOMIC_WAIT,    // < A wait action
        ATOMIC_ANNOTATION,      // < An annotation action to pass information to a trace analysis
+       VOLATILE_READ,
+       VOLATILE_WRITE,
        NOOP    // no operation, which returns control to scheduler
 } action_type_t;
 
index 9faae5345e857caa7918b278527ba713c9259ef8..67364d5abf7a9a3a51178a8dc4f5f37fea0f7283 100644 (file)
 #include "threads-model.h"
 #include "datarace.h"
 
-memory_order orders[6] = {
+memory_order orders[8] = {
        memory_order_relaxed, memory_order_consume, memory_order_acquire,
-       memory_order_release, memory_order_acq_rel, memory_order_seq_cst
+       memory_order_release, memory_order_acq_rel, memory_order_seq_cst,
+       volatile_order
 };
 
 static void ensureModel() {
@@ -93,6 +94,47 @@ void model_rmwc_action_helper(void *obj, int atomic_index, const char *position)
        model->switch_to_master(new ModelAction(ATOMIC_RMWC, position, orders[atomic_index], obj));
 }
 
+// cds volatile loads
+uint8_t cds_volatile_load8(void * obj, int atomic_index, const char * position) {
+       ensureModel();
+       return (uint8_t) model->switch_to_master(
+               new ModelAction(VOLATILE_READ, position, orders[atomic_index], obj));
+}
+uint16_t cds_volatile_load16(void * obj, int atomic_index, const char * position) {
+       ensureModel();
+       return (uint16_t) model->switch_to_master(
+               new ModelAction(VOLATILE_READ, position, orders[atomic_index], obj));
+}
+uint32_t cds_volatile_load32(void * obj, int atomic_index, const char * position) {
+       ensureModel();
+       return (uint32_t) model->switch_to_master(
+               new ModelAction(VOLATILE_READ, position, orders[atomic_index], obj)
+               );
+}
+uint64_t cds_volatile_load64(void * obj, int atomic_index, const char * position) {
+       ensureModel();
+       return model->switch_to_master(
+               new ModelAction(VOLATILE_READ, position, orders[atomic_index], obj));
+}
+
+// cds volatile stores
+void cds_volatile_store8(void * obj, uint8_t val, int atomic_index, const char * position) {
+       ensureModel();
+       model->switch_to_master(new ModelAction(VOLATILE_WRITE, position, orders[atomic_index], obj, (uint64_t) val));
+}
+void cds_volatile_store16(void * obj, uint16_t val, int atomic_index, const char * position) {
+       ensureModel();
+       model->switch_to_master(new ModelAction(VOLATILE_WRITE, position, orders[atomic_index], obj, (uint64_t) val));
+}
+void cds_volatile_store32(void * obj, uint32_t val, int atomic_index, const char * position) {
+       ensureModel();
+       model->switch_to_master(new ModelAction(VOLATILE_WRITE, position, orders[atomic_index], obj, (uint64_t) val));
+}
+void cds_volatile_store64(void * obj, uint64_t val, int atomic_index, const char * position) {
+       ensureModel();
+       model->switch_to_master(new ModelAction(VOLATILE_WRITE, position, orders[atomic_index], obj, (uint64_t) val));
+}
+
 // cds atomic inits
 #define CDSATOMICINT(size)                                              \
        void cds_atomic_init ## size (void * obj, uint ## size ## _t val, const char * position) { \
index 706e078d97ca3a5031a6226a3e60d3a3284d24fb..323c83d36fe4273ddf0d08508af7653abadf3b91 100644 (file)
@@ -27,6 +27,7 @@ struct model_snapshot_members {
                next_thread_id(INITIAL_THREAD_ID),
                used_sequence_numbers(0),
                bugs(),
+               dataraces(),
                bad_synchronization(false),
                asserted(false)
        { }
@@ -34,12 +35,16 @@ struct model_snapshot_members {
        ~model_snapshot_members() {
                for (unsigned int i = 0;i < bugs.size();i++)
                        delete bugs[i];
+               for (unsigned int i = 0;i < dataraces.size(); i++) 
+                       delete dataraces[i];
                bugs.clear();
+               dataraces.clear();
        }
 
        unsigned int next_thread_id;
        modelclock_t used_sequence_numbers;
        SnapVector<bug_message *> bugs;
+       SnapVector<bug_message *> dataraces;
        /** @brief Incorrectly-ordered synchronization was made */
        bool bad_synchronization;
        bool asserted;
@@ -185,12 +190,38 @@ bool ModelExecution::assert_bug(const char *msg)
        return false;
 }
 
+/* @brief Put data races in a different list from other bugs. The purpose
+ *  is to continue the program untill the number of data races exceeds a 
+ *  threshold */
+
+/* TODO: check whether set_assert should be called */
+bool ModelExecution::assert_race(const char *msg)
+{
+       priv->dataraces.push_back(new bug_message(msg));
+
+       if (isfeasibleprefix()) {
+               set_assert();
+               return true;
+       }
+       return false;
+}
+
 /** @return True, if any bugs have been reported for this execution */
 bool ModelExecution::have_bug_reports() const
 {
        return priv->bugs.size() != 0;
 }
 
+/** @return True, if any fatal bugs have been reported for this execution.
+ *  Any bug other than a data race is considered a fatal bug. Data races 
+ *  are not considered fatal unless the number of races is exceeds
+ *  a threshold (temporarily set as 15). 
+ */
+bool ModelExecution::have_fatal_bug_reports() const
+{
+       return priv->bugs.size() != 0 || priv->dataraces.size() >= 15;
+}
+
 SnapVector<bug_message *> * ModelExecution::get_bugs() const
 {
        return &priv->bugs;
@@ -1621,8 +1652,8 @@ Thread * ModelExecution::take_step(ModelAction *curr)
        curr = check_current_action(curr);
        ASSERT(curr);
 
-       // model_print("poitner loc: %p, thread: %d, type: %d, order: %d, position: %s\n", curr, curr->get_tid(), curr->get_type(), curr->get_mo(), curr->get_position() );
-       model->get_history()->add_func_atomic( curr, curr_thrd->get_id() );
+       /* Process this action in ModelHistory for records*/
+       model->get_history()->process_action( curr, curr_thrd->get_id() );
 
        if (curr_thrd->is_blocked() || curr_thrd->is_complete())
                scheduler->remove_thread(curr_thrd);
index 682e94b15017ef2c16d4dd0085f9a7ed99cb3644..74496c67d9eae8538d4ad9eaaf3c1d4345598b8e 100644 (file)
@@ -68,7 +68,11 @@ public:
        bool check_action_enabled(ModelAction *curr);
 
        bool assert_bug(const char *msg);
+       bool assert_race(const char *msg);
+
        bool have_bug_reports() const;
+       bool have_fatal_bug_reports() const;
+
        SnapVector<bug_message *> * get_bugs() const;
 
        bool has_asserted() const;
index 12bf530661322fc26a3a0a06fe1039a1037d3897..e07ab9e22b13c9775e591e35ca81eba44fc43252 100644 (file)
@@ -3,7 +3,9 @@
 FuncNode::FuncNode() :
        func_inst_map(),
        inst_list(),
-       entry_insts()
+       entry_insts(),
+       thrd_read_map(),
+       read_locations()
 {}
 
 /* Check whether FuncInst with the same type, position, and location
@@ -38,9 +40,7 @@ FuncInst * FuncNode::get_or_add_action(ModelAction *act)
 
                        func_inst = new FuncInst(act, this);
                        inst->get_collisions()->push_back(func_inst);
-                       inst_list.push_back(func_inst); // delete?
-                       if (func_inst->is_read())
-                               group_reads_by_loc(func_inst);
+                       inst_list.push_back(func_inst);         // delete?
 
                        return func_inst;
                }
@@ -49,12 +49,10 @@ FuncInst * FuncNode::get_or_add_action(ModelAction *act)
        }
 
        FuncInst * func_inst = new FuncInst(act, this);
+
        func_inst_map.put(position, func_inst);
        inst_list.push_back(func_inst);
 
-       if (func_inst->is_read())
-               group_reads_by_loc(func_inst);
-
        return func_inst;
 }
 
@@ -72,29 +70,113 @@ void FuncNode::add_entry_inst(FuncInst * inst)
        entry_insts.push_back(inst);
 }
 
-/* group atomic read actions by memory location */
-void FuncNode::group_reads_by_loc(FuncInst * inst)
+/* @param inst_list a list of FuncInsts; this argument comes from ModelExecution
+ * Link FuncInsts in a list - add one FuncInst to another's predecessors and successors
+ */
+void FuncNode::link_insts(func_inst_list_t * inst_list)
 {
-       ASSERT(inst);
-       if ( !inst->is_read() )
+       if (inst_list == NULL)
                return;
 
-       void * location = inst->get_location();
+       func_inst_list_t::iterator it = inst_list->begin();
+       func_inst_list_t::iterator prev;
 
-       func_inst_list_mt * reads;
-       if ( !reads_by_loc.contains(location) ) {
-               reads = new func_inst_list_mt();
-               reads->push_back(inst);
-               reads_by_loc.put(location, reads);
+       if (inst_list->size() == 0)
                return;
+
+       /* add the first instruction to the list of entry insts */
+       FuncInst * entry_inst = *it;
+       add_entry_inst(entry_inst);
+
+       it++;
+       while (it != inst_list->end()) {
+               prev = it;
+               prev--;
+
+               FuncInst * prev_inst = *prev;
+               FuncInst * curr_inst = *it;
+
+               prev_inst->add_succ(curr_inst);
+               curr_inst->add_pred(prev_inst);
+
+               it++;
        }
+}
 
-       reads = reads_by_loc.get(location);
-       func_inst_list_mt::iterator it;
-       for (it = reads->begin();it != reads->end();it++) {
-               if (inst == *it)
-                       return;
+/* @param tid thread id
+ * Store the values read by atomic read actions into thrd_read_map */
+void FuncNode::store_read(ModelAction * act, uint32_t tid)
+{
+       ASSERT(act);
+
+       void * location = act->get_location();
+       uint64_t read_from_val = act->get_reads_from_value();
+
+       if (thrd_read_map.size() <= tid)
+               thrd_read_map.resize(tid + 1);
+
+       read_map_t * read_map = thrd_read_map[tid];
+       if (read_map == NULL) {
+               read_map = new read_map_t();
+               thrd_read_map[tid] = read_map;
        }
 
-       reads->push_back(inst);
+       read_map->put(location, read_from_val);
+
+       /* Store the memory locations where atomic reads happen */
+       bool push_loc = true;
+       ModelList<void *>::iterator it;
+       for (it = read_locations.begin(); it != read_locations.end(); it++) {
+               if (location == *it) {
+                       push_loc = false;
+                       break;
+               }
+       }
+
+       if (push_loc)
+               read_locations.push_back(location);
+}
+
+uint64_t FuncNode::query_last_read(ModelAction * act, uint32_t tid)
+{
+       if (thrd_read_map.size() <= tid)
+               return 0xdeadbeef;
+
+       read_map_t * read_map = thrd_read_map[tid];
+       void * location = act->get_location();
+
+       /* last read value not found */
+       if ( !read_map->contains(location) )
+               return 0xdeadbeef;
+
+       uint64_t read_val = read_map->get(location);
+       return read_val;
+}
+
+/* @param tid thread id
+ * Reset read map for a thread. This function shall only be called
+ * when a thread exits a function
+ */
+void FuncNode::clear_read_map(uint32_t tid)
+{
+       ASSERT(thrd_read_map.size() > tid);
+       thrd_read_map[tid]->reset();
+}
+
+/* @param tid thread id
+ * Print the values read by the last read actions for each memory location
+ */
+void FuncNode::print_last_read(uint32_t tid)
+{
+       ASSERT(thrd_read_map.size() > tid);
+       read_map_t * read_map = thrd_read_map[tid];
+
+       ModelList<void *>::iterator it;
+       for (it = read_locations.begin(); it != read_locations.end(); it++) {
+               if ( !read_map->contains(*it) )
+                       break;
+
+               uint64_t read_val = read_map->get(*it);
+               model_print("last read of thread %d at %p: 0x%x\n", tid, *it, read_val);
+       }
 }
index c8c76ba7f8695bdf084e0c189aae910924e8e271..be6f406a4e3453b029247e8e23550deb9186cd99 100644 (file)
@@ -5,6 +5,7 @@
 class ModelAction;
 
 typedef ModelList<FuncInst *> func_inst_list_mt;
+typedef HashTable<void *, uint64_t, uintptr_t, 4, model_malloc, model_calloc, model_free> read_map_t;
 
 class FuncNode {
 public:
@@ -22,8 +23,13 @@ public:
        func_inst_list_mt * get_inst_list() { return &inst_list; }
        func_inst_list_mt * get_entry_insts() { return &entry_insts; }
        void add_entry_inst(FuncInst * inst);
+       void link_insts(func_inst_list_t * inst_list);
 
-       void group_reads_by_loc(FuncInst * inst);
+       void store_read(ModelAction * act, uint32_t tid);
+       uint64_t query_last_read(ModelAction * act, uint32_t tid);
+       void clear_read_map(uint32_t tid);
+
+       void print_last_read(uint32_t tid);
 
        MEMALLOC
 private:
@@ -32,9 +38,6 @@ private:
 
        /* Use source line number as the key of hashtable, to check if
         * atomic operation with this line number has been added or not
-        *
-        * To do: cds_atomic_compare_exchange contains three atomic operations
-        * that are feeded with the same source line number by llvm pass
         */
        HashTable<const char *, FuncInst *, uintptr_t, 4, model_malloc, model_calloc, model_free> func_inst_map;
 
@@ -44,6 +47,7 @@ private:
        /* possible entry atomic actions in this function */
        func_inst_list_mt entry_insts;
 
-       /* group atomic read actions by memory location */
-       HashTable<void *, func_inst_list_mt *, uintptr_t, 4, model_malloc, model_calloc, model_free> reads_by_loc;
+       /* Store the values read by atomic read actions per memory location for each thread */
+       ModelVector<read_map_t *> thrd_read_map;
+       ModelList<void *> read_locations;
 };
index cdb642fd3fefd50a8a121a6400ce5f53279b20fd..352a9a4cc479065062d684bfc56fe16fbfa88dd7 100644 (file)
 
 /** @brief Constructor */
 ModelHistory::ModelHistory() :
-       func_counter(0),        /* function id starts with 0 */
+       func_counter(1), /* function id starts with 1 */
        func_map(),
        func_map_rev(),
-       func_atomics()
+       func_nodes()
 {}
 
 void ModelHistory::enter_function(const uint32_t func_id, thread_id_t tid)
@@ -60,11 +60,14 @@ void ModelHistory::exit_function(const uint32_t func_id, thread_id_t tid)
        uint32_t last_func_id = func_list->back();
 
        if (last_func_id == func_id) {
-               func_list->pop_back();
+               /* clear read map upon exiting functions */
+               FuncNode * func_node = func_nodes[func_id];
+               func_node->clear_read_map(tid);
 
                func_inst_list_t * curr_inst_list = func_inst_lists->back();
-               link_insts(curr_inst_list);
+               func_node->link_insts(curr_inst_list);
 
+               func_list->pop_back();
                func_inst_lists->pop_back();
        } else {
                model_print("trying to exit with a wrong function id\n");
@@ -73,7 +76,7 @@ void ModelHistory::exit_function(const uint32_t func_id, thread_id_t tid)
        //model_print("thread %d exiting func %d\n", tid, func_id);
 }
 
-void ModelHistory::add_func_atomic(ModelAction *act, thread_id_t tid)
+void ModelHistory::process_action(ModelAction *act, thread_id_t tid)
 {
        /* return if thread i has not entered any function or has exited
           from all functions */
@@ -93,70 +96,52 @@ void ModelHistory::add_func_atomic(ModelAction *act, thread_id_t tid)
 
        uint32_t func_id = func_list->back();
 
-       if ( func_atomics.size() <= func_id )
-               func_atomics.resize( func_id + 1 );
+       if ( func_nodes.size() <= func_id )
+               func_nodes.resize( func_id + 1 );
 
-       FuncNode * func_node = func_atomics[func_id];
+       FuncNode * func_node = func_nodes[func_id];
        if (func_node == NULL) {
                const char * func_name = func_map_rev[func_id];
                func_node = new FuncNode();
                func_node->set_func_id(func_id);
                func_node->set_func_name(func_name);
 
-               func_atomics[func_id] = func_node;
+               func_nodes[func_id] = func_node;
        }
 
+       /* add corresponding FuncInst to func_node */
        FuncInst * inst = func_node->get_or_add_action(act);
-       if (inst != NULL) {
-               func_inst_list_t * curr_inst_list = func_inst_lists->back();
-
-               ASSERT(curr_inst_list != NULL);
-               curr_inst_list->push_back(inst);
-       }
-}
-
-/* Link FuncInsts in a list - add one FuncInst to another's predecessors and successors */
-void ModelHistory::link_insts(func_inst_list_t * inst_list)
-{
-       if (inst_list == NULL)
-               return;
 
-       func_inst_list_t::iterator it = inst_list->begin();
-       func_inst_list_t::iterator prev;
-
-       if (inst_list->size() == 0)
+       if (inst == NULL)
                return;
 
-       /* add the first instruction to the list of entry insts */
-       FuncInst * entry_inst = *it;
-       FuncNode * func_node = entry_inst->get_func_node();
-       func_node->add_entry_inst(entry_inst);
-
-       it++;
-       while (it != inst_list->end()) {
-               prev = it;
-               prev--;
+       if (inst->is_read())
+               func_node->store_read(act, tid);
 
-               FuncInst * prev_inst = *prev;
-               FuncInst * curr_inst = *it;
+       /* add to curr_inst_list */
+       func_inst_list_t * curr_inst_list = func_inst_lists->back();
+       ASSERT(curr_inst_list != NULL);
+       curr_inst_list->push_back(inst);
+}
 
-               prev_inst->add_succ(curr_inst);
-               curr_inst->add_pred(prev_inst);
+/* return the FuncNode given its func_id  */
+FuncNode * ModelHistory::get_func_node(uint32_t func_id)
+{
+       if (func_nodes.size() <= func_id)       // this node has not been added
+               return NULL;
 
-               it++;
-       }
+       return func_nodes[func_id];
 }
 
 void ModelHistory::print()
 {
-       for (uint32_t i = 0;i < func_atomics.size();i++ ) {
-               FuncNode * funcNode = func_atomics[i];
-               if (funcNode == NULL)
-                       continue;
+       /* function id starts with 1 */
+       for (uint32_t i = 1; i < func_nodes.size(); i++) {
+               FuncNode * func_node = func_nodes[i];
 
-               func_inst_list_mt * entry_insts = funcNode->get_entry_insts();
+               func_inst_list_mt * entry_insts = func_node->get_entry_insts();
+               model_print("function %s has entry actions\n", func_node->get_func_name());
 
-               model_print("function %s has entry actions\n", funcNode->get_func_name());
                func_inst_list_mt::iterator it;
                for (it = entry_insts->begin();it != entry_insts->end();it++) {
                        FuncInst *inst = *it;
index 92f451519bb93e18d1b41fbfd248ce6efbefe77c..d6d090baa741e83cb1d9fe0f49580c70ac7fc1b9 100644 (file)
--- a/history.h
+++ b/history.h
@@ -14,14 +14,14 @@ public:
        uint32_t get_func_counter() { return func_counter; }
        void incr_func_counter() { func_counter++; }
 
-       void add_func_atomic(ModelAction *act, thread_id_t tid);
+       void process_action(ModelAction *act, thread_id_t tid);
 
        HashTable<const char *, uint32_t, uintptr_t, 4, model_malloc, model_calloc, model_free> * getFuncMap() { return &func_map; }
        ModelVector<const char *> * getFuncMapRev() { return &func_map_rev; }
 
-       ModelVector<FuncNode *> * getFuncAtomics() { return &func_atomics; }
+       ModelVector<FuncNode *> * getFuncNodes() { return &func_nodes; }
+       FuncNode * get_func_node(uint32_t func_id);
 
-       void link_insts(func_inst_list_t * inst_list);
        void print();
 
        MEMALLOC
@@ -33,5 +33,5 @@ private:
        /* map integer ids to function names */
        ModelVector<const char *> func_map_rev;
 
-       ModelVector<FuncNode *> func_atomics;
+       ModelVector<FuncNode *> func_nodes;
 };
index 6b180a9f94a30cfdcf535fb8b53e0f422c376ca9..b491c38e0d17ae8dd9abe3d7641806584e556e42 100644 (file)
@@ -31,6 +31,17 @@ void model_rmwc_action_helper(void *obj, int atomic_index, const char *position)
 // void model_fence_action_helper(int atomic_index);
 
 /* the following functions are used by llvm pass */
+// cds volatile loads
+uint8_t cds_volatile_load8(void * obj, int atomic_index, const char * position);
+uint16_t cds_volatile_load16(void * obj, int atomic_index, const char * position);
+uint32_t cds_volatile_load32(void * obj, int atomic_index, const char * position);
+uint64_t cds_volatile_load64(void * obj, int atomic_index, const char * position);
+
+// cds volatile stores
+void cds_volatile_store8(void * obj, uint8_t val, int atomic_index, const char * position);
+void cds_volatile_store16(void * obj, uint16_t val, int atomic_index, const char * position);
+void cds_volatile_store32(void * obj, uint32_t val, int atomic_index, const char * position);
+void cds_volatile_store64(void * obj, uint64_t val, int atomic_index, const char * position);
 
 void cds_atomic_init8(void * obj, uint8_t val, const char * position);
 void cds_atomic_init16(void * obj, uint16_t val, const char * position);
index 2117b5eb75fffbdf133267902390006839523ca9..2e617a90c5d75b044a88d26f239b819cd8114061 100644 (file)
@@ -14,7 +14,8 @@ namespace std {
 
 typedef enum memory_order {
        memory_order_relaxed, memory_order_consume, memory_order_acquire,
-       memory_order_release, memory_order_acq_rel, memory_order_seq_cst
+       memory_order_release, memory_order_acq_rel, memory_order_seq_cst,
+       volatile_order
 } memory_order;
 
 #ifdef __cplusplus
index cffd8c2d1cb93b90ff43f8e56890af13167336e0..20cddb9cf64da03d7c5742c05bf5a5e0b0734aaa 100644 (file)
@@ -44,7 +44,6 @@ int pthread_attr_setscope(pthread_attr_t *, int);
 int pthread_attr_setstackaddr(pthread_attr_t *, void *);
 int pthread_attr_setstacksize(pthread_attr_t *, size_t);
 int pthread_cancel(pthread_t);
-int pthread_cond_broadcast(pthread_cond_t *);
 int pthread_cond_destroy(pthread_cond_t *);
 int pthread_condattr_destroy(pthread_condattr_t *);
 int pthread_condattr_getpshared(const pthread_condattr_t *, int *);
index 4eafe4fbb321415169bf098d95ba44621de21851..17cba12a4e999986c775ac9fba8ff605913e8aa2 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -139,6 +139,28 @@ bool ModelChecker::assert_bug(const char *msg, ...)
        return execution->assert_bug(str);
 }
 
+/**
+ * @brief Assert a data race in the executing program.
+ *
+ * Different from assert_bug, the program will not be aborted immediately
+ * upon calling this function, unless the number of data races exceeds
+ * a threshold.
+ *
+ * @param msg Descriptive message for the bug (do not include newline char)
+ * @return True if bug is immediately-feasible
+ */
+bool ModelChecker::assert_race(const char *msg, ...)
+{
+       char str[800];
+
+       va_list ap;
+       va_start(ap, msg);
+       vsnprintf(str, sizeof(str), msg, ap);
+       va_end(ap);
+
+       return execution->assert_race(str);
+}
+
 /**
  * @brief Assert a bug in the executing program, asserted by a user thread
  * @see ModelChecker::assert_bug
@@ -358,7 +380,7 @@ bool ModelChecker::should_terminate_execution()
        /* Infeasible -> don't take any more steps */
        if (execution->is_infeasible())
                return true;
-       else if (execution->isfeasibleprefix() && execution->have_bug_reports()) {
+       else if (execution->isfeasibleprefix() && execution->have_fatal_bug_reports()) {
                execution->set_assert();
                return true;
        }
diff --git a/model.h b/model.h
index be9c86afca6d973b0bec4280654fb6c819268489..a37bd49d5e0deb818cdfa833336140554fa984a8 100644 (file)
--- a/model.h
+++ b/model.h
@@ -59,6 +59,8 @@ public:
        uint64_t switch_to_master(ModelAction *act);
 
        bool assert_bug(const char *msg, ...);
+       bool assert_race(const char *msg, ...);
+
        void assert_user_bug(const char *msg);
 
        model_params params;
index 276e37587e43de82e2ff8f84ca30aca3dc4cb7d9..95fa57a24515aaa69587eb08ea87d1a6a6849d09 100644 (file)
@@ -202,3 +202,15 @@ int pthread_cond_signal(pthread_cond_t *p_cond) {
        v->notify_one();
        return 0;
 }
+
+int pthread_cond_broadcast(pthread_cond_t *p_cond) {
+       // notify all blocked threads
+       ModelExecution *execution = model->get_execution();
+       if ( !execution->getCondMap()->contains(p_cond) )
+               pthread_cond_init(p_cond, NULL);
+
+       cdsc::snapcondition_variable *v = execution->getCondMap()->get(p_cond);
+
+       v->notify_all();
+       return 0;
+}