static void param_defaults(struct model_params * params) {
params->maxreads = 0;
+ params->maxfuturedelay = 100;
}
-static void print_usage() {
+static void print_usage(struct model_params *params) {
printf(
"Usage: <program name> [MC_OPTIONS] -- [PROGRAM ARGUMENTS]\n"
"\n"
"Options:\n"
"-h Display this help message and exit\n"
-"-m Maximum times a thread can read from the same write while other writes exist\n"
-"-- Program arguments follow.\n\n");
+"-m Maximum times a thread can read from the same write while other writes exist. Default: %d\n"
+"-s Maximum actions that the model checker will wait for a write from the future past the expected number of actions. Default: %d\n"
+"-- Program arguments follow.\n\n", params->maxreads, params->maxfuturedelay);
exit(EXIT_SUCCESS);
}
static void parse_options(struct model_params *params, int *argc, char ***argv) {
- const char *shortopts = "hm:";
+ const char *shortopts = "hm:s:";
int opt;
bool error = false;
while (!error && (opt = getopt(*argc, *argv, shortopts)) != -1) {
switch (opt) {
case 'h':
- print_usage();
+ print_usage(params);
+ break;
+ case 's':
+ params->maxfuturedelay = atoi(optarg);
break;
case 'm':
params->maxreads = atoi(optarg);
(*argv) += optind;
if (error)
- print_usage();
+ print_usage(params);
}
int main_argc;
} else {
/* Read from future value */
value = curr->get_node()->get_future_value();
+ modelclock_t expiration = curr->get_node()->get_future_value_expiration();
curr->read_from(NULL);
- Promise *valuepromise = new Promise(curr, value);
+ Promise *valuepromise = new Promise(curr, value, expiration);
promises->push_back(valuepromise);
}
th->set_return_value(value);
return get_next_thread(curr);
}
+bool ModelChecker::promises_expired() {
+ for (unsigned int promise_index = 0; promise_index < promises->size(); promise_index++) {
+ Promise *promise = (*promises)[promise_index];
+ if (promise->get_expiration()<priv->used_sequence_numbers) {
+ return true;
+ }
+ }
+ return false;
+}
+
/** @returns whether the current partial trace must be a prefix of a
* feasible trace. */
bool ModelChecker::isfeasibleprefix() {
/** @returns whether the current partial trace is feasible. */
bool ModelChecker::isfeasible() {
- return !mo_graph->checkForCycles() && !failed_promise && !too_many_reads;
+ return !mo_graph->checkForCycles() && !failed_promise && !too_many_reads && !promises_expired();
}
/** Returns whether the current completed trace is feasible. */
=>
that read could potentially read from our write.
*/
- if (isfeasible() && act->get_node()->add_future_value(curr->get_value()) &&
+ if (isfeasible() && act->get_node()->add_future_value(curr->get_value(), curr->get_seq_number()+params.maxfuturedelay) &&
(!priv->next_backtrack || *act > *priv->next_backtrack))
priv->next_backtrack = act;
}
*/
struct model_params {
int maxreads;
+ int maxfuturedelay;
};
/**
bool has_asserted() {return asserted;}
void reset_asserted() {asserted=false;}
int num_executions;
-
+ bool promises_expired();
const model_params params;
/**
void Node::set_promise(unsigned int i) {
if (i >= promises.size())
promises.resize(i + 1, PROMISE_IGNORE);
- promises[i] = PROMISE_UNFULFILLED;
+ if (promises[i] == PROMISE_IGNORE)
+ promises[i] = PROMISE_UNFULFILLED;
}
/**
* 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;
}
*/
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();
}
#include <cstddef>
#include "threads.h"
#include "mymemory.h"
+#include "clockvector.h"
class ModelAction;
PROMISE_FULFILLED /**< This promise is applicable and fulfilled */
} promise_t;
+struct future_value {
+ uint64_t value;
+ modelclock_t expiration;
+};
+
+
/**
* @brief A single node in a NodeStack
*
* occurred previously in the stack. */
Node * get_parent() const { return parent; }
- bool add_future_value(uint64_t value);
+ bool add_future_value(uint64_t value, modelclock_t expiration);
uint64_t get_future_value();
+ modelclock_t get_future_value_expiration();
bool increment_future_value();
bool future_value_empty();
unsigned int read_from_index;
- std::vector< uint64_t, MyAlloc< uint64_t > > future_values;
+ std::vector< struct future_value, MyAlloc<struct future_value> > future_values;
std::vector< promise_t, MyAlloc<promise_t> > promises;
unsigned int future_index;
};
class Promise {
public:
- Promise(ModelAction *act, uint64_t value) :
- value(value), read(act), numthreads(1)
+ Promise(ModelAction *act, uint64_t value, modelclock_t expiration) :
+ value(value), expiration(expiration), read(act), numthreads(1)
{ }
+ modelclock_t get_expiration() const {return expiration;}
ModelAction * get_action() const { return read; }
int increment_threads() { return ++numthreads; }
uint64_t get_value() const { return value; }
private:
const uint64_t value;
+ const modelclock_t expiration;
ModelAction * const read;
unsigned int numthreads;
};