Package soot.jimple.toolkits.thread.synchronization

Source Code of soot.jimple.toolkits.thread.synchronization.DeadlockDetector

package soot.jimple.toolkits.thread.synchronization;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;

import soot.EquivalentValue;
import soot.G;
import soot.MethodOrMethodContext;
import soot.PointsToAnalysis;
import soot.Scene;
import soot.Unit;
import soot.Value;
import soot.jimple.spark.pag.PAG;
import soot.jimple.spark.sets.HashPointsToSet;
import soot.jimple.spark.sets.PointsToSetInternal;
import soot.jimple.toolkits.callgraph.Filter;
import soot.jimple.toolkits.callgraph.TransitiveTargets;
import soot.toolkits.graph.HashMutableDirectedGraph;
import soot.toolkits.graph.HashMutableEdgeLabelledDirectedGraph;
import soot.toolkits.graph.MutableDirectedGraph;
import soot.toolkits.graph.MutableEdgeLabelledDirectedGraph;

public class DeadlockDetector {

  boolean optionPrintDebug;
  boolean optionRepairDeadlock;
  boolean optionAllowSelfEdges;
  List<CriticalSection> criticalSections;
  TransitiveTargets tt;
 
  public DeadlockDetector(boolean optionPrintDebug, boolean optionRepairDeadlock, boolean optionAllowSelfEdges, List<CriticalSection> criticalSections)
  {
    this.optionPrintDebug = optionPrintDebug;
    this.optionRepairDeadlock = optionRepairDeadlock;
    this.optionAllowSelfEdges = optionAllowSelfEdges && !optionRepairDeadlock; // can only do this if not repairing
    this.criticalSections = criticalSections;
    this.tt = new TransitiveTargets(Scene.v().getCallGraph(), new Filter(new CriticalSectionVisibleEdgesPred(null)));
  }
 
  public MutableDirectedGraph<CriticalSectionGroup> detectComponentBasedDeadlock()
  {
    MutableDirectedGraph<CriticalSectionGroup> lockOrder;
    boolean foundDeadlock;
    int iteration = 0;
    do
    {
      iteration++;
      G.v().out.println("[DeadlockDetector] Deadlock Iteration #" + iteration);
      foundDeadlock = false;
      lockOrder = new HashMutableDirectedGraph(); // start each iteration with a fresh graph

      // Assemble the partial ordering of locks
      Iterator<CriticalSection> deadlockIt1 = criticalSections.iterator();
      while(deadlockIt1.hasNext() && !foundDeadlock)
      {
        CriticalSection tn1 = deadlockIt1.next();

        // skip if unlocked
        if( tn1.setNumber <= 0 )
          continue;

        // add a node for this set
        if( !lockOrder.containsNode(tn1.group) )
        {
          lockOrder.addNode(tn1.group);
        }

        // 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() && (!optionRepairDeadlock || !foundDeadlock))
        {
          CriticalSection tn2 = deadlockIt2.next();

          // skip if unlocked or in same set as tn1
          if( tn2.setNumber <= 0 || (tn2.setNumber == tn1.setNumber && !optionAllowSelfEdges) ) // this is wrong... dynamic locks in same group can be diff locks
            continue;

          // add a node for this set
          if( !lockOrder.containsNode(tn2.group) )
          {
            lockOrder.addNode(tn2.group);
         

          if( tn1.transitiveTargets.contains(tn2.method) )
          {
            // This implies the partial ordering tn1lock before tn2lock
            if(optionPrintDebug)
            {
              G.v().out.println("group" + (tn1.setNumber) + " before group" + (tn2.setNumber) + ": " +
                  "outer: " + tn1.name + " inner: " + tn2.name);
            }

            // Check if tn2lock before tn1lock is in our lock order
            List afterTn2 = new ArrayList();
            afterTn2.addAll( lockOrder.getSuccsOf(tn2.group) );
            for( int i = 0; i < afterTn2.size(); i++ )
            {
              List succs = lockOrder.getSuccsOf((CriticalSectionGroup) afterTn2.get(i));
              for( Object o : succs )
              {
                if(!afterTn2.contains(o))
                  afterTn2.add(o);
              }
            }

            if( afterTn2.contains(tn1.group) )
            {
              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: merging group" +
                    (tn1.setNumber) + " and group" + (tn2.setNumber) +
                " and restarting deadlock detection");

                if(optionPrintDebug)
                {
                  G.v().out.println("tn1.setNumber was " + tn1.setNumber + " and tn2.setNumber was " + tn2.setNumber);
                  G.v().out.println("tn1.group.size was " + tn1.group.criticalSections.size() +
                      " and tn2.group.size was " + tn2.group.criticalSections.size());
                  G.v().out.println("tn1.group.num was  " + tn1.group.num() + " and tn2.group.num was  " + tn2.group.num());
                }
                tn1.group.mergeGroups(tn2.group);
                if(optionPrintDebug)
                {
                  G.v().out.println("tn1.setNumber is  " + tn1.setNumber + " and tn2.setNumber is  " + tn2.setNumber);
                  G.v().out.println("tn1.group.size is  " + tn1.group.criticalSections.size() +
                      " and tn2.group.size is  " + tn2.group.criticalSections.size());
                }

                foundDeadlock = true;
              }
            }

            lockOrder.addEdge(tn1.group, tn2.group);
          }
        }
      }
    } while(foundDeadlock && optionRepairDeadlock);
    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));
                          }
                      }
                      G.v().out.println("[DeadlockDetector]   Restarting deadlock detection");
                    }
                   
                    foundDeadlock = true;
                    break;
                    }
                  }
                 
                  if(lock1Num != lock2Num)
                  lockOrder.addEdge(lock1Num, lock2Num, tn1);
                }
                if(foundDeadlock)
                  break;
              }
            }
        }
      }
    } while(foundDeadlock && optionRepairDeadlock);
    return lockOrder;
  }

  public void reorderLocksets(Map<Value, Integer> lockToLockNum, MutableEdgeLabelledDirectedGraph lockOrder) {
    for(CriticalSection tn : criticalSections)
    {
      // Get the portion of the lock order that is visible to tn
      HashMutableDirectedGraph visibleOrder = new HashMutableDirectedGraph();
      if(tn.group != null)
      {
        for(CriticalSection otherTn : criticalSections)
        {
          // Check if otherTn and tn share a static lock
          boolean tnsShareAStaticLock = false;
          for( EquivalentValue tnLockEqVal : tn.lockset )
          {
            Integer tnLockNum = lockToLockNum.get(tnLockEqVal.getValue());
            if(tnLockNum < 0)
            {
              // this is a static lock... see if some lock in labelTn has the same #
              if(otherTn.group != null)
              {
                for( EquivalentValue otherTnLockEqVal : otherTn.lockset )
                {
                  if(lockToLockNum.get(otherTnLockEqVal.getValue()) == tnLockNum)
                  {
                    tnsShareAStaticLock = true;
                  }
                }
              }
              else
                tnsShareAStaticLock = true; // not really... but we want to skip this one
            }
          }
         
          if(!tnsShareAStaticLock || tn == otherTn) // if tns don't share any static lock, or if tns are the same one
          {
            // add these orderings to tn's visible order
            MutableDirectedGraph orderings = lockOrder.getEdgesForLabel(otherTn);
            for(Object node1 : orderings.getNodes())
            {
              if(!visibleOrder.containsNode(node1))
                visibleOrder.addNode(node1);
              for(Object node2 : orderings.getSuccsOf(node1))
              {
                if(!visibleOrder.containsNode(node2))
                  visibleOrder.addNode(node2);
                visibleOrder.addEdge(node1, node2);
              }
            }
          }
        }

        G.v().out.println("VISIBLE ORDER FOR " + tn.name);
        visibleOrder.printGraph();
     
        // Order locks in tn's lockset according to the visible order (insertion sort)
        List<EquivalentValue> newLockset = new ArrayList();
        for(EquivalentValue lockEqVal : tn.lockset)
        {
          Value lockToInsert = lockEqVal.getValue();
          Integer lockNumToInsert = lockToLockNum.get(lockToInsert);
          int i = 0;
          while( i < newLockset.size() )
          {
            EquivalentValue existingLockEqVal = newLockset.get(i);
            Value existingLock = existingLockEqVal.getValue();
            Integer existingLockNum = lockToLockNum.get(existingLock);
            if( visibleOrder.containsEdge(lockNumToInsert, existingLockNum) ||
              lockNumToInsert < existingLockNum )
//              !visibleOrder.containsEdge(existingLockNum, lockNumToInsert) ) // if(! existing before toinsert )
              break;
            i++;
          }
          newLockset.add(i, lockEqVal);
        }
        G.v().out.println("reordered from " + LockAllocator.locksetToLockNumString(tn.lockset, lockToLockNum) +
                " to " + LockAllocator.locksetToLockNumString(newLockset, lockToLockNum));

        tn.lockset = newLockset;
      }
    }
  }
}
TOP

Related Classes of soot.jimple.toolkits.thread.synchronization.DeadlockDetector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.