bool ModelAction::has_synchronized_with(const ModelAction *act) const
{
- return cv->has_synchronized_with(act->cv);
+ return cv->synchronized_since(act);
}
/**
return false;
}
-bool ClockVector::has_synchronized_with(const ClockVector *cv) const
-{
- ASSERT(cv);
- if (cv->num_threads > num_threads)
- return false;
- for (int i = 0; i < cv->num_threads; i++)
- if (cv->clock[i] > clock[i])
- return false;
- return true;
-}
-
/** Gets the clock corresponding to a given thread id from the clock vector. */
modelclock_t ClockVector::getClock(thread_id_t thread) {
int threadid = id_to_int(thread);
~ClockVector();
void merge(const ClockVector *cv);
bool synchronized_since(const ModelAction *act) const;
- bool has_synchronized_with(const ClockVector *cv) const;
void print() const;
modelclock_t getClock(thread_id_t thread);
for(unsigned int i=0;i<get_num_threads();i++) {
thread_id_t tid=int_to_id(i);
Thread *thr=get_thread(tid);
- if ( scheduler->get_enabled(thr) == THREAD_SLEEP_SET ) {
+ if ( scheduler->get_enabled(thr) == THREAD_SLEEP_SET &&
+ thr->get_pending() == NULL ) {
thr->set_state(THREAD_RUNNING);
scheduler->next_thread(thr);
Thread::swap(&system_context, thr);
pending_rel_seqs->size());
- if (isfinalfeasible() || (params.bound != 0 && priv->used_sequence_numbers > params.bound ) || DBG_ENABLED() )
+ if (isfinalfeasible() || (params.bound != 0 && priv->used_sequence_numbers > params.bound ) || DBG_ENABLED() ) {
+ checkDataRaces();
print_summary();
+ }
if ((diverge = get_next_backtrack()) == NULL)
return false;
/** @return whether the current partial trace must be a prefix of a
* feasible trace. */
bool ModelChecker::isfeasibleprefix() {
- return promises->size() == 0 && pending_rel_seqs->size() == 0;
+ return promises->size() == 0 && pending_rel_seqs->size() == 0 && isfeasible();
}
/** @return whether the current partial trace is feasible. */
ModelAction *act=*rit;
bool foundvalue = false;
for (int j = 0; j<act->get_node()->get_read_from_size(); j++) {
- if (act->get_node()->get_read_from_at(i)==write) {
+ if (act->get_node()->get_read_from_at(j)==write) {
foundvalue = true;
break;
}
/* Iterate over all threads */
for (i = 0; i < thrd_lists->size(); i++) {
- ModelAction *write_after_read = NULL;
+ const ModelAction *write_after_read = NULL;
/* Iterate over actions in thread, starting from most recent */
action_list_t *list = &(*thrd_lists)[i];
break;
else if (act->is_write())
write_after_read = act;
+ else if (act->is_read()&&act->get_reads_from()!=NULL) {
+ write_after_read = act->get_reads_from();
+ }
}
-
- if (write_after_read && mo_graph->checkReachable(write_after_read, writer))
+
+ if (write_after_read && write_after_read!=writer && mo_graph->checkReachable(write_after_read, writer))
return false;
}
!act->same_thread(curr) &&
act->get_location() == curr->get_location() &&
promise->get_value() == curr->get_value()) {
- curr->get_node()->set_promise(i);
+ curr->get_node()->set_promise(i, act->is_rmw());
}
}
}
}
}
+void ModelChecker::check_promises_thread_disabled() {
+ for (unsigned int i = 0; i < promises->size(); i++) {
+ Promise *promise = (*promises)[i];
+ if (promise->check_promise()) {
+ failed_promise = true;
+ return;
+ }
+ }
+}
+
/** Checks promises in response to addition to modification order for threads.
* Definitions:
* pthread is the thread that performed the read that created the promise
if (promise->has_sync_thread(tid))
continue;
- if (mo_graph->checkReachable(promise->get_write(), write)) {
+ if (promise->get_write()&&mo_graph->checkReachable(promise->get_write(), write)) {
if (promise->increment_threads(tid)) {
failed_promise = true;
return;
bool isfeasible();
bool isfeasibleotherthanRMW();
bool isfinalfeasible();
+ void check_promises_thread_disabled();
void mo_check_promises(thread_id_t tid, const ModelAction *write);
void check_promises(thread_id_t tid, ClockVector *old_cv, ClockVector * merge_cv);
void get_release_seq_heads(ModelAction *act, rel_heads_list_t *release_heads);
* Sets a promise to explore meeting with the given node.
* @param i is the promise index.
*/
-void Node::set_promise(unsigned int i) {
+void Node::set_promise(unsigned int i, bool is_rmw) {
if (i >= promises.size())
promises.resize(i + 1, PROMISE_IGNORE);
- if (promises[i] == PROMISE_IGNORE)
+ if (promises[i] == PROMISE_IGNORE) {
promises[i] = PROMISE_UNFULFILLED;
+ if (is_rmw)
+ promises[i] |= PROMISE_RMW;
+ }
}
/**
* @return true if the promise should be satisfied by the given model action.
*/
bool Node::get_promise(unsigned int i) {
- return (i < promises.size()) && (promises[i] == PROMISE_FULFILLED);
+ return (i < promises.size()) && ((promises[i] & PROMISE_MASK) == PROMISE_FULFILLED);
}
/**
*/
bool Node::increment_promise() {
DBG();
-
+ unsigned int rmw_count=0;
+ for (unsigned int i = 0; i < promises.size(); i++) {
+ if (promises[i]==(PROMISE_RMW|PROMISE_FULFILLED))
+ rmw_count++;
+ }
+
for (unsigned int i = 0; i < promises.size(); i++) {
- if (promises[i] == PROMISE_UNFULFILLED) {
- promises[i] = PROMISE_FULFILLED;
+ if ((promises[i] & PROMISE_MASK) == PROMISE_UNFULFILLED) {
+ if ((rmw_count > 0) && (promises[i] & PROMISE_RMW)) {
+ //sending our value to two rmws... not going to work..try next combination
+ continue;
+ }
+ promises[i] = (promises[i] & PROMISE_RMW) |PROMISE_FULFILLED;
while (i > 0) {
i--;
- if (promises[i] == PROMISE_FULFILLED)
- promises[i] = PROMISE_UNFULFILLED;
+ if ((promises[i] & PROMISE_MASK) == PROMISE_FULFILLED)
+ promises[i] = (promises[i] & PROMISE_RMW) | PROMISE_UNFULFILLED;
}
return true;
+ } else if (promises[i] == (PROMISE_RMW|PROMISE_FULFILLED)) {
+ rmw_count--;
}
}
return false;
* @return true if we have explored all promise combinations.
*/
bool Node::promise_empty() {
- for (unsigned int i = 0; i < promises.size();i++)
- if (promises[i] == PROMISE_UNFULFILLED)
+ bool fulfilledrmw=false;
+ for (int i = promises.size()-1 ; i>=0; i--) {
+ if (promises[i]==PROMISE_UNFULFILLED)
+ return false;
+ if (!fulfilledrmw && ((promises[i]&PROMISE_MASK)==PROMISE_UNFULFILLED))
return false;
+ if (promises[i]==(PROMISE_FULFILLED|PROMISE_RMW))
+ fulfilledrmw=true;
+ }
return true;
}
* <li>@b fulfilled: satisfied by this Node's ModelAction under the current
* configuration.</li></ol>
*/
-typedef enum {
- PROMISE_IGNORE = 0, /**< This promise is inapplicable; ignore it */
- PROMISE_UNFULFILLED, /**< This promise is applicable but unfulfilled */
- PROMISE_FULFILLED /**< This promise is applicable and fulfilled */
-} promise_t;
+
+#define PROMISE_IGNORE 0 /**< This promise is inapplicable; ignore it */
+#define PROMISE_UNFULFILLED 1 /**< This promise is applicable but unfulfilled */
+#define PROMISE_FULFILLED 2 /**< This promise is applicable and fulfilled */
+#define PROMISE_MASK 0xf
+#define PROMISE_RMW 0x10
+
+typedef int promise_t;
struct future_value {
uint64_t value;
int get_read_from_size();
const ModelAction * get_read_from_at(int i);
- void set_promise(unsigned int i);
+ void set_promise(unsigned int i, bool is_rmw);
bool get_promise(unsigned int i);
bool increment_promise();
bool promise_empty();
bool Promise::increment_threads(thread_id_t tid) {
unsigned int id=id_to_int(tid);
- if (id>=synced_thread.size()) {
+ if ( id >= synced_thread.size() ) {
synced_thread.resize(id+1, false);
}
if (synced_thread[id])
synced_thread[id]=true;
enabled_type_t * enabled=model->get_scheduler()->get_enabled();
+ unsigned int sync_size=synced_thread.size();
+ int promise_tid=id_to_int(read->get_tid());
+ for(unsigned int i=1;i<model->get_num_threads();i++) {
+ if ((i >= sync_size || !synced_thread[i]) && ( (int)i != promise_tid ) && (enabled[i] != THREAD_DISABLED)) {
+ return false;
+ }
+ }
+ return true;
+}
- for(unsigned int i=0;i<model->get_num_threads();i++) {
- if (!synced_thread[id] && (enabled[id] == THREAD_ENABLED))
+bool Promise::check_promise() {
+ enabled_type_t * enabled=model->get_scheduler()->get_enabled();
+ unsigned int sync_size=synced_thread.size();
+ for(unsigned int i=1;i<model->get_num_threads();i++) {
+ if ((i >= sync_size || !synced_thread[i]) && (enabled[i] != THREAD_DISABLED)) {
return false;
+ }
}
return true;
}
return synced_thread[id];
}
+ bool check_promise();
uint64_t get_value() const { return value; }
void set_write(const ModelAction *act) { write = act; }
const ModelAction * get_write() { return write; }
enabled_len=threadid+1;
}
enabled[threadid]=enabled_status;
+ if (enabled_status == THREAD_DISABLED)
+ model->check_promises_thread_disabled();
}
/**