X-Git-Url: http://plrg.eecs.uci.edu/git/?p=c11tester.git;a=blobdiff_plain;f=action.cc;h=4cdca0d7a7272b2f4c6eef265ef34ca613bc0c3f;hp=bd98f5ca2f490f4c3743641ee7018d8e178d72ec;hb=7742256df627848c1c375f979f5369a45c92057b;hpb=4fa31aac91303266f4c87a6cd5d60cbab34135db diff --git a/action.cc b/action.cc index bd98f5ca..4cdca0d7 100644 --- a/action.cc +++ b/action.cc @@ -1,13 +1,14 @@ #include #define __STDC_FORMAT_MACROS #include +#include #include "model.h" #include "action.h" #include "clockvector.h" #include "common.h" #include "threads-model.h" -#include "nodestack.h" +#include "wildcard.h" #define ACTION_INITIAL_CLOCK 0 @@ -30,26 +31,160 @@ * (default), then a Thread is assigned according to the scheduler. */ ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, - uint64_t value, Thread *thread) : + uint64_t value, Thread *thread) : + location(loc), + position(NULL), + reads_from(NULL), + last_fence_release(NULL), + cv(NULL), + rf_cv(NULL), + action_ref(NULL), + value(value), + type(type), + order(order), + original_order(order), + seq_number(ACTION_INITIAL_CLOCK) +{ + /* References to NULL atomic variables can end up here */ + ASSERT(loc || type == ATOMIC_FENCE || type == ATOMIC_NOP); + + Thread *t = thread ? thread : thread_current(); + this->tid = t!= NULL ? t->get_id() : -1; +} + + +/** + * @brief Construct a new ModelAction for sleep actions + * + * @param type The type of action: THREAD_SLEEP + * @param order The memory order of this action. A "don't care" for non-ATOMIC + * actions (e.g., THREAD_* or MODEL_* actions). + * @param loc The location that this action acts upon + * @param value The time duration a thread is scheduled to sleep. + * @param _time The this sleep action is constructed + */ +ModelAction::ModelAction(action_type_t type, memory_order order, uint64_t value, uint64_t _time) : + location(NULL), + position(NULL), + time(_time), + last_fence_release(NULL), + cv(NULL), + rf_cv(NULL), + action_ref(NULL), + value(value), + type(type), + order(order), + original_order(order), + seq_number(ACTION_INITIAL_CLOCK) +{ + Thread *t = thread_current(); + this->tid = t!= NULL ? t->get_id() : -1; +} + +/** + * @brief Construct a new ModelAction + * + * @param type The type of action + * @param order The memory order of this action. A "don't care" for non-ATOMIC + * actions (e.g., THREAD_* or MODEL_* actions). + * @param loc The location that this action acts upon + * @param value (optional) A value associated with the action (e.g., the value + * read or written). Defaults to a given macro constant, for debugging purposes. + * @param size (optional) The Thread in which this action occurred. If NULL + * (default), then a Thread is assigned according to the scheduler. + */ +ModelAction::ModelAction(action_type_t type, memory_order order, void *loc, + uint64_t value, int size) : + location(loc), + position(NULL), + reads_from(NULL), + last_fence_release(NULL), + cv(NULL), + rf_cv(NULL), + action_ref(NULL), + value(value), type(type), order(order), + original_order(order), + seq_number(ACTION_INITIAL_CLOCK) +{ + /* References to NULL atomic variables can end up here */ + ASSERT(loc); + this->size = size; + this->tid = thread_current_id(); +} + + +/** + * @brief Construct a new ModelAction with source line number (requires llvm support) + * + * @param type The type of action + * @param order The memory order of this action. A "don't care" for non-ATOMIC + * actions (e.g., THREAD_* or MODEL_* actions). + * @param loc The location that this action acts upon + * @param value (optional) A value associated with the action (e.g., the value + * read or written). Defaults to a given macro constant, for debugging purposes. + * @param size (optional) The Thread in which this action occurred. If NULL + * (default), then a Thread is assigned according to the scheduler. + */ +ModelAction::ModelAction(action_type_t type, const char * position, memory_order order, void *loc, + uint64_t value, int size) : location(loc), + position(position), + reads_from(NULL), + last_fence_release(NULL), + cv(NULL), + rf_cv(NULL), + action_ref(NULL), value(value), + type(type), + order(order), + original_order(order), + seq_number(ACTION_INITIAL_CLOCK) +{ + /* References to NULL atomic variables can end up here */ + ASSERT(loc); + this->size = size; + this->tid = thread_current_id(); +} + + +/** + * @brief Construct a new ModelAction with source line number (requires llvm support) + * + * @param type The type of action + * @param position The source line number of this atomic operation + * @param order The memory order of this action. A "don't care" for non-ATOMIC + * actions (e.g., THREAD_* or MODEL_* actions). + * @param loc The location that this action acts upon + * @param value (optional) A value associated with the action (e.g., the value + * read or written). Defaults to a given macro constant, for debugging purposes. + * @param thread (optional) The Thread in which this action occurred. If NULL + * (default), then a Thread is assigned according to the scheduler. + */ +ModelAction::ModelAction(action_type_t type, const char * position, memory_order order, + void *loc, uint64_t value, Thread *thread) : + location(loc), + position(position), reads_from(NULL), - reads_from_promise(NULL), last_fence_release(NULL), - node(NULL), - seq_number(ACTION_INITIAL_CLOCK), cv(NULL), - sleep_flag(false) + rf_cv(NULL), + action_ref(NULL), + value(value), + type(type), + order(order), + original_order(order), + seq_number(ACTION_INITIAL_CLOCK) { /* References to NULL atomic variables can end up here */ - ASSERT(loc || type == ATOMIC_FENCE || type == MODEL_FIXUP_RELSEQ); + ASSERT(loc || type == ATOMIC_FENCE); Thread *t = thread ? thread : thread_current(); this->tid = t->get_id(); } + /** @brief ModelAction destructor */ ModelAction::~ModelAction() { @@ -60,9 +195,15 @@ ModelAction::~ModelAction() * vectors which have already been rolled back to an unallocated state. */ - /* - if (cv) - delete cv; */ + + if (cv) + delete cv; + if (rf_cv) + delete rf_cv; +} + +int ModelAction::getSize() const { + return size; } void ModelAction::copy_from_new(ModelAction *newaction) @@ -72,30 +213,28 @@ void ModelAction::copy_from_new(ModelAction *newaction) void ModelAction::set_seq_number(modelclock_t num) { - /* ATOMIC_UNINIT actions should never have non-zero clock */ - ASSERT(!is_uninitialized()); ASSERT(seq_number == ACTION_INITIAL_CLOCK); seq_number = num; } -bool ModelAction::is_thread_start() const +void ModelAction::reset_seq_number() { - return type == THREAD_START; + seq_number = 0; } -bool ModelAction::is_thread_join() const +bool ModelAction::is_thread_start() const { - return type == THREAD_JOIN; + return type == THREAD_START; } -bool ModelAction::is_relseq_fixup() const +bool ModelAction::is_thread_join() const { - return type == MODEL_FIXUP_RELSEQ; + return type == THREAD_JOIN || type == PTHREAD_JOIN; } bool ModelAction::is_mutex_op() const { - return type == ATOMIC_LOCK || type == ATOMIC_TRYLOCK || type == ATOMIC_UNLOCK || type == ATOMIC_WAIT || type == ATOMIC_NOTIFY_ONE || type == ATOMIC_NOTIFY_ALL; + return type == ATOMIC_LOCK || type == ATOMIC_TRYLOCK || type == ATOMIC_UNLOCK || type == ATOMIC_WAIT || type == ATOMIC_TIMEDWAIT || type == ATOMIC_NOTIFY_ONE || type == ATOMIC_NOTIFY_ALL; } bool ModelAction::is_lock() const @@ -103,8 +242,13 @@ bool ModelAction::is_lock() const return type == ATOMIC_LOCK; } +bool ModelAction::is_sleep() const +{ + return type == THREAD_SLEEP; +} + bool ModelAction::is_wait() const { - return type == ATOMIC_WAIT; + return type == ATOMIC_WAIT || type == ATOMIC_TIMEDWAIT; } bool ModelAction::is_notify() const { @@ -141,19 +285,24 @@ bool ModelAction::is_atomic_var() const return is_read() || could_be_write(); } -bool ModelAction::is_uninitialized() const +bool ModelAction::is_read() const { - return type == ATOMIC_UNINIT; + return type == ATOMIC_READ || type == ATOMIC_RMWR || type == ATOMIC_RMWRCAS || type == ATOMIC_RMW; } -bool ModelAction::is_read() const +bool ModelAction::is_write() const { - return type == ATOMIC_READ || type == ATOMIC_RMWR || type == ATOMIC_RMW; + return type == ATOMIC_WRITE || type == ATOMIC_RMW || type == ATOMIC_INIT || type == NONATOMIC_WRITE; } -bool ModelAction::is_write() const +bool ModelAction::is_create() const +{ + return type == THREAD_CREATE || type == PTHREAD_CREATE; +} + +bool ModelAction::is_free() const { - return type == ATOMIC_WRITE || type == ATOMIC_RMW || type == ATOMIC_INIT || type == ATOMIC_UNINIT; + return type == READY_FREE; } bool ModelAction::could_be_write() const @@ -168,7 +317,12 @@ bool ModelAction::is_yield() const bool ModelAction::is_rmwr() const { - return type == ATOMIC_RMWR; + return type == ATOMIC_RMWR || type == ATOMIC_RMWRCAS; +} + +bool ModelAction::is_rmwrcas() const +{ + return type == ATOMIC_RMWRCAS; } bool ModelAction::is_rmw() const @@ -191,6 +345,11 @@ bool ModelAction::is_initialization() const return type == ATOMIC_INIT; } +bool ModelAction::is_annotation() const +{ + return type == ATOMIC_ANNOTATION; +} + bool ModelAction::is_relaxed() const { return order == std::memory_order_relaxed; @@ -269,13 +428,18 @@ void ModelAction::copy_typeandorder(ModelAction * act) 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_operand is set in execution.cc */ + return thread_operand; + } else if (type == PTHREAD_CREATE) { + return thread_operand; + } else if (type == THREAD_JOIN) { /* THREAD_JOIN uses (Thread *) for location */ return (Thread *)get_location(); - else + } else if (type == PTHREAD_JOIN) { + // return NULL; + // thread_operand is stored in execution::pthread_map; + return (Thread *)get_location(); + } else return NULL; } @@ -322,7 +486,7 @@ bool ModelAction::could_synchronize_with(const ModelAction *act) const return false; // Different locations commute - if (!same_var(act)) + if (!same_var(act) && !is_fence() && !act->is_fence()) return false; // Explore interleavings of seqcst writes/fences to guarantee total @@ -417,9 +581,8 @@ 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 */ + + return VALUE_NONE; // Only for new actions with no reads-from } /** @@ -459,36 +622,15 @@ uint64_t ModelAction::get_return_value() const return value; } -/** @return The Node associated with this ModelAction */ -Node * ModelAction::get_node() const -{ - /* UNINIT actions do not have a Node */ - ASSERT(!is_uninitialized()); - return node; -} - /** * Update the model action's read_from action * @param act The action to read from; should be a write */ -void ModelAction::set_read_from(const ModelAction *act) +void ModelAction::set_read_from(ModelAction *act) { ASSERT(act); - reads_from = act; - 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; + reads_from = act; } /** @@ -499,9 +641,8 @@ void ModelAction::set_read_from_promise(Promise *promise) */ bool ModelAction::synchronize_with(const ModelAction *act) { - if (*this < *act && type != THREAD_JOIN && type != ATOMIC_LOCK) + if (*this < *act) return false; - model->check_promises(act->get_tid(), cv, act->cv); cv->merge(act->cv); return true; } @@ -522,115 +663,74 @@ bool ModelAction::happens_before(const ModelAction *act) const return act->cv->synchronized_since(this); } -/** @brief Print nicely-formatted info about this ModelAction */ -void ModelAction::print() const +const char * ModelAction::get_type_str() const { - const char *type_str, *mo_str; switch (this->type) { - case MODEL_FIXUP_RELSEQ: - type_str = "relseq fixup"; - break; - case THREAD_CREATE: - type_str = "thread create"; - break; - case THREAD_START: - type_str = "thread start"; - break; - case THREAD_YIELD: - type_str = "thread yield"; - break; - case THREAD_JOIN: - type_str = "thread join"; - break; - case THREAD_FINISH: - type_str = "thread finish"; - break; - case ATOMIC_UNINIT: - type_str = "uninitialized"; - break; - case ATOMIC_READ: - type_str = "atomic read"; - break; - case ATOMIC_WRITE: - type_str = "atomic write"; - break; - case ATOMIC_RMW: - type_str = "atomic rmw"; - break; - case ATOMIC_FENCE: - type_str = "fence"; - break; - case ATOMIC_RMWR: - type_str = "atomic rmwr"; - break; - case ATOMIC_RMWC: - type_str = "atomic rmwc"; - break; - case ATOMIC_INIT: - type_str = "init atomic"; - break; - case ATOMIC_LOCK: - type_str = "lock"; - break; - case ATOMIC_UNLOCK: - type_str = "unlock"; - break; - case ATOMIC_TRYLOCK: - type_str = "trylock"; - break; - case ATOMIC_WAIT: - type_str = "wait"; - break; - case ATOMIC_NOTIFY_ONE: - type_str = "notify one"; - break; - case ATOMIC_NOTIFY_ALL: - type_str = "notify all"; - break; - default: - type_str = "unknown type"; - } - + case THREAD_CREATE: return "thread create"; + case THREAD_START: return "thread start"; + case THREAD_YIELD: return "thread yield"; + case THREAD_JOIN: return "thread join"; + case THREAD_FINISH: return "thread finish"; + case THREAD_SLEEP: return "thread sleep"; + case THREADONLY_FINISH: return "pthread_exit finish"; + + case PTHREAD_CREATE: return "pthread create"; + case PTHREAD_JOIN: return "pthread join"; + + case NONATOMIC_WRITE: return "nonatomic write"; + case ATOMIC_READ: return "atomic read"; + case ATOMIC_WRITE: return "atomic write"; + case ATOMIC_RMW: return "atomic rmw"; + case ATOMIC_FENCE: return "fence"; + case ATOMIC_RMWR: return "atomic rmwr"; + case ATOMIC_RMWRCAS: return "atomic rmwrcas"; + case ATOMIC_RMWC: return "atomic rmwc"; + case ATOMIC_INIT: return "init atomic"; + case ATOMIC_LOCK: return "lock"; + case ATOMIC_UNLOCK: return "unlock"; + case ATOMIC_TRYLOCK: return "trylock"; + case ATOMIC_WAIT: return "wait"; + case ATOMIC_TIMEDWAIT: return "timed wait"; + case ATOMIC_NOTIFY_ONE: return "notify one"; + case ATOMIC_NOTIFY_ALL: return "notify all"; + case ATOMIC_ANNOTATION: return "annotation"; + default: return "unknown type"; + }; +} + +const char * ModelAction::get_mo_str() const +{ switch (this->order) { - case std::memory_order_relaxed: - mo_str = "relaxed"; - break; - case std::memory_order_acquire: - mo_str = "acquire"; - break; - case std::memory_order_release: - mo_str = "release"; - break; - case std::memory_order_acq_rel: - mo_str = "acq_rel"; - break; - case std::memory_order_seq_cst: - mo_str = "seq_cst"; - break; - default: - mo_str = "unknown"; - break; + case std::memory_order_relaxed: return "relaxed"; + case std::memory_order_acquire: return "acquire"; + case std::memory_order_release: return "release"; + case std::memory_order_acq_rel: return "acq_rel"; + case std::memory_order_seq_cst: return "seq_cst"; + default: return "unknown"; } +} - 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, get_return_value()); +/** @brief Print nicely-formatted info about this ModelAction */ +void ModelAction::print() const +{ + const char *type_str = get_type_str(), *mo_str = get_mo_str(); + + model_print("%-4d %-2d %-14s %7s %14p %-#18" PRIx64, + seq_number, id_to_int(tid), type_str, mo_str, location, get_return_value()); if (is_read()) { + if (is_write()) { + model_print("(%" PRIx64 ")", get_write_value()); + } if (reads_from) - model_print(" Rf: %-3d", reads_from->get_seq_number()); - 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: ? "); + model_print(" %-3d", reads_from->get_seq_number()); + else + model_print(" ? "); } if (cv) { if (is_read()) model_print(" "); else - model_print(" "); + model_print(" "); cv->print(); } else model_print("\n"); @@ -645,51 +745,23 @@ unsigned int ModelAction::hash() const hash ^= id_to_int(tid) << 6; if (is_read()) { - if (reads_from) - hash ^= reads_from->get_seq_number(); - else if (reads_from_promise) - hash ^= model->get_promise_number(reads_from_promise); - hash ^= get_reads_from_value(); + if (reads_from) + hash ^= reads_from->get_seq_number(); + hash ^= get_reads_from_value(); } 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 +cdsc::mutex * ModelAction::get_mutex() const { if (is_trylock() || is_lock() || is_unlock()) - return (std::mutex *)get_location(); + return (cdsc::mutex *)get_location(); else if (is_wait()) - return (std::mutex *)get_value(); + return (cdsc::mutex *)get_value(); else return NULL; }