/** @brief Destructor */
ModelChecker::~ModelChecker()
{
- for (int i = 0; i < get_num_threads(); i++)
+ for (unsigned int i = 0; i < get_num_threads(); i++)
delete thread_map->get(i);
delete thread_map;
}
/** @return the number of user threads created during this execution */
-int ModelChecker::get_num_threads()
+unsigned int ModelChecker::get_num_threads()
{
return priv->next_thread_id;
}
curr->read_from(reads_from);
mo_graph->commitChanges();
+ mo_check_promises(curr->get_tid(), reads_from);
+
updated |= r_status;
} else if (!second_part_of_rmw) {
/* Read from future value */
}
mo_graph->commitChanges();
+ mo_check_promises(curr->get_tid(), curr);
+
get_thread(curr)->set_return_value(VALUE_NONE);
return updated_mod_order || updated_promises;
}
break;
}
case THREAD_START: {
- check_promises(NULL, curr->get_cv());
+ check_promises(curr->get_tid(), NULL, curr->get_cv());
break;
}
default:
void ModelChecker::get_release_seq_heads(ModelAction *act, rel_heads_list_t *release_heads)
{
const ModelAction *rf = act->get_reads_from();
- bool complete;
- complete = release_seq_heads(rf, release_heads);
- if (!complete) {
+
+ if (!release_seq_heads(rf, release_heads)) {
/* add act to 'lazy checking' list */
pending_acq_rel_seq->push_back(act);
}
bool ModelChecker::resolve_promises(ModelAction *write)
{
bool resolved = false;
+ std::vector<thread_id_t> threads_to_check;
for (unsigned int i = 0, promise_index = 0; promise_index < promises->size(); i++) {
Promise *promise = (*promises)[promise_index];
post_r_modification_order(read, write);
//Make sure the promise's value matches the write's value
ASSERT(promise->get_value() == write->get_value());
-
delete(promise);
+
promises->erase(promises->begin() + promise_index);
+ threads_to_check.push_back(read->get_tid());
+
resolved = true;
} else
promise_index++;
}
+ for(unsigned int i=0;i<threads_to_check.size();i++)
+ mo_check_promises(threads_to_check[i], write);
+
return resolved;
}
}
/** Checks promises in response to change in ClockVector Threads. */
-void ModelChecker::check_promises(ClockVector *old_cv, ClockVector *merge_cv)
+void ModelChecker::check_promises(thread_id_t tid, ClockVector *old_cv, ClockVector *merge_cv)
{
for (unsigned int i = 0; i < promises->size(); i++) {
Promise *promise = (*promises)[i];
const ModelAction *act = promise->get_action();
if ((old_cv == NULL || !old_cv->synchronized_since(act)) &&
merge_cv->synchronized_since(act)) {
- //This thread is no longer able to send values back to satisfy the promise
- int num_synchronized_threads = promise->increment_threads();
- if (num_synchronized_threads == get_num_threads()) {
+ if (promise->increment_threads(tid)) {
//Promise has failed
failed_promise = true;
return;
}
}
+/** Checks promises in response to change in ClockVector Threads. */
+void ModelChecker::mo_check_promises(thread_id_t tid, const ModelAction *write) {
+ void * location = write->get_location();
+ for (unsigned int i = 0; i < promises->size(); i++) {
+ Promise *promise = (*promises)[i];
+ const ModelAction *act = promise->get_action();
+
+ //Is this promise on the same location?
+ if ( act->get_location() != location )
+ continue;
+
+ if ( act->get_tid()==tid) {
+ if (promise->get_write() == NULL ) {
+ promise->set_write(write);
+ }
+ if (mo_graph->checkPromise(write, promise)) {
+ failed_promise = true;
+ return;
+ }
+ }
+
+ //Don't do any lookups twice for the same thread
+ if (promise->has_sync_thread(tid))
+ continue;
+
+ if (mo_graph->checkReachable(promise->get_write(), write)) {
+ if (promise->increment_threads(tid)) {
+ failed_promise = true;
+ return;
+ }
+ }
+ }
+}
+
/**
* Build up an initial set of all past writes that this 'read' action may read
* from. This set is determined by the clock vector's "happens before"