* same thread or the parent that created this thread)
* @param act is an action with which to update the ClockVector
*/
-ClockVector::ClockVector(ClockVector *parent, ModelAction *act)
+ClockVector::ClockVector(ClockVector *parent, const ModelAction *act)
{
ASSERT(act);
num_threads = int_to_id(act->get_tid()) + 1;
class ClockVector {
public:
- ClockVector(ClockVector *parent = NULL, ModelAction *act = NULL);
+ ClockVector(ClockVector *parent = NULL, const ModelAction *act = NULL);
~ClockVector();
bool merge(const ClockVector *cv);
bool synchronized_since(const ModelAction *act) const;
#include "action.h"
#include "common.h"
#include "threads-model.h"
+#include "clockvector.h"
/** Initializes a CycleGraph object. */
CycleGraph::CycleGraph() :
- discovered(new HashTable<const CycleNode *, const CycleNode *, uintptr_t, 4, model_malloc, model_calloc, model_free>(16)),
- queue(new ModelVector<const CycleNode *>()),
- hasCycles(false),
- oldCycles(false)
+ queue(new SnapVector<const CycleNode *>())
{
}
CycleGraph::~CycleGraph()
{
delete queue;
- delete discovered;
}
/**
* @param tonode The edge points to this CycleNode
* @return True, if new edge(s) are added; otherwise false
*/
-bool CycleGraph::addNodeEdge(CycleNode *fromnode, CycleNode *tonode)
+void CycleGraph::addNodeEdge(CycleNode *fromnode, CycleNode *tonode)
{
- if (fromnode->addEdge(tonode)) {
- rollbackvector.push_back(fromnode);
- if (!hasCycles)
- hasCycles = checkReachable(tonode, fromnode);
- } else
- return false;/* No new edge */
+ //quick check whether edge is redundant
+ if (checkReachable(fromnode, tonode))
+ return;
+
+ CycleNode *edgeSrcNode = fromnode;
/*
- * If the fromnode has a rmwnode that is not the tonode, we should
- * follow its RMW chain to add an edge at the end, unless we encounter
- * tonode along the way
+ * If the fromnode has a rmwnode, we should
+ * follow its RMW chain to add an edge at the end.
*/
CycleNode *rmwnode = fromnode->getRMW();
if (rmwnode) {
- while (rmwnode != tonode && rmwnode->getRMW())
+ while (rmwnode->getRMW())
rmwnode = rmwnode->getRMW();
+ edgeSrcNode = rmwnode;
+ }
- if (rmwnode != tonode) {
- if (rmwnode->addEdge(tonode)) {
- if (!hasCycles)
- hasCycles = checkReachable(tonode, rmwnode);
-
- rollbackvector.push_back(rmwnode);
+ edgeSrcNode->addEdge(tonode); //Add edge to edgeSrcNode
+
+ /* Propagate clock vector changes */
+ if (tonode->cv->merge(edgeSrcNode->cv)) {
+ queue->push_back(edgeSrcNode);
+ while(!queue->empty()) {
+ const CycleNode *node = queue->back();
+ unsigned int numedges = node->getNumEdges();
+ for(unsigned int i = 0;i < numedges;i++) {
+ CycleNode * enode = node->getEdge(i);
+ if (enode->cv->merge(node->cv))
+ queue->push_back(enode);
}
}
}
- return true;
}
/**
* @brief Add an edge between a write and the RMW which reads from it
*
* Handles special case of a RMW action, where the ModelAction rmw reads from
- * the ModelAction/Promise from. The key differences are:
+ * the ModelAction from. The key differences are:
* -# No write can occur in between the @a rmw and @a from actions.
* -# Only one RMW action can read from a given write.
*
- * @param from The edge comes from this ModelAction/Promise
+ * @param from The edge comes from this ModelAction
* @param rmw The edge points to this ModelAction; this action must read from
- * the ModelAction/Promise from
+ * the ModelAction from
*/
-template <typename T>
-void CycleGraph::addRMWEdge(const T *from, const ModelAction *rmw)
+void CycleGraph::addRMWEdge(const ModelAction *from, const ModelAction *rmw)
{
ASSERT(from);
ASSERT(rmw);
/* We assume that this RMW has no RMW reading from it yet */
ASSERT(!rmwnode->getRMW());
- /* Two RMW actions cannot read from the same write. */
- if (fromnode->setRMW(rmwnode))
- hasCycles = true;
- else
- rmwrollbackvector.push_back(fromnode);
+ fromnode->setRMW(rmwnode);
/* Transfer all outgoing edges from the from node to the rmw node */
/* This process should not add a cycle because either:
for (unsigned int i = 0;i < fromnode->getNumEdges();i++) {
CycleNode *tonode = fromnode->getEdge(i);
if (tonode != rmwnode) {
- if (rmwnode->addEdge(tonode))
- rollbackvector.push_back(rmwnode);
+ rmwnode->addEdge(tonode);
}
}
addNodeEdge(fromnode, rmwnode);
}
-/* Instantiate two forms of CycleGraph::addRMWEdge */
-template void CycleGraph::addRMWEdge(const ModelAction *from, const ModelAction *rmw);
/**
* @brief Adds an edge between objects
* @param from The edge comes from this object, of type U
* @return True, if new edge(s) are added; otherwise false
*/
-template <typename T, typename U>
-bool CycleGraph::addEdge(const T *from, const U *to)
+
+void CycleGraph::addEdge(const ModelAction *from, const ModelAction *to)
{
ASSERT(from);
ASSERT(to);
CycleNode *fromnode = getNode(from);
CycleNode *tonode = getNode(to);
- return addNodeEdge(fromnode, tonode);
+ addNodeEdge(fromnode, tonode);
}
-/* Instantiate four forms of CycleGraph::addEdge */
-template bool CycleGraph::addEdge(const ModelAction *from, const ModelAction *to);
#if SUPPORT_MOD_ORDER_DUMP
print_node(file, getNode(act), 1);
}
-template <typename T, typename U>
-void CycleGraph::dot_print_edge(FILE *file, const T *from, const U *to, const char *prop)
+void CycleGraph::dot_print_edge(FILE *file, const ModelAction *from, const ModelAction *to, const char *prop)
{
CycleNode *fromnode = getNode(from);
CycleNode *tonode = getNode(to);
print_edge(file, fromnode, tonode, prop);
}
-/* Instantiate two forms of CycleGraph::dot_print_edge */
-template void CycleGraph::dot_print_edge(FILE *file, const ModelAction *from, const ModelAction *to, const char *prop);
void CycleGraph::dumpNodes(FILE *file) const
{
*/
bool CycleGraph::checkReachable(const CycleNode *from, const CycleNode *to) const
{
- discovered->reset();
- queue->clear();
- queue->push_back(from);
- discovered->put(from, from);
- while (!queue->empty()) {
- const CycleNode *node = queue->back();
- queue->pop_back();
- if (node == to)
- return true;
- for (unsigned int i = 0;i < node->getNumEdges();i++) {
- CycleNode *next = node->getEdge(i);
- if (!discovered->contains(next)) {
- discovered->put(next, next);
- queue->push_back(next);
- }
- }
- }
- return false;
+ return to->cv->synchronized_since(from->action);
}
/**
- * Checks whether one ModelAction/Promise can reach another ModelAction/Promise
- * @param from The ModelAction or Promise from which to begin exploration
- * @param to The ModelAction or Promise to reach
+ * Checks whether one ModelAction can reach another ModelAction
+ * @param from The ModelAction from which to begin exploration
+ * @param to The ModelAction to reach
* @return True, @a from can reach @a to; otherwise, false
*/
-template <typename T, typename U>
-bool CycleGraph::checkReachable(const T *from, const U *to) const
+bool CycleGraph::checkReachable(const ModelAction *from, const ModelAction *to) const
{
CycleNode *fromnode = getNode_noCreate(from);
CycleNode *tonode = getNode_noCreate(to);
return checkReachable(fromnode, tonode);
}
-/* Instantiate four forms of CycleGraph::checkReachable */
-template bool CycleGraph::checkReachable(const ModelAction *from,
- const ModelAction *to) const;
-
-/** @brief Begin a new sequence of graph additions which can be rolled back */
-void CycleGraph::startChanges()
-{
- ASSERT(rollbackvector.empty());
- ASSERT(rmwrollbackvector.empty());
- ASSERT(oldCycles == hasCycles);
-}
-
-/** Commit changes to the cyclegraph. */
-void CycleGraph::commitChanges()
-{
- rollbackvector.clear();
- rmwrollbackvector.clear();
- oldCycles = hasCycles;
-}
-
-/** Rollback changes to the previous commit. */
-void CycleGraph::rollbackChanges()
-{
- for (unsigned int i = 0;i < rollbackvector.size();i++)
- rollbackvector[i]->removeEdge();
-
- for (unsigned int i = 0;i < rmwrollbackvector.size();i++)
- rmwrollbackvector[i]->clearRMW();
-
- hasCycles = oldCycles;
- rollbackvector.clear();
- rmwrollbackvector.clear();
-}
-
-/** @returns whether a CycleGraph contains cycles. */
-bool CycleGraph::checkForCycles() const
-{
- return hasCycles;
-}
/**
* @brief Constructor for a CycleNode
*/
CycleNode::CycleNode(const ModelAction *act) :
action(act),
- hasRMW(NULL)
+ hasRMW(NULL),
+ cv(new ClockVector(NULL, act))
{
}
return edges.size();
}
-/**
- * @brief Remove an element from a vector
- * @param v The vector
- * @param n The element to remove
- * @return True if the element was found; false otherwise
- */
-template <typename T>
-static bool vector_remove_node(SnapVector<T>& v, const T n)
-{
- for (unsigned int i = 0;i < v.size();i++) {
- if (v[i] == n) {
- v.erase(v.begin() + i);
- return true;
- }
- }
- return false;
-}
-
/**
* @brief Remove a (forward) edge from this CycleNode
* @return The CycleNode which was popped, if one exists; otherwise NULL
* @param node The node to which we add a directed edge
* @return True if this edge is a new edge; false otherwise
*/
-bool CycleNode::addEdge(CycleNode *node)
+void CycleNode::addEdge(CycleNode *node)
{
for (unsigned int i = 0;i < edges.size();i++)
if (edges[i] == node)
- return false;
+ return;
edges.push_back(node);
- return true;
}
/** @returns the RMW CycleNode that reads from the current CycleNode */
public:
CycleGraph();
~CycleGraph();
+ void addEdge(const ModelAction *from, const ModelAction *to);
+ void addRMWEdge(const ModelAction *from, const ModelAction *rmw);
+ bool checkReachable(const ModelAction *from, const ModelAction *to) const;
- template <typename T, typename U>
- bool addEdge(const T *from, const U *to);
-
- template <typename T>
- void addRMWEdge(const T *from, const ModelAction *rmw);
-
- bool checkForCycles() const;
-
- template <typename T, typename U>
- bool checkReachable(const T *from, const U *to) const;
-
- void startChanges();
- void commitChanges();
- void rollbackChanges();
#if SUPPORT_MOD_ORDER_DUMP
void dumpNodes(FILE *file) const;
void dumpGraphToFile(const char *filename) const;
-
void dot_print_node(FILE *file, const ModelAction *act);
- template <typename T, typename U>
- void dot_print_edge(FILE *file, const T *from, const U *to, const char *prop);
+ void dot_print_edge(FILE *file, const ModelAction *from, const ModelAction *to, const char *prop);
#endif
- CycleNode * getNode_noCreate(const ModelAction *act) const;
+ CycleNode * getNode_noCreate(const ModelAction *act) const;
SNAPSHOTALLOC
private:
- bool addNodeEdge(CycleNode *fromnode, CycleNode *tonode);
+ void addNodeEdge(CycleNode *fromnode, CycleNode *tonode);
void putNode(const ModelAction *act, CycleNode *node);
CycleNode * getNode(const ModelAction *act);
- bool mergeNodes(CycleNode *node1, CycleNode *node2);
-
- HashTable<const CycleNode *, const CycleNode *, uintptr_t, 4, model_malloc, model_calloc, model_free> *discovered;
- ModelVector<const CycleNode *> * queue;
-
/** @brief A table for mapping ModelActions to CycleNodes */
HashTable<const ModelAction *, CycleNode *, uintptr_t, 4> actionToNode;
+ SnapVector<const CycleNode *> * queue;
#if SUPPORT_MOD_ORDER_DUMP
SnapVector<CycleNode *> nodeList;
#endif
bool checkReachable(const CycleNode *from, const CycleNode *to) const;
-
- /** @brief A flag: true if this graph contains cycles */
- bool hasCycles;
- /** @brief The previous value of CycleGraph::hasCycles, for rollback */
- bool oldCycles;
-
- SnapVector<CycleNode *> rollbackvector;
- SnapVector<CycleNode *> rmwrollbackvector;
};
/**
class CycleNode {
public:
CycleNode(const ModelAction *act);
- bool addEdge(CycleNode *node);
+ void addEdge(CycleNode *node);
CycleNode * getEdge(unsigned int i) const;
unsigned int getNumEdges() const;
CycleNode * removeEdge();
-
bool setRMW(CycleNode *);
CycleNode * getRMW() const;
void clearRMW() { hasRMW = NULL; }
/** Pointer to a RMW node that reads from this node, or NULL, if none
* exists */
CycleNode *hasRMW;
+
+ /** ClockVector for this Node. */
+ ClockVector *cv;
+ friend class CycleGraph;
};
#endif /* __CYCLEGRAPH_H__ */
used_sequence_numbers(0),
bugs(),
bad_synchronization(false),
- bad_sc_read(false),
asserted(false)
{ }
SnapVector<bug_message *> bugs;
/** @brief Incorrectly-ordered synchronization was made */
bool bad_synchronization;
- bool bad_sc_read;
bool asserted;
SNAPSHOTALLOC
};
/** @brief Constructor */
-ModelExecution::ModelExecution(ModelChecker *m,
- Scheduler *scheduler,
- NodeStack *node_stack) :
+ModelExecution::ModelExecution(ModelChecker *m, Scheduler *scheduler, NodeStack *node_stack) :
model(m),
params(NULL),
scheduler(scheduler),
priv->bad_synchronization = true;
}
-/** @brief Alert the model-checker that an incorrectly-ordered
- * synchronization was made */
-void ModelExecution::set_bad_sc_read()
-{
- priv->bad_sc_read = true;
-}
-
bool ModelExecution::assert_bug(const char *msg)
{
priv->bugs.push_back(new bug_message(msg));
* @param rf_set is the set of model actions we can possibly read from
* @return True if processing this read updates the mo_graph.
*/
-bool ModelExecution::process_read(ModelAction *curr, ModelVector<ModelAction *> * rf_set)
+bool ModelExecution::process_read(ModelAction *curr, SnapVector<ModelAction *> * rf_set)
{
while(true) {
ASSERT(rf);
mo_graph->startChanges();
- bool updated = r_modification_order(curr, rf);
+ r_modification_order(curr, rf);
if (!is_infeasible()) {
read_from(curr, rf);
mo_graph->commitChanges();
if (!second_part_of_rmw)
add_action_to_lists(curr);
- ModelVector<ModelAction *> * rf_set = NULL;
+ SnapVector<ModelAction *> * rf_set = NULL;
/* Build may_read_from set for newly-created actions */
if (newly_explored && curr->is_read())
rf_set = build_may_read_from(curr);
ptr += sprintf(ptr, "[mo cycle]");
if (priv->bad_synchronization)
ptr += sprintf(ptr, "[bad sw ordering]");
- if (priv->bad_sc_read)
- ptr += sprintf(ptr, "[bad sc read]");
if (ptr != buf)
model_print("%s: %s", prefix ? prefix : "Infeasible", buf);
}
bool ModelExecution::is_infeasible() const
{
return mo_graph->checkForCycles() ||
- priv->bad_synchronization ||
- priv->bad_sc_read;
+ priv->bad_synchronization;
}
/** Close out a RMWR by converting previous RMWR into a RMW or READ. */
* @param rf The ModelAction or Promise that curr reads from. Must be a write.
* @return True if modification order edges were added; false otherwise
*/
-template <typename rf_type>
-bool ModelExecution::r_modification_order(ModelAction *curr, const rf_type *rf)
+
+bool ModelExecution::r_modification_order(ModelAction *curr, const ModelAction *rf, SnapVector<ModelAction *> * priorset)
{
SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
unsigned int i;
- bool added = false;
ASSERT(curr->is_read());
/* Last SC fence in the current thread */
/* C++, Section 29.3 statement 5 */
if (curr->is_seqcst() && last_sc_fence_thread_local &&
*act < *last_sc_fence_thread_local) {
- added = mo_graph->addEdge(act, rf) || added;
+ if (mo_graph->checkReachable(rf, act))
+ return false;
+ priorset->add(act);
break;
}
/* C++, Section 29.3 statement 4 */
else if (act->is_seqcst() && last_sc_fence_local &&
*act < *last_sc_fence_local) {
- added = mo_graph->addEdge(act, rf) || added;
- break;
+ if (mo_graph->checkReachable(rf, act))
+ return false;
+ priorset->add(act);
+ break;
}
/* C++, Section 29.3 statement 6 */
else if (last_sc_fence_thread_before &&
*act < *last_sc_fence_thread_before) {
- added = mo_graph->addEdge(act, rf) || added;
- break;
+ if (mo_graph->checkReachable(rf, act))
+ return false;
+ priorset->add(act);
+ break;
}
}
*/
if (act->happens_before(curr)) {
if (act->is_write()) {
- added = mo_graph->addEdge(act, rf) || added;
+ if (mo_graph->checkReachable(rf, act))
+ return false;
+ priorset->add(act);
} else {
const ModelAction *prevrf = act->get_reads_from();
- if (!prevrf->equals(rf))
- added = mo_graph->addEdge(prevrf, rf) || added;
+ if (!prevrf->equals(rf)) {
+ if (mo_graph->checkReachable(rf, prevrf))
+ return false;
+ priorset->add(prevrf);
+ }
}
break;
}
}
}
-
- return added;
+ return true;
}
/**
* value. If NULL, then don't record any future values.
* @return True if modification order edges were added; false otherwise
*/
-bool ModelExecution::w_modification_order(ModelAction *curr)
+void ModelExecution::w_modification_order(ModelAction *curr)
{
SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
unsigned int i;
- bool added = false;
ASSERT(curr->is_write());
if (curr->is_seqcst()) {
so we are initialized. */
ModelAction *last_seq_cst = get_last_seq_cst_write(curr);
if (last_seq_cst != NULL) {
- added = mo_graph->addEdge(last_seq_cst, curr) || added;
+ mo_graph->addEdge(last_seq_cst, curr);
}
}
/* C++, Section 29.3 statement 7 */
if (last_sc_fence_thread_before && act->is_write() &&
*act < *last_sc_fence_thread_before) {
- added = mo_graph->addEdge(act, curr) || added;
+ mo_graph->addEdge(act, curr);
break;
}
* readfrom(act) --mo--> act
*/
if (act->is_write())
- added = mo_graph->addEdge(act, curr) || added;
+ mo_graph->addEdge(act, curr);
else if (act->is_read()) {
//if previous read accessed a null, just keep going
- added = mo_graph->addEdge(act->get_reads_from(), curr) || added;
+ mo_graph->addEdge(act->get_reads_from(), curr);
}
break;
} else if (act->is_read() && !act->could_synchronize_with(curr) &&
}
}
}
-
- return added;
}
/**
* @param curr is the current ModelAction that we are exploring; it must be a
* 'read' operation.
*/
-ModelVector<ModelAction *> * ModelExecution::build_may_read_from(ModelAction *curr)
+SnapVector<ModelAction *> * ModelExecution::build_may_read_from(ModelAction *curr)
{
SnapVector<action_list_t> *thrd_lists = obj_thrd_map.get(curr->get_location());
unsigned int i;
if (curr->is_seqcst())
last_sc_write = get_last_seq_cst_write(curr);
- ModelVector<ModelAction *> * rf_set = new ModelVector<ModelAction *>();
+ SnapVector<ModelAction *> * rf_set = new SnapVector<ModelAction *>();
+ SnapVector<ModelAction *> * priorset = new SnapVector<ModelAction *>();
/* Iterate over all threads */
for (i = 0;i < thrd_lists->size();i++) {
bool mo_may_allow(const ModelAction *writer, const ModelAction *reader);
void set_bad_synchronization();
- void set_bad_sc_read();
bool should_wake_up(const ModelAction *curr, const Thread *thread) const;
void wake_up_sleeping_actions(ModelAction *curr);
modelclock_t get_next_seq_num();
bool next_execution();
ModelAction * check_current_action(ModelAction *curr);
bool initialize_curr_action(ModelAction **curr);
- bool process_read(ModelAction *curr, ModelVector<ModelAction *> * rf_set);
+ bool process_read(ModelAction *curr, SnapVector<ModelAction *> * rf_set);
bool process_write(ModelAction *curr);
bool process_fence(ModelAction *curr);
bool process_mutex(ModelAction *curr);
ModelAction * get_last_seq_cst_write(ModelAction *curr) const;
ModelAction * get_last_seq_cst_fence(thread_id_t tid, const ModelAction *before_fence) const;
ModelAction * get_last_unlock(ModelAction *curr) const;
- ModelVector<ModelAction *> * build_may_read_from(ModelAction *curr);
+ SnapVector<ModelAction *> * build_may_read_from(ModelAction *curr);
ModelAction * process_rmw(ModelAction *curr);
- template <typename rf_type>
- bool r_modification_order(ModelAction *curr, const rf_type *rf);
-
- bool w_modification_order(ModelAction *curr);
+ bool r_modification_order(ModelAction *curr, const ModelAction *rf, SnapVector<ModelAction *> *priorset);
+ void w_modification_order(ModelAction *curr);
void get_release_seq_heads(ModelAction *acquire, ModelAction *read, rel_heads_list_t *release_heads);
bool release_seq_heads(const ModelAction *rf, rel_heads_list_t *release_heads) const;
ModelAction * get_uninitialized_action(const ModelAction *curr) const;
#include "threads-model.h"
#include "model.h"
-int Fuzzer::selectWrite(ModelAction *read, ModelVector<ModelAction *> * rf_set) {
+int Fuzzer::selectWrite(ModelAction *read, SnapVector<ModelAction *> * rf_set) {
int random_index = random() % rf_set->size();
return random_index;
}
class Fuzzer {
public:
Fuzzer() {}
- int selectWrite(ModelAction *read, ModelVector<ModelAction *>* rf_set);
+ int selectWrite(ModelAction *read, SnapVector<ModelAction *>* rf_set);
Thread * selectThread(Node *n, int * threadlist, int numthreads);
Thread * selectNotify(action_list_t * waiters);
MEMALLOC