X-Git-Url: http://plrg.eecs.uci.edu/git/?p=model-checker.git;a=blobdiff_plain;f=action.cc;h=be8c4a6c0cdc69bde75fd08436a33705fa9157af;hp=84c20eb5c42f0ff9b1fa4f3ef668aa6432b793d5;hb=ff3ab0abac18649da161a495781c3925cbcd62a4;hpb=0e8659aba12909cfc5785163022378519837710e diff --git a/action.cc b/action.cc index 84c20eb..be8c4a6 100644 --- a/action.cc +++ b/action.cc @@ -31,6 +31,7 @@ ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, location(loc), value(value), reads_from(NULL), + reads_from_promise(NULL), last_fence_release(NULL), node(NULL), seq_number(ACTION_INITIAL_CLOCK), @@ -238,6 +239,31 @@ void ModelAction::copy_typeandorder(ModelAction * act) this->order = act->order; } +/** + * Get the Thread which is the operand of this action. This is only valid for + * THREAD_* operations (currently only for THREAD_CREATE and THREAD_JOIN). Note + * that this provides a central place for determining the conventions of Thread + * storage in ModelAction, where we generally aren't very type-safe (e.g., we + * store object references in a (void *) address. + * + * For THREAD_CREATE, this yields the Thread which is created. + * For THREAD_JOIN, this yields the Thread we are joining with. + * + * @return The Thread which this action acts on, if exists; otherwise NULL + */ +Thread * ModelAction::get_thread_operand() const +{ + if (type == THREAD_CREATE) { + /* THREAD_CREATE stores its (Thread *) in a thrd_t::priv */ + thrd_t *thrd = (thrd_t *)get_location(); + return thrd->priv; + } else if (type == THREAD_JOIN) + /* THREAD_JOIN uses (Thread *) for location */ + return (Thread *)get_location(); + else + return NULL; +} + /** This method changes an existing read part of an RMW action into either: * (1) a full RMW action in case of the completed write or * (2) a READ action in case a failed action. @@ -276,13 +302,11 @@ bool ModelAction::could_synchronize_with(const ModelAction *act) const // Explore interleavings of seqcst writes/fences to guarantee total // order of seq_cst operations that don't commute - if ((could_be_write() || act->could_be_write() || is_fence() || act->is_fence()) - && is_seqcst() && act->is_seqcst()) + if ((could_be_write() || act->could_be_write() || is_fence() || act->is_fence()) && is_seqcst() && act->is_seqcst()) return true; - // Explore synchronizing read/write/fence pairs - if (is_acquire() && act->is_release() && (is_read() || is_fence()) && - (act->could_be_write() || act->is_fence())) + // Explore synchronizing read/write pairs + if (is_acquire() && act->is_release() && is_read() && act->could_be_write()) return true; // lock just released...we can grab lock @@ -354,6 +378,64 @@ void ModelAction::set_try_lock(bool obtainedlock) { value = VALUE_TRYFAILED; } +/** + * @brief Get the value read by this load + * + * We differentiate this function from ModelAction::get_write_value and + * ModelAction::get_value for the purpose of RMW's, which may have both a + * 'read' and a 'write' value. + * + * Note: 'this' must be a load. + * + * @return The value read by this load + */ +uint64_t ModelAction::get_reads_from_value() const +{ + ASSERT(is_read()); + if (reads_from) + return reads_from->get_write_value(); + else if (reads_from_promise) + return reads_from_promise->get_value(); + return VALUE_NONE; /* Only for new actions with no reads-from */ +} + +/** + * @brief Get the value written by this store + * + * We differentiate this function from ModelAction::get_reads_from_value and + * ModelAction::get_value for the purpose of RMW's, which may have both a + * 'read' and a 'write' value. + * + * Note: 'this' must be a store. + * + * @return The value written by this store + */ +uint64_t ModelAction::get_write_value() const +{ + ASSERT(is_write()); + return value; +} + +/** + * @brief Get the value returned by this action + * + * For atomic reads (including RMW), an operation returns the value it read. + * For atomic writes, an operation returns the value it wrote. For other + * operations, the return value varies (sometimes is a "don't care"), but the + * value is simply stored in the "value" field. + * + * @return This action's return value + */ +uint64_t ModelAction::get_return_value() const +{ + if (is_read()) + return get_reads_from_value(); + else if (is_write()) + return get_write_value(); + else + return value; +} + /** @return The Node associated with this ModelAction */ Node * ModelAction::get_node() const { @@ -368,11 +450,24 @@ Node * ModelAction::get_node() const */ void ModelAction::set_read_from(const ModelAction *act) { + ASSERT(act); reads_from = act; - if (act && act->is_uninitialized()) + reads_from_promise = NULL; + if (act->is_uninitialized()) model->assert_bug("May read from uninitialized atomic\n"); } +/** + * Set this action's read-from promise + * @param promise The promise to read from + */ +void ModelAction::set_read_from_promise(Promise *promise) +{ + ASSERT(is_read()); + reads_from_promise = promise; + reads_from = NULL; +} + /** * Synchronize the current thread with the thread corresponding to the * ModelAction parameter. @@ -473,12 +568,6 @@ void ModelAction::print() const type_str = "unknown type"; } - uint64_t valuetoprint; - if (type == ATOMIC_READ && reads_from != NULL) - valuetoprint = reads_from->value; - else - valuetoprint = value; - switch (this->order) { case std::memory_order_relaxed: mo_str = "relaxed"; @@ -501,11 +590,17 @@ void ModelAction::print() const } model_print("(%4d) Thread: %-2d Action: %-13s MO: %7s Loc: %14p Value: %-#18" PRIx64, - seq_number, id_to_int(tid), type_str, mo_str, location, valuetoprint); + seq_number, id_to_int(tid), type_str, mo_str, location, get_return_value()); if (is_read()) { if (reads_from) model_print(" Rf: %-3d", reads_from->get_seq_number()); - else + else if (reads_from_promise) { + int idx = model->get_promise_number(reads_from_promise); + if (idx >= 0) + model_print(" Rf: P%-2d", idx); + else + model_print(" RF: P? "); + } else model_print(" Rf: ? "); } if (cv) { @@ -518,7 +613,7 @@ void ModelAction::print() const model_print("\n"); } -/** @brief Print nicely-formatted info about this ModelAction */ +/** @brief Get a (likely) unique hash for this ModelAction */ unsigned int ModelAction::hash() const { unsigned int hash = (unsigned int)this->type; @@ -530,3 +625,43 @@ unsigned int ModelAction::hash() const hash ^= reads_from->get_seq_number(); return hash; } + +/** + * @brief Checks the NodeStack to see if a ModelAction is in our may-read-from set + * @param write The ModelAction to check for + * @return True if the ModelAction is found; false otherwise + */ +bool ModelAction::may_read_from(const ModelAction *write) const +{ + for (int i = 0; i < node->get_read_from_past_size(); i++) + if (node->get_read_from_past(i) == write) + return true; + return false; +} + +/** + * @brief Checks the NodeStack to see if a Promise is in our may-read-from set + * @param promise The Promise to check for + * @return True if the Promise is found; false otherwise + */ +bool ModelAction::may_read_from(const Promise *promise) const +{ + for (int i = 0; i < node->get_read_from_promise_size(); i++) + if (node->get_read_from_promise(i) == promise) + return true; + return false; +} + +/** + * Only valid for LOCK, TRY_LOCK, UNLOCK, and WAIT operations. + * @return The mutex operated on by this action, if any; otherwise NULL + */ +std::mutex * ModelAction::get_mutex() const +{ + if (is_trylock() || is_lock() || is_unlock()) + return (std::mutex *)get_location(); + else if (is_wait()) + return (std::mutex *)get_value(); + else + return NULL; +}