+#include <string.h>
+
#include "nodestack.h"
#include "action.h"
#include "common.h"
* @param nthreads The number of threads which exist at this point in the
* execution trace.
*/
-Node::Node(ModelAction *act, Node *par, int nthreads)
+Node::Node(ModelAction *act, Node *par, int nthreads, Node *prevfairness)
: action(act),
parent(par),
num_threads(nthreads),
explored_children(num_threads),
backtrack(num_threads),
+ fairness(num_threads),
numBacktracks(0),
+ enabled_array(NULL),
may_read_from(),
read_from_index(0),
future_values(),
future_index(-1)
{
- if (act)
+ if (act) {
act->set_node(this);
+ int currtid=id_to_int(act->get_tid());
+ int prevtid=(prevfairness != NULL)?id_to_int(prevfairness->action->get_tid()):0;
+
+ if ( model->params.fairwindow != 0 ) {
+ for(int i=0;i<nthreads;i++) {
+ ASSERT(i<((int)fairness.size()));
+ struct fairness_info * fi=& fairness[i];
+ struct fairness_info * prevfi=(par!=NULL)&&(i<par->get_num_threads())?&par->fairness[i]:NULL;
+ if (prevfi) {
+ *fi=*prevfi;
+ }
+ if (parent->enabled_array[i]) {
+ fi->enabled_count++;
+ }
+ if (i==currtid) {
+ fi->turns++;
+ fi->priority = false;
+ }
+ //Do window processing
+ if (prevfairness != NULL) {
+ if (prevfairness -> parent->enabled_array[i])
+ fi->enabled_count--;
+ if (i==prevtid) {
+ fi->turns--;
+ }
+ //Need full window to start evaluating conditions
+ //If we meet the enabled count and have no turns, give us priority
+ if ((fi->enabled_count >= model->params.enabledcount) &&
+ (fi->turns == 0))
+ fi->priority = true;
+ }
+ }
+ }
+ }
}
/** @brief Node desctructor */
{
if (action)
delete action;
+ if (enabled_array)
+ MYFREE(enabled_array);
}
/** Prints debugging info for the ModelAction associated with this Node */
*/
void Node::set_promise(unsigned int i) {
if (i >= promises.size())
- promises.resize(i + 1, 0);
- promises[i] = 1;
+ promises.resize(i + 1, PROMISE_IGNORE);
+ if (promises[i] == PROMISE_IGNORE)
+ promises[i] = PROMISE_UNFULFILLED;
}
/**
* @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] == 2);
+ return (i < promises.size()) && (promises[i] == PROMISE_FULFILLED);
}
/**
*/
bool Node::increment_promise() {
for (unsigned int i = 0; i < promises.size(); i++) {
- if (promises[i] == 1) {
- promises[i] = 2;
+ if (promises[i] == PROMISE_UNFULFILLED) {
+ promises[i] = PROMISE_FULFILLED;
while (i > 0) {
i--;
- if (promises[i] == 2)
- promises[i] = 1;
+ if (promises[i] == PROMISE_FULFILLED)
+ promises[i] = PROMISE_UNFULFILLED;
}
return true;
}
*/
bool Node::promise_empty() {
for (unsigned int i = 0; i < promises.size();i++)
- if (promises[i] == 1)
+ if (promises[i] == PROMISE_UNFULFILLED)
return false;
return true;
}
* Adds a value from a weakly ordered future write to backtrack to.
* @param value is the value to backtrack to.
*/
-bool Node::add_future_value(uint64_t value) {
- for (unsigned int i = 0; i < future_values.size(); i++)
- if (future_values[i] == value)
- return false;
+bool Node::add_future_value(uint64_t value, modelclock_t expiration) {
+ int suitableindex=-1;
+ for (unsigned int i = 0; i < future_values.size(); i++) {
+ if (future_values[i].value == value) {
+ if (future_values[i].expiration>=expiration)
+ return false;
+ if (future_index < i) {
+ suitableindex=i;
+ }
+ }
+ }
- future_values.push_back(value);
+ if (suitableindex!=-1) {
+ future_values[suitableindex].expiration=expiration;
+ return true;
+ }
+ struct future_value newfv={value, expiration};
+ future_values.push_back(newfv);
return true;
}
* Mark the appropriate backtracking information for exploring a thread choice.
* @param act The ModelAction to explore
*/
-void Node::explore_child(ModelAction *act)
+void Node::explore_child(ModelAction *act, bool * is_enabled)
{
+ if ( ! enabled_array )
+ enabled_array=(bool *)MYMALLOC(sizeof(bool)*num_threads);
+ if (is_enabled != NULL)
+ memcpy(enabled_array, is_enabled, sizeof(bool)*num_threads);
+ else {
+ for(int i=0;i<num_threads;i++)
+ enabled_array[i]=false;
+ }
+
explore(act->get_tid());
}
bool Node::is_enabled(Thread *t)
{
- return id_to_int(t->get_id()) < num_threads;
+ int thread_id=id_to_int(t->get_id());
+ return thread_id < num_threads && enabled_array[thread_id];
+}
+
+bool Node::is_enabled(thread_id_t tid)
+{
+ int thread_id=id_to_int(tid);
+ return thread_id < num_threads && enabled_array[thread_id];
}
/**
*/
uint64_t Node::get_future_value() {
ASSERT(future_index<future_values.size());
- return future_values[future_index];
+ return future_values[future_index].value;
+}
+
+modelclock_t Node::get_future_value_expiration() {
+ ASSERT(future_index<future_values.size());
+ return future_values[future_index].expiration;
+}
+
+
+int Node::get_read_from_size() {
+ return may_read_from.size();
+}
+
+const ModelAction * Node::get_read_from_at(int i) {
+ return may_read_from[i];
}
/**
explored_children[i] = true;
}
-static void clear_node_list(node_list_t *list, node_list_t::iterator start,
- node_list_t::iterator end)
-{
- node_list_t::iterator it;
-
- for (it = start; it != end; it++)
- delete (*it);
- list->erase(start, end);
-}
-
NodeStack::NodeStack()
: total_nodes(0)
{
node_list.push_back(new Node());
total_nodes++;
- iter = node_list.begin();
+ iter = 0;
}
NodeStack::~NodeStack()
{
- clear_node_list(&node_list, node_list.begin(), node_list.end());
}
void NodeStack::print()
{
- node_list_t::iterator it;
printf("............................................\n");
printf("NodeStack printing node_list:\n");
- for (it = node_list.begin(); it != node_list.end(); it++) {
+ for (unsigned int it = 0; it < node_list.size(); it++) {
if (it == this->iter)
printf("vvv following action is the current iterator vvv\n");
- (*it)->print();
+ node_list[it]->print();
}
printf("............................................\n");
}
-ModelAction * NodeStack::explore_action(ModelAction *act)
+/** Note: The is_enabled set contains what actions were enabled when
+ * act was chosen. */
+
+ModelAction * NodeStack::explore_action(ModelAction *act, bool * is_enabled)
{
DBG();
ASSERT(!node_list.empty());
- node_list_t::iterator it=iter;
- it++;
- if (it != node_list.end()) {
+ if ((iter+1) < node_list.size()) {
iter++;
- return (*iter)->get_action();
+ return node_list[iter]->get_action();
}
/* Record action */
- get_head()->explore_child(act);
- node_list.push_back(new Node(act, get_head(), model->get_num_threads()));
+ get_head()->explore_child(act, is_enabled);
+ Node *prevfairness = NULL;
+ if ( model->params.fairwindow != 0 && iter > model->params.fairwindow ) {
+ prevfairness = node_list[iter-model->params.fairwindow];
+ }
+ node_list.push_back(new Node(act, get_head(), model->get_num_threads(), prevfairness));
total_nodes++;
iter++;
return NULL;
void NodeStack::pop_restofstack(int numAhead)
{
/* Diverging from previous execution; clear out remainder of list */
- node_list_t::iterator it = iter;
- while (numAhead--)
- it++;
- clear_node_list(&node_list, it, node_list.end());
+ unsigned int it=iter+numAhead;
+ node_list.resize(it);
}
Node * NodeStack::get_head()
{
if (node_list.empty())
return NULL;
- return *iter;
+ return node_list[iter];
}
Node * NodeStack::get_next()
{
- node_list_t::iterator it = iter;
if (node_list.empty()) {
DEBUG("Empty\n");
return NULL;
}
- it++;
- if (it == node_list.end()) {
+ unsigned int it=iter+1;
+ if (it == node_list.size()) {
DEBUG("At end\n");
return NULL;
}
- return *it;
+ return node_list[it];
}
void NodeStack::reset_execution()
{
- iter = node_list.begin();
+ iter = 0;
}