#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 */