X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=model.cc;h=7df70eebbe271c88486a4c85e4289217f1a40e4b;hb=262fab229626c8504297467fc7b5a04f60b7c530;hp=d2a2c744bea23c0462db61861a6be583f2d50cef;hpb=e6789461057e3395ba78575b85c114b553f4ed19;p=model-checker.git diff --git a/model.cc b/model.cc index d2a2c74..7df70ee 100644 --- a/model.cc +++ b/model.cc @@ -61,7 +61,7 @@ struct model_snapshot_members { unsigned int next_thread_id; modelclock_t used_sequence_numbers; ModelAction *next_backtrack; - std::vector< bug_message *, SnapshotAlloc > bugs; + SnapVector bugs; struct execution_stats stats; bool failed_promise; bool too_many_reads; @@ -85,12 +85,12 @@ ModelChecker::ModelChecker(struct model_params params) : obj_map(new HashTable()), lock_waiters_map(new HashTable()), condvar_waiters_map(new HashTable()), - obj_thrd_map(new HashTable *, uintptr_t, 4 >()), - promises(new std::vector< Promise *, SnapshotAlloc >()), - futurevalues(new std::vector< struct PendingFutureValue, SnapshotAlloc >()), - pending_rel_seqs(new std::vector< struct release_seq *, SnapshotAlloc >()), - thrd_last_action(new std::vector< ModelAction *, SnapshotAlloc >(1)), - thrd_last_fence_release(new std::vector< ModelAction *, SnapshotAlloc >()), + obj_thrd_map(new HashTable *, uintptr_t, 4 >()), + promises(new SnapVector()), + futurevalues(new SnapVector()), + pending_rel_seqs(new SnapVector()), + thrd_last_action(new SnapVector(1)), + thrd_last_fence_release(new SnapVector()), node_stack(new NodeStack()), priv(new struct model_snapshot_members()), mo_graph(new CycleGraph()) @@ -137,11 +137,11 @@ static action_list_t * get_safe_ptr_action(HashTable * get_safe_ptr_vect_action(HashTable *, uintptr_t, 4> * hash, void * ptr) +static SnapVector * get_safe_ptr_vect_action(HashTable *, uintptr_t, 4> * hash, void * ptr) { - std::vector *tmp = hash->get(ptr); + SnapVector *tmp = hash->get(ptr); if (tmp == NULL) { - tmp = new std::vector(); + tmp = new SnapVector(); hash->put(ptr, tmp); } return tmp; @@ -642,8 +642,8 @@ ModelAction * ModelChecker::get_last_fence_conflict(ModelAction *act) const * load-acquire * or * load --sb-> fence-acquire */ - std::vector< ModelAction *, ModelAlloc > acquire_fences(get_num_threads(), NULL); - std::vector< ModelAction *, ModelAlloc > prior_loads(get_num_threads(), NULL); + ModelVector acquire_fences(get_num_threads(), NULL); + ModelVector prior_loads(get_num_threads(), NULL); bool found_acquire_fences = false; for ( ; rit != list->rend(); rit++) { ModelAction *prev = *rit; @@ -1051,25 +1051,66 @@ bool ModelChecker::process_mutex(ModelAction *curr) return false; } +/** + * @brief Check if the current pending promises allow a future value to be sent + * + * If one of the following is true: + * (a) there are no pending promises + * (b) the reader and writer do not cross any promises + * Then, it is safe to pass a future value back now. + * + * Otherwise, we must save the pending future value until (a) or (b) is true + * + * @param writer The operation which sends the future value. Must be a write. + * @param reader The operation which will observe the value. Must be a read. + * @return True if the future value can be sent now; false if it must wait. + */ +bool ModelChecker::promises_may_allow(const ModelAction *writer, + const ModelAction *reader) const +{ + if (promises->empty()) + return true; + for(int i=promises->size()-1;i>=0;i--) { + ModelAction *pr=(*promises)[i]->get_reader(0); + //reader is after promise...doesn't cross any promise + if (*reader > *pr) + return true; + //writer is after promise, reader before...bad... + if (*writer > *pr) + return false; + } + return true; +} + +/** + * @brief Add a future value to a reader + * + * This function performs a few additional checks to ensure that the future + * value can be feasibly observed by the reader + * + * @param writer The operation whose value is sent. Must be a write. + * @param reader The read operation which may read the future value. Must be a read. + */ void ModelChecker::add_future_value(const ModelAction *writer, ModelAction *reader) { /* Do more ambitious checks now that mo is more complete */ - if (mo_may_allow(writer, reader)) { - Node *node = reader->get_node(); - - /* Find an ancestor thread which exists at the time of the reader */ - Thread *write_thread = get_thread(writer); - while (id_to_int(write_thread->get_id()) >= node->get_num_threads()) - write_thread = write_thread->get_parent(); - - struct future_value fv = { - writer->get_write_value(), - writer->get_seq_number() + params.maxfuturedelay, - write_thread->get_id(), - }; - if (node->add_future_value(fv)) - set_latest_backtrack(reader); - } + if (!mo_may_allow(writer, reader)) + return; + + Node *node = reader->get_node(); + + /* Find an ancestor thread which exists at the time of the reader */ + Thread *write_thread = get_thread(writer); + while (id_to_int(write_thread->get_id()) >= node->get_num_threads()) + write_thread = write_thread->get_parent(); + + struct future_value fv = { + writer->get_write_value(), + writer->get_seq_number() + params.maxfuturedelay, + write_thread->get_id(), + }; + if (node->add_future_value(fv)) + set_latest_backtrack(reader); } /** @@ -1080,32 +1121,41 @@ void ModelChecker::add_future_value(const ModelAction *writer, ModelAction *read bool ModelChecker::process_write(ModelAction *curr) { /* Readers to which we may send our future value */ - std::vector< ModelAction *, ModelAlloc > send_fv; + ModelVector send_fv; - bool updated_mod_order = w_modification_order(curr, &send_fv); - int promise_idx = get_promise_to_resolve(curr); const ModelAction *earliest_promise_reader; bool updated_promises = false; - if (promise_idx >= 0) { - earliest_promise_reader = (*promises)[promise_idx]->get_reader(0); - updated_promises = resolve_promise(curr, promise_idx); + bool updated_mod_order = w_modification_order(curr, &send_fv); + Promise *promise = pop_promise_to_resolve(curr); + + if (promise) { + earliest_promise_reader = promise->get_reader(0); + updated_promises = resolve_promise(curr, promise); } else earliest_promise_reader = NULL; - /* Don't send future values to reads after the Promise we resolve */ for (unsigned int i = 0; i < send_fv.size(); i++) { ModelAction *read = send_fv[i]; - if (!earliest_promise_reader || *read < *earliest_promise_reader) - futurevalues->push_back(PendingFutureValue(curr, read)); + + /* Don't send future values to reads after the Promise we resolve */ + if (!earliest_promise_reader || *read < *earliest_promise_reader) { + /* Check if future value can be sent immediately */ + if (promises_may_allow(curr, read)) { + add_future_value(curr, read); + } else { + futurevalues->push_back(PendingFutureValue(curr, read)); + } + } } - if (promises->size() == 0) { - for (unsigned int i = 0; i < futurevalues->size(); i++) { - struct PendingFutureValue pfv = (*futurevalues)[i]; - add_future_value(pfv.writer, pfv.act); + /* Check the pending future values */ + for (int i = (int)futurevalues->size() - 1; i >= 0; i--) { + struct PendingFutureValue pfv = (*futurevalues)[i]; + if (promises_may_allow(pfv.writer, pfv.reader)) { + add_future_value(pfv.writer, pfv.reader); + futurevalues->erase(futurevalues->begin() + i); } - futurevalues->clear(); } mo_graph->commitChanges(); @@ -1128,6 +1178,7 @@ bool ModelChecker::process_fence(ModelAction *curr) * use in later synchronization * fence-acquire (this function): search for hypothetical release * sequences + * fence-seq-cst: MO constraints formed in {r,w}_modification_order */ bool updated = false; if (curr->is_acquire()) { @@ -1704,7 +1755,7 @@ bool ModelChecker::should_read_instead(const ModelAction *curr, const T *rf, con if (!mo_graph->checkReachable(rf, other_rf)) return false; - std::vector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); + SnapVector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); action_list_t *list = &(*thrd_lists)[id_to_int(curr->get_tid())]; action_list_t::reverse_iterator rit = list->rbegin(); ASSERT((*rit) == curr); @@ -1747,7 +1798,7 @@ bool ModelChecker::check_recency(ModelAction *curr, const T *rf) const curr->get_node()->get_read_from_promise_size() <= 1) return true; - std::vector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); + SnapVector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); int tid = id_to_int(curr->get_tid()); ASSERT(tid < (int)thrd_lists->size()); action_list_t *list = &(*thrd_lists)[tid]; @@ -1805,13 +1856,16 @@ bool ModelChecker::check_recency(ModelAction *curr, const T *rf) const template bool ModelChecker::r_modification_order(ModelAction *curr, const rf_type *rf) { - std::vector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); + SnapVector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); unsigned int i; bool added = false; ASSERT(curr->is_read()); /* Last SC fence in the current thread */ ModelAction *last_sc_fence_local = get_last_seq_cst_fence(curr->get_tid(), NULL); + ModelAction *last_sc_write = NULL; + if (curr->is_seqcst()) + last_sc_write = get_last_seq_cst_write(curr); /* Iterate over all threads */ for (i = 0; i < thrd_lists->size(); i++) { @@ -1831,7 +1885,18 @@ bool ModelChecker::r_modification_order(ModelAction *curr, const rf_type *rf) for (rit = list->rbegin(); rit != list->rend(); rit++) { ModelAction *act = *rit; - if (act->is_write() && !act->equals(rf) && act != curr) { + /* Skip curr */ + if (act == curr) + continue; + /* Don't want to add reflexive edges on 'rf' */ + if (act->equals(rf)) { + if (act->happens_before(curr)) + break; + else + continue; + } + + if (act->is_write()) { /* C++, Section 29.3 statement 5 */ if (curr->is_seqcst() && last_sc_fence_thread_local && *act < *last_sc_fence_thread_local) { @@ -1852,15 +1917,19 @@ bool ModelChecker::r_modification_order(ModelAction *curr, const rf_type *rf) } } + /* C++, Section 29.3 statement 3 (second subpoint) */ + if (curr->is_seqcst() && last_sc_write && act == last_sc_write) { + added = mo_graph->addEdge(act, rf) || added; + break; + } + /* * Include at most one act per-thread that "happens - * before" curr. Don't consider reflexively. + * before" curr */ - if (act->happens_before(curr) && act != curr) { + if (act->happens_before(curr)) { if (act->is_write()) { - if (!act->equals(rf)) { - added = mo_graph->addEdge(act, rf) || added; - } + added = mo_graph->addEdge(act, rf) || added; } else { const ModelAction *prevrf = act->get_reads_from(); const Promise *prevrf_promise = act->get_reads_from_promise(); @@ -1911,9 +1980,9 @@ bool ModelChecker::r_modification_order(ModelAction *curr, const rf_type *rf) * value. If NULL, then don't record any future values. * @return True if modification order edges were added; false otherwise */ -bool ModelChecker::w_modification_order(ModelAction *curr, std::vector< ModelAction *, ModelAlloc > *send_fv) +bool ModelChecker::w_modification_order(ModelAction *curr, ModelVector *send_fv) { - std::vector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); + SnapVector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); unsigned int i; bool added = false; ASSERT(curr->is_write()); @@ -2029,7 +2098,7 @@ bool ModelChecker::w_modification_order(ModelAction *curr, std::vector< ModelAct /** Arbitrary reads from the future are not allowed. Section 29.3 * part 9 places some constraints. This method checks one result of constraint * constraint. Others require compiler support. */ -bool ModelChecker::thin_air_constraint_may_allow(const ModelAction *writer, const ModelAction *reader) +bool ModelChecker::thin_air_constraint_may_allow(const ModelAction *writer, const ModelAction *reader) const { if (!writer->is_rmw()) return true; @@ -2057,7 +2126,7 @@ bool ModelChecker::thin_air_constraint_may_allow(const ModelAction *writer, cons */ bool ModelChecker::mo_may_allow(const ModelAction *writer, const ModelAction *reader) { - std::vector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, reader->get_location()); + SnapVector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, reader->get_location()); unsigned int i; /* Iterate over all threads */ for (i = 0; i < thrd_lists->size(); i++) { @@ -2158,7 +2227,7 @@ bool ModelChecker::release_seq_heads(const ModelAction *rf, release_heads->push_back(fence_release); int tid = id_to_int(rf->get_tid()); - std::vector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, rf->get_location()); + SnapVector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, rf->get_location()); action_list_t *list = &(*thrd_lists)[tid]; action_list_t::const_reverse_iterator rit; @@ -2301,7 +2370,7 @@ void ModelChecker::get_release_seq_heads(ModelAction *acquire, bool ModelChecker::resolve_release_sequences(void *location, work_queue_t *work_queue) { bool updated = false; - std::vector< struct release_seq *, SnapshotAlloc >::iterator it = pending_rel_seqs->begin(); + SnapVector::iterator it = pending_rel_seqs->begin(); while (it != pending_rel_seqs->end()) { struct release_seq *pending = *it; ModelAction *acquire = pending->acquire; @@ -2382,7 +2451,7 @@ void ModelChecker::add_action_to_lists(ModelAction *act) if (uninit) action_trace->push_front(uninit); - std::vector *vec = get_safe_ptr_vect_action(obj_thrd_map, act->get_location()); + SnapVector *vec = get_safe_ptr_vect_action(obj_thrd_map, act->get_location()); if (tid >= (int)vec->size()) vec->resize(priv->next_thread_id); (*vec)[tid].push_back(act); @@ -2405,7 +2474,7 @@ void ModelChecker::add_action_to_lists(ModelAction *act) void *mutex_loc = (void *) act->get_value(); get_safe_ptr_action(obj_map, mutex_loc)->push_back(act); - std::vector *vec = get_safe_ptr_vect_action(obj_thrd_map, mutex_loc); + SnapVector *vec = get_safe_ptr_vect_action(obj_thrd_map, mutex_loc); if (tid >= (int)vec->size()) vec->resize(priv->next_thread_id); (*vec)[tid].push_back(act); @@ -2454,8 +2523,11 @@ ModelAction * ModelChecker::get_last_seq_cst_write(ModelAction *curr) const action_list_t *list = get_safe_ptr_action(obj_map, location); /* Find: max({i in dom(S) | seq_cst(t_i) && isWrite(t_i) && samevar(t_i, t)}) */ action_list_t::reverse_iterator rit; - for (rit = list->rbegin(); rit != list->rend(); rit++) - if ((*rit)->is_write() && (*rit)->is_seqcst() && (*rit) != curr) + for (rit = list->rbegin(); (*rit) != curr; rit++) + ; + rit++; /* Skip past curr */ + for ( ; rit != list->rend(); rit++) + if ((*rit)->is_write() && (*rit)->is_seqcst()) return *rit; return NULL; } @@ -2528,29 +2600,31 @@ ClockVector * ModelChecker::get_cv(thread_id_t tid) const } /** - * @brief Find the promise, if any to resolve for the current action + * @brief Find the promise (if any) to resolve for the current action and + * remove it from the pending promise vector * @param curr The current ModelAction. Should be a write. - * @return The (non-negative) index for the Promise to resolve, if any; - * otherwise -1 + * @return The Promise to resolve, if any; otherwise NULL */ -int ModelChecker::get_promise_to_resolve(const ModelAction *curr) const +Promise * ModelChecker::pop_promise_to_resolve(const ModelAction *curr) { for (unsigned int i = 0; i < promises->size(); i++) - if (curr->get_node()->get_promise(i)) - return i; - return -1; + if (curr->get_node()->get_promise(i)) { + Promise *ret = (*promises)[i]; + promises->erase(promises->begin() + i); + return ret; + } + return NULL; } /** * Resolve a Promise with a current write. * @param write The ModelAction that is fulfilling Promises - * @param promise_idx The index corresponding to the promise + * @param promise The Promise to resolve * @return True if the Promise was successfully resolved; false otherwise */ -bool ModelChecker::resolve_promise(ModelAction *write, unsigned int promise_idx) +bool ModelChecker::resolve_promise(ModelAction *write, Promise *promise) { - std::vector< ModelAction *, ModelAlloc > actions_to_check; - Promise *promise = (*promises)[promise_idx]; + ModelVector actions_to_check; for (unsigned int i = 0; i < promise->get_num_readers(); i++) { ModelAction *read = promise->get_reader(i); @@ -2562,7 +2636,6 @@ bool ModelChecker::resolve_promise(ModelAction *write, unsigned int promise_idx) if (!mo_graph->resolvePromise(promise, write)) priv->failed_promise = true; - promises->erase(promises->begin() + promise_idx); /** * @todo It is possible to end up in an inconsistent state, where a * "resolved" promise may still be referenced if @@ -2724,7 +2797,7 @@ void ModelChecker::compute_relseq_breakwrites(ModelAction *curr) */ void ModelChecker::build_may_read_from(ModelAction *curr) { - std::vector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); + SnapVector *thrd_lists = get_safe_ptr_vect_action(obj_thrd_map, curr->get_location()); unsigned int i; ASSERT(curr->is_read()); @@ -2827,7 +2900,7 @@ ModelAction * ModelChecker::get_uninitialized_action(const ModelAction *curr) co Node *node = curr->get_node(); ModelAction *act = node->get_uninit_action(); if (!act) { - act = new ModelAction(ATOMIC_UNINIT, std::memory_order_relaxed, curr->get_location(), 0, model_thread); + act = new ModelAction(ATOMIC_UNINIT, std::memory_order_relaxed, curr->get_location(), model->params.uninitvalue, model_thread); node->set_uninit_action(act); } act->create_cv(NULL); @@ -2933,15 +3006,6 @@ void ModelChecker::add_thread(Thread *t) scheduler->add_thread(t); } -/** - * Removes a thread from the scheduler. - * @param the thread to remove. - */ -void ModelChecker::remove_thread(Thread *t) -{ - scheduler->remove_thread(t); -} - /** * @brief Get a Thread reference by its ID * @param tid The Thread's ID @@ -3030,6 +3094,7 @@ uint64_t ModelChecker::switch_to_master(ModelAction *act) { DBG(); Thread *old = thread_current(); + scheduler->set_current_thread(NULL); ASSERT(!old->get_pending()); old->set_pending(act); if (Thread::swap(old, &system_context) < 0) {