break;
}
case THREAD_JOIN: {
- Thread *blocking = (Thread *)curr->get_location();
- ModelAction *act = get_last_action(blocking->get_id());
- curr->synchronize_with(act);
- updated = true; /* trigger rel-seq checks */
+ 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);
+ updated = true; /* trigger rel-seq checks */
+ }
break;
}
case THREAD_FINISH: {
Thread *th = get_thread(curr);
while (!th->wait_list_empty()) {
ModelAction *act = th->pop_wait_list();
- scheduler->wake(get_thread(act));
+ Thread *wake = get_thread(act);
+ scheduler->wake(wake);
+ do_complete_join(act);
+ updated = true; /* trigger rel-seq checks */
}
th->complete();
updated = true; /* trigger rel-seq checks */
}
/**
- * @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.
- *
+ * 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.
* @param curr is the ModelAction to check whether it is enabled.
* @return a bool that indicates whether the action is enabled.
*/
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;
if (!check_action_enabled(curr)) {
/* Make the execution look like we chose to run this action
- * much later, when a lock/join can succeed */
+ * much later, when a lock is actually available to release */
get_current_thread()->set_pending(curr);
scheduler->sleep(get_current_thread());
return get_next_thread(NULL);
return get_next_thread(curr);
}
+/**
+ * Complete a THREAD_JOIN operation, by synchronizing with the THREAD_FINISH
+ * operation from the Thread it is joining with. Must be called after the
+ * completion of the Thread in question.
+ * @param join The THREAD_JOIN action
+ */
+void ModelChecker::do_complete_join(ModelAction *join)
+{
+ Thread *blocking = (Thread *)join->get_location();
+ ModelAction *act = get_last_action(blocking->get_id());
+ join->synchronize_with(act);
+}
+
void ModelChecker::check_curr_backtracking(ModelAction * curr) {
Node *currnode = curr->get_node();
Node *parnode = currnode->get_parent();