common: make model_print() use OS file descriptor, not C library FILE*
[c11tester.git] / model.cc
index e6f9afd9c6fd1d2b904e3ea4e23777198b71561f..f385e560f085cc9af3aec101207f732a7a3ef8e3 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -83,7 +83,6 @@ ModelChecker::ModelChecker(struct model_params params) :
        action_trace(new action_list_t()),
        thread_map(new HashTable<int, Thread *, int>()),
        obj_map(new HashTable<const void *, action_list_t *, uintptr_t, 4>()),
-       lock_waiters_map(new HashTable<const void *, action_list_t *, uintptr_t, 4>()),
        condvar_waiters_map(new HashTable<const void *, action_list_t *, uintptr_t, 4>()),
        obj_thrd_map(new HashTable<void *, SnapVector<action_list_t> *, uintptr_t, 4 >()),
        promises(new SnapVector<Promise *>()),
@@ -109,7 +108,6 @@ ModelChecker::~ModelChecker()
 
        delete obj_thrd_map;
        delete obj_map;
-       delete lock_waiters_map;
        delete condvar_waiters_map;
        delete action_trace;
 
@@ -156,9 +154,6 @@ void ModelChecker::reset_to_initial_state()
        DEBUG("+++ Resetting to initial state +++\n");
        node_stack->reset_execution();
 
-       /* Print all model-checker output before rollback */
-       fflush(model_out);
-
        /**
         * FIXME: if we utilize partial rollback, we will need to free only
         * those pending actions which were NOT pending before the rollback
@@ -288,7 +283,7 @@ Thread * ModelChecker::get_next_thread()
        }
        DEBUG("*** ModelChecker chose next thread = %d ***\n", id_to_int(tid));
        ASSERT(tid != THREAD_ID_T_NONE);
-       return thread_map->get(id_to_int(tid));
+       return get_thread(id_to_int(tid));
 }
 
 /**
@@ -757,6 +752,7 @@ void ModelChecker::set_backtracking(ModelAction *act)
 
        Node *node = prev->get_node()->get_parent();
 
+       /* See Dynamic Partial Order Reduction (addendum), POPL '05 */
        int low_tid, high_tid;
        if (node->enabled_status(t->get_id()) == THREAD_ENABLED) {
                low_tid = id_to_int(act->get_tid());
@@ -773,6 +769,7 @@ void ModelChecker::set_backtracking(ModelAction *act)
                if (i >= node->get_num_threads())
                        break;
 
+               /* See Dynamic Partial Order Reduction (addendum), POPL '05 */
                /* Don't backtrack into a point where the thread is disabled or sleeping. */
                if (node->enabled_status(tid) != THREAD_ENABLED)
                        continue;
@@ -968,32 +965,26 @@ bool ModelChecker::process_mutex(ModelAction *curr)
                }
                break;
        }
+       case ATOMIC_WAIT:
        case ATOMIC_UNLOCK: {
-               //unlock the lock
-               state->locked = NULL;
-               //wake up the other threads
-               action_list_t *waiters = get_safe_ptr_action(lock_waiters_map, curr->get_location());
-               //activate all the waiting threads
-               for (action_list_t::iterator rit = waiters->begin(); rit != waiters->end(); rit++) {
-                       scheduler->wake(get_thread(*rit));
+               /* wake up the other threads */
+               for (unsigned int i = 0; i < get_num_threads(); i++) {
+                       Thread *t = get_thread(int_to_id(i));
+                       Thread *curr_thrd = get_thread(curr);
+                       if (t->waiting_on() == curr_thrd && t->get_pending()->is_lock())
+                               scheduler->wake(t);
                }
-               waiters->clear();
-               break;
-       }
-       case ATOMIC_WAIT: {
-               //unlock the lock
+
+               /* unlock the lock - after checking who was waiting on it */
                state->locked = NULL;
-               //wake up the other threads
-               action_list_t *waiters = get_safe_ptr_action(lock_waiters_map, (void *) curr->get_value());
-               //activate all the waiting threads
-               for (action_list_t::iterator rit = waiters->begin(); rit != waiters->end(); rit++) {
-                       scheduler->wake(get_thread(*rit));
-               }
-               waiters->clear();
-               //check whether we should go to sleep or not...simulate spurious failures
+
+               if (!curr->is_wait())
+                       break; /* The rest is only for ATOMIC_WAIT */
+
+               /* Should we go to sleep? (simulate spurious failures) */
                if (curr->get_node()->get_misc() == 0) {
                        get_safe_ptr_action(condvar_waiters_map, curr->get_location())->push_back(curr);
-                       //disable us
+                       /* disable us */
                        scheduler->sleep(get_thread(curr));
                }
                break;
@@ -1227,9 +1218,12 @@ bool ModelChecker::process_thread_action(ModelAction *curr)
        }
        case THREAD_FINISH: {
                Thread *th = get_thread(curr);
-               while (!th->wait_list_empty()) {
-                       ModelAction *act = th->pop_wait_list();
-                       scheduler->wake(get_thread(act));
+               /* Wake up any joining threads */
+               for (unsigned int i = 0; i < get_num_threads(); i++) {
+                       Thread *waiting = get_thread(int_to_id(i));
+                       if (waiting->waiting_on() == th &&
+                                       waiting->get_pending()->is_thread_join())
+                               scheduler->wake(waiting);
                }
                th->complete();
                /* Completed thread can't satisfy promises */
@@ -1465,17 +1459,13 @@ void ModelChecker::thread_blocking_check_promises(Thread *blocker, Thread *waiti
  */
 bool ModelChecker::check_action_enabled(ModelAction *curr) {
        if (curr->is_lock()) {
-               std::mutex *lock = (std::mutex *)curr->get_location();
+               std::mutex *lock = curr->get_mutex();
                struct std::mutex_state *state = lock->get_state();
-               if (state->locked) {
-                       //Stick the action in the appropriate waiting queue
-                       get_safe_ptr_action(lock_waiters_map, curr->get_location())->push_back(curr);
+               if (state->locked)
                        return false;
-               }
        } else if (curr->is_thread_join()) {
-               Thread *blocking = (Thread *)curr->get_location();
+               Thread *blocking = curr->get_thread_operand();
                if (!blocking->is_complete()) {
-                       blocking->push_wait_list(curr);
                        thread_blocking_check_promises(blocking, get_thread(curr));
                        return false;
                }