model: rename check_deadlock() to is_circular_wait()
[model-checker.git] / model.cc
index 7741760025162b786b48c903aaf86937bb4cb0f1..c713d1e1761b308cc5433dfa05345a8c23d5024a 100644 (file)
--- a/model.cc
+++ b/model.cc
@@ -400,6 +400,22 @@ bool ModelChecker::is_deadlocked() const
        return blocking_threads;
 }
 
+/**
+ * Check if a Thread has entered a circular wait deadlock situation. This will
+ * not check other threads for potential deadlock situations, and may miss
+ * deadlocks involving WAIT.
+ *
+ * @param t The thread which may have entered a deadlock
+ * @return True if this Thread entered a deadlock; false otherwise
+ */
+bool ModelChecker::is_circular_wait(const Thread *t) const
+{
+       for (Thread *waiting = t->waiting_on() ; waiting != NULL; waiting = waiting->waiting_on())
+               if (waiting == t)
+                       return true;
+       return false;
+}
+
 /**
  * Check if this is a complete execution. That is, have all thread completed
  * execution (rather than exiting because sleep sets have forced a redundant
@@ -935,7 +951,7 @@ bool ModelChecker::process_mutex(ModelAction *curr)
 
        switch (curr->get_type()) {
        case ATOMIC_TRYLOCK: {
-               bool success = !state->islocked;
+               bool success = !state->locked;
                curr->set_try_lock(success);
                if (!success) {
                        get_thread(curr)->set_return_value(0);
@@ -947,7 +963,7 @@ bool ModelChecker::process_mutex(ModelAction *curr)
        case ATOMIC_LOCK: {
                if (curr->get_cv()->getClock(state->alloc_tid) <= state->alloc_clock)
                        assert_bug("Lock access before initialization");
-               state->islocked = true;
+               state->locked = get_thread(curr);
                ModelAction *unlock = get_last_unlock(curr);
                //synchronize with the previous unlock statement
                if (unlock != NULL) {
@@ -958,7 +974,7 @@ bool ModelChecker::process_mutex(ModelAction *curr)
        }
        case ATOMIC_UNLOCK: {
                //unlock the lock
-               state->islocked = false;
+               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
@@ -970,7 +986,7 @@ bool ModelChecker::process_mutex(ModelAction *curr)
        }
        case ATOMIC_WAIT: {
                //unlock the lock
-               state->islocked = false;
+               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
@@ -1402,7 +1418,7 @@ bool ModelChecker::check_action_enabled(ModelAction *curr) {
        if (curr->is_lock()) {
                std::mutex *lock = (std::mutex *)curr->get_location();
                struct std::mutex_state *state = lock->get_state();
-               if (state->islocked) {
+               if (state->locked) {
                        //Stick the action in the appropriate waiting queue
                        get_safe_ptr_action(lock_waiters_map, curr->get_location())->push_back(curr);
                        return false;
@@ -3036,6 +3052,8 @@ void ModelChecker::run()
                                Thread *thr = get_thread(tid);
                                if (!thr->is_model_thread() && !thr->is_complete() && !thr->get_pending()) {
                                        switch_from_master(thr);
+                                       if (is_circular_wait(thr))
+                                               assert_bug("Deadlock detected");
                                }
                        }