return lockOrder;
}
public MutableEdgeLabelledDirectedGraph detectLocksetDeadlock(
Map<Value, Integer> lockToLockNum, List<PointsToSetInternal> lockPTSets) {
MutableEdgeLabelledDirectedGraph permanentOrder = new HashMutableEdgeLabelledDirectedGraph();
MutableEdgeLabelledDirectedGraph lockOrder;
boolean foundDeadlock;
int iteration = 0;
do
{
iteration++;
G.v().out.println("[DeadlockDetector] Deadlock Iteration #" + iteration);
foundDeadlock = false;
lockOrder = (HashMutableEdgeLabelledDirectedGraph) ((HashMutableEdgeLabelledDirectedGraph) permanentOrder).clone(); // start each iteration with a fresh copy of the permanent orders
// Assemble the partial ordering of locks
Iterator<CriticalSection> deadlockIt1 = criticalSections.iterator();
while(deadlockIt1.hasNext() && !foundDeadlock)
{
CriticalSection tn1 = deadlockIt1.next();
// skip if unlocked
if( tn1.group == null )
continue;
// add a node for each lock in this lockset
for( EquivalentValue lockEqVal : tn1.lockset )
{
Value lock = lockEqVal.getValue();
if( !lockOrder.containsNode(lockToLockNum.get(lock)) )
lockOrder.addNode(lockToLockNum.get(lock));
}
// Get list of tn1's target methods
if(tn1.transitiveTargets == null)
{
tn1.transitiveTargets = new HashSet<MethodOrMethodContext>();
for(Unit tn1Invoke : tn1.invokes)
{
Iterator<MethodOrMethodContext> targetIt = tt.iterator(tn1Invoke);
while(targetIt.hasNext())
tn1.transitiveTargets.add(targetIt.next());
}
}
// compare to each other tn
Iterator<CriticalSection> deadlockIt2 = criticalSections.iterator();
while(deadlockIt2.hasNext() && !foundDeadlock)
{
CriticalSection tn2 = deadlockIt2.next();
// skip if unlocked
if( tn2.group == null )
continue;
// add a node for each lock in this lockset
for( EquivalentValue lockEqVal : tn2.lockset )
{
Value lock = lockEqVal.getValue();
if( !lockOrder.containsNode(lockToLockNum.get(lock)) )
lockOrder.addNode(lockToLockNum.get(lock));
}
if( tn1.transitiveTargets.contains(tn2.method) && !foundDeadlock )
{
// This implies the partial ordering (locks in tn1) before (locks in tn2)
if(true) //optionPrintDebug)
{
G.v().out.println("[DeadlockDetector] locks in " + (tn1.name) + " before locks in " + (tn2.name) + ": " +
"outer: " + tn1.name + " inner: " + tn2.name);
}
// Check if tn2locks before tn1locks is in our lock order
for( EquivalentValue lock2EqVal : tn2.lockset )
{
Value lock2 = lock2EqVal.getValue();
Integer lock2Num = lockToLockNum.get(lock2);
List afterTn2 = new ArrayList();
afterTn2.addAll( lockOrder.getSuccsOf(lock2Num) ); // filter here!
ListIterator lit = afterTn2.listIterator();
while(lit.hasNext())
{
Integer to = (Integer) lit.next(); // node the edges go to
List labels = lockOrder.getLabelsForEdges(lock2Num, to);
boolean keep = false;
if(labels != null) // this shouldn't really happen... is something wrong with the edge-labelled graph?
{
for(Object l : labels)
{
CriticalSection labelTn = (CriticalSection) l;
// Check if labelTn and tn1 share a static lock
boolean tnsShareAStaticLock = false;
for( EquivalentValue tn1LockEqVal : tn1.lockset )
{
Integer tn1LockNum = lockToLockNum.get(tn1LockEqVal.getValue());
if(tn1LockNum < 0)
{
// this is a static lock... see if some lock in labelTn has the same #
for( EquivalentValue labelTnLockEqVal : labelTn.lockset )
{
if(lockToLockNum.get(labelTnLockEqVal.getValue()) == tn1LockNum)
{
tnsShareAStaticLock = true;
}
}
}
}
if(!tnsShareAStaticLock) // !hasStaticLockInCommon(tn1, labelTn))
{
keep = true;
break;
}
}
}
if(!keep)
lit.remove();
}
/* for( int i = 0; i < afterTn2.size(); i++ )
{
List succs = lockOrder.getSuccsOf(afterTn2.get(i)); // but not here
for( Object o : succs )
{
if(!afterTn2.contains(o))
afterTn2.add(o);
}
}
*/
for( EquivalentValue lock1EqVal : tn1.lockset )
{
Value lock1 = lock1EqVal.getValue();
Integer lock1Num = lockToLockNum.get(lock1);
if( ( lock1Num != lock2Num ||
lock1Num > 0 ) &&
afterTn2.contains(lock1Num) )
{
if(!optionRepairDeadlock)
{
G.v().out.println("[DeadlockDetector] DEADLOCK HAS BEEN DETECTED: not correcting");
foundDeadlock = true;
}
else
{
G.v().out.println("[DeadlockDetector] DEADLOCK HAS BEEN DETECTED while inspecting " + lock1Num + " ("+lock1+") and " + lock2Num + " ("+lock2+") ");
// Create a deadlock avoidance edge
DeadlockAvoidanceEdge dae = new DeadlockAvoidanceEdge(tn1.method.getDeclaringClass());
EquivalentValue daeEqVal = new EquivalentValue(dae);
// Register it as a static lock
Integer daeNum = new Integer(-lockPTSets.size()); // negative indicates a static lock
permanentOrder.addNode(daeNum);
lockToLockNum.put(dae, daeNum);
PointsToSetInternal dummyLockPT = new HashPointsToSet(lock1.getType(), (PAG) Scene.v().getPointsToAnalysis());
lockPTSets.add(dummyLockPT);
// Add it to the locksets of tn1 and whoever says l2 before l1
for(EquivalentValue lockEqVal : tn1.lockset)
{
Integer lockNum = lockToLockNum.get(lockEqVal.getValue());
if(!permanentOrder.containsNode(lockNum))
permanentOrder.addNode(lockNum);
permanentOrder.addEdge(daeNum, lockNum, tn1);
}
tn1.lockset.add(daeEqVal);
List forwardLabels = lockOrder.getLabelsForEdges(lock1Num, lock2Num);
if(forwardLabels != null)
{
for(Object t : forwardLabels)
{
CriticalSection tn = (CriticalSection) t;
if(!tn.lockset.contains(daeEqVal))
{
for(EquivalentValue lockEqVal : tn.lockset)
{
Integer lockNum = lockToLockNum.get(lockEqVal.getValue());
if(!permanentOrder.containsNode(lockNum))
permanentOrder.addNode(lockNum);
permanentOrder.addEdge(daeNum, lockNum, tn);
}
tn.lockset.add(daeEqVal);
}
}
}
List backwardLabels = lockOrder.getLabelsForEdges(lock2Num, lock1Num);
if(backwardLabels != null)
{
for(Object t : backwardLabels)
{
CriticalSection tn = (CriticalSection) t;
if(!tn.lockset.contains(daeEqVal))
{
for(EquivalentValue lockEqVal : tn.lockset)
{
Integer lockNum = lockToLockNum.get(lockEqVal.getValue());
if(!permanentOrder.containsNode(lockNum))
permanentOrder.addNode(lockNum);
permanentOrder.addEdge(daeNum, lockNum, tn);
}
tn.lockset.add(daeEqVal);
G.v().out.println("[DeadlockDetector] Adding deadlock avoidance edge between " +
(tn1.name) + " and " + (tn.name));
}