Fix waiter list
[c11tester.git] / execution.cc
index 8853bfeefee1a44a7a05e220999ceb057ecc385e..48c73cfbeca2db10dd19148062bded4bfd9858e7 100644 (file)
@@ -53,12 +53,15 @@ ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler) :
        scheduler(scheduler),
        thread_map(2),  /* We'll always need at least 2 threads */
        pthread_map(0),
-       pthread_counter(1),
+       pthread_counter(2),
        action_trace(),
        obj_map(),
        condvar_waiters_map(),
        obj_thrd_map(),
+       obj_wr_thrd_map(),
+       obj_last_sc_map(),
        mutex_map(),
+       cond_map(),
        thrd_last_action(1),
        thrd_last_fence_release(),
        priv(new struct model_snapshot_members ()),
@@ -73,7 +76,7 @@ ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler) :
        /* Initialize a model-checker thread, for special ModelActions */
        model_thread = new Thread(get_next_id());
        add_thread(model_thread);
-       fuzzer->register_engine(this);
+       fuzzer->register_engine(m, this);
        scheduler->register_engine(this);
 #ifdef TLS
        pthread_key_create(&pthreadkey, tlsdestructor);
@@ -373,6 +376,8 @@ bool ModelExecution::process_mutex(ModelAction *curr)
                //TODO: FIND SOME BETTER WAY TO CHECK LOCK INITIALIZED OR NOT
                //if (curr->get_cv()->getClock(state->alloc_tid) <= state->alloc_clock)
                //      assert_bug("Lock access before initialization");
+
+               // TODO: lock count for recursive mutexes
                state->locked = get_thread(curr);
                ModelAction *unlock = get_last_unlock(curr);
                //synchronize with the previous unlock statement
@@ -396,8 +401,17 @@ bool ModelExecution::process_mutex(ModelAction *curr)
                        /* unlock the lock - after checking who was waiting on it */
                        state->locked = NULL;
 
-                       /* disable this thread */
-                       get_safe_ptr_action(&condvar_waiters_map, curr->get_location())->push_back(curr);
+                       /* remove old wait action and disable this thread */
+                       action_list_t * waiters = get_safe_ptr_action(&condvar_waiters_map, curr->get_location());
+                       for (sllnode<ModelAction *> * it = waiters->begin(); it != NULL; it = it->getNext()) {
+                               ModelAction * wait = it->getVal();
+                               if (wait->get_tid() == curr->get_tid()) {
+                                       waiters->erase(it);
+                                       break;
+                               }
+                       }
+
+                       waiters->push_back(curr);
                        scheduler->sleep(get_thread(curr));
                }
 
@@ -414,6 +428,7 @@ bool ModelExecution::process_mutex(ModelAction *curr)
                //FAILS AND IN THE CASE IT DOESN'T...  TIMED WAITS
                //MUST EVENMTUALLY RELEASE...
 
+               // TODO: lock count for recursive mutexes
                /* wake up the other threads */
                for (unsigned int i = 0;i < get_num_threads();i++) {
                        Thread *t = get_thread(int_to_id(i));
@@ -688,8 +703,15 @@ bool ModelExecution::check_action_enabled(ModelAction *curr) {
        if (curr->is_lock()) {
                cdsc::mutex *lock = curr->get_mutex();
                struct cdsc::mutex_state *state = lock->get_state();
-               if (state->locked)
+               if (state->locked) {
+                       Thread *lock_owner = (Thread *)state->locked;
+                       Thread *curr_thread = get_thread(curr);
+                       if (lock_owner == curr_thread && state->type == PTHREAD_MUTEX_RECURSIVE) {
+                               return true;
+                       }
+
                        return false;
+               }
        } else if (curr->is_thread_join()) {
                Thread *blocking = curr->get_thread_operand();
                if (!blocking->is_complete()) {
@@ -1524,6 +1546,40 @@ void ModelExecution::print_summary()
 
 }
 
+void ModelExecution::print_tail()
+{
+       model_print("Execution trace %d:\n", get_execution_number());
+
+       sllnode<ModelAction*> *it;
+
+       model_print("------------------------------------------------------------------------------------\n");
+       model_print("#    t    Action type     MO       Location         Value               Rf  CV\n");
+       model_print("------------------------------------------------------------------------------------\n");
+
+       unsigned int hash = 0;
+
+       int length = 25;
+       int counter = 0;
+       SnapList<ModelAction *> list;
+       for (it = action_trace.end(); it != NULL; it = it->getPrev()) {
+               if (counter > length)
+                       break;
+
+               ModelAction * act = it->getVal();
+               list.push_front(act);
+               counter++;
+       }
+
+       for (it = list.begin();it != NULL;it=it->getNext()) {
+               const ModelAction *act = it->getVal();
+               if (act->get_seq_number() > 0)
+                       act->print();
+               hash = hash^(hash<<3)^(it->getVal()->hash());
+       }
+       model_print("HASH %u\n", hash);
+       model_print("------------------------------------------------------------------------------------\n");
+}
+
 /**
  * Add a Thread to the system for the first time. Should only be called once
  * per thread.
@@ -1568,14 +1624,21 @@ Thread * ModelExecution::get_thread(const ModelAction *act) const
  * @return A Thread reference
  */
 Thread * ModelExecution::get_pthread(pthread_t pid) {
+       // pid 1 is reserved for the main thread, pthread ids should start from 2
+       if (pid == 1)
+               return get_thread(pid);
+
        union {
                pthread_t p;
                uint32_t v;
        } x;
        x.p = pid;
        uint32_t thread_id = x.v;
-       if (thread_id < pthread_counter + 1) return pthread_map[thread_id];
-       else return NULL;
+
+       if (thread_id < pthread_counter + 1)
+               return pthread_map[thread_id];
+       else
+               return NULL;
 }
 
 /**
@@ -1612,7 +1675,7 @@ bool ModelExecution::is_enabled(thread_id_t tid) const
 Thread * ModelExecution::action_select_next_thread(const ModelAction *curr) const
 {
        /* Do not split atomic RMW */
-       if (curr->is_rmwr() && !paused_by_fuzzer(curr))
+       if (curr->is_rmwr())
                return get_thread(curr);
        /* Follow CREATE with the created thread */
        /* which is not needed, because model.cc takes care of this */
@@ -1624,15 +1687,6 @@ Thread * ModelExecution::action_select_next_thread(const ModelAction *curr) cons
        return NULL;
 }
 
-/** @param act A read atomic action */
-bool ModelExecution::paused_by_fuzzer(const ModelAction * act) const
-{
-       ASSERT(act->is_read());
-
-       // Actions paused by fuzzer have their sequence number reset to 0
-       return act->get_seq_number() == 0;
-}
-
 /**
  * Takes the next step in the execution, if possible.
  * @param curr The current step to take
@@ -1725,7 +1779,7 @@ ClockVector * ModelExecution::computeMinimalCV() {
 /** Sometimes we need to remove an action that is the most recent in the thread.  This happens if it is mo before action in other threads.  In that case we need to create a replacement latest ModelAction */
 
 void ModelExecution::fixupLastAct(ModelAction *act) {
-       ModelAction *newact = new ModelAction(ATOMIC_NOP, std::memory_order_seq_cst, get_thread(act->get_tid()));
+       ModelAction *newact = new ModelAction(ATOMIC_NOP, std::memory_order_seq_cst, NULL, VALUE_NONE, get_thread(act->get_tid()));
        newact->set_seq_number(get_next_seq_num());
        newact->create_cv(act);
        newact->set_last_fence_release(act->get_last_fence_release());
@@ -1735,6 +1789,9 @@ void ModelExecution::fixupLastAct(ModelAction *act) {
 /** Compute which actions to free.  */
 
 void ModelExecution::collectActions() {
+       if (priv->used_sequence_numbers < params->traceminsize)
+               return;
+
        //Compute minimal clock vector for all live threads
        ClockVector *cvmin = computeMinimalCV();
        SnapVector<CycleNode *> * queue = new SnapVector<CycleNode *>();
@@ -1809,6 +1866,7 @@ void ModelExecution::collectActions() {
                                        if (islastact) {
                                                fixupLastAct(act);
                                        }
+
                                        delete act;
                                        continue;
                                }
@@ -1880,6 +1938,11 @@ void ModelExecution::collectActions() {
                        modelclock_t tid_clock = cvmin->getClock(act_tid);
                        if (actseq <= tid_clock) {
                                removeAction(act);
+                               // Remove reference to act from thrd_last_fence_release
+                               int thread_id = id_to_int( act->get_tid() );
+                               if (thrd_last_fence_release[thread_id] == act) {
+                                       thrd_last_fence_release[thread_id] = NULL;
+                               }
                                delete act;
                                continue;
                        }
@@ -1905,18 +1968,17 @@ void ModelExecution::collectActions() {
                                delete act;
                                continue;
                        }
+               }
 
-                       //If we don't delete the action, we should remove references to release fences
-                       const ModelAction *rel_fence =act->get_last_fence_release();
-                       if (rel_fence != NULL) {
-                               modelclock_t relfenceseq = rel_fence->get_seq_number();
-                               thread_id_t relfence_tid = rel_fence->get_tid();
-                               modelclock_t tid_clock = cvmin->getClock(relfence_tid);
-                               //Remove references to irrelevant release fences
-                               if (relfenceseq <= tid_clock)
-                                       act->set_last_fence_release(NULL);
-                       }
-
+               //If we don't delete the action, we should remove references to release fences
+               const ModelAction *rel_fence =act->get_last_fence_release();
+               if (rel_fence != NULL) {
+                       modelclock_t relfenceseq = rel_fence->get_seq_number();
+                       thread_id_t relfence_tid = rel_fence->get_tid();
+                       modelclock_t tid_clock = cvmin->getClock(relfence_tid);
+                       //Remove references to irrelevant release fences
+                       if (relfenceseq <= tid_clock)
+                               act->set_last_fence_release(NULL);
                }
        }