From 620ae95ce4fed006d18a41b6ccfd949d7e77f677 Mon Sep 17 00:00:00 2001
From: Brian Norris <banorris@uci.edu>
Date: Tue, 2 Oct 2012 17:28:02 -0700
Subject: [PATCH] model: unify JOIN- and LOCK-related sleep/wake code

We might as well use similar code paths for JOIN and LOCK operations
that must wait on another thread to re-enable it. The side benefit here
is that the JOIN action is now placed at the correct sequence point in
the execution trace.
---
 model.cc | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/model.cc b/model.cc
index 2c5ad5a..ce9e066 100644
--- a/model.cc
+++ b/model.cc
@@ -484,26 +484,17 @@ bool ModelChecker::process_thread_action(ModelAction *curr)
 		break;
 	}
 	case THREAD_JOIN: {
-		Thread *waiting, *blocking;
-		waiting = get_thread(curr);
-		blocking = (Thread *)curr->get_location();
-		if (!blocking->is_complete()) {
-			blocking->push_wait_list(curr);
-			scheduler->sleep(waiting);
-		} else {
-			do_complete_join(curr);
-			synchronized = true;
-		}
+		Thread *blocking = (Thread *)curr->get_location();
+		ModelAction *act = get_last_action(blocking->get_id());
+		curr->synchronize_with(act);
+		synchronized = true;
 		break;
 	}
 	case THREAD_FINISH: {
 		Thread *th = get_thread(curr);
 		while (!th->wait_list_empty()) {
 			ModelAction *act = th->pop_wait_list();
-			Thread *wake = get_thread(act);
-			scheduler->wake(wake);
-			do_complete_join(act);
-			synchronized = true;
+			scheduler->wake(get_thread(act));
 		}
 		th->complete();
 		break;
@@ -573,9 +564,12 @@ ModelAction * ModelChecker::initialize_curr_action(ModelAction *curr)
 }
 
 /**
- * This method checks whether a model action is enabled at the given point.
- * At this point, it checks whether a lock operation would be successful at this point.
- * If not, it puts the thread in a waiter list.
+ * @brief Check whether a model action is enabled.
+ *
+ * Checks whether a lock or join operation would be successful (i.e., is the
+ * lock already locked, or is the joined thread already complete). If not, put
+ * the action in a waiter list.
+ *
  * @param curr is the ModelAction to check whether it is enabled.
  * @return a bool that indicates whether the action is enabled.
  */
@@ -588,6 +582,12 @@ bool ModelChecker::check_action_enabled(ModelAction *curr) {
 			lock_waiters_map->get_safe_ptr(curr->get_location())->push_back(curr);
 			return false;
 		}
+	} else if (curr->get_type() == THREAD_JOIN) {
+		Thread *blocking = (Thread *)curr->get_location();
+		if (!blocking->is_complete()) {
+			blocking->push_wait_list(curr);
+			return false;
+		}
 	}
 
 	return true;
@@ -613,7 +613,7 @@ Thread * ModelChecker::check_current_action(ModelAction *curr)
 
 	if (!check_action_enabled(curr)) {
 		/* Make the execution look like we chose to run this action
-		 * much later, when a lock is actually available to release */
+		 * much later, when a lock/join can succeed */
 		get_current_thread()->set_pending(curr);
 		scheduler->sleep(get_current_thread());
 		return get_next_thread(NULL);
-- 
2.34.1