Package org.apache.kato.katoview.commands

Source Code of org.apache.kato.katoview.commands.DeadlockCommand

/*******************************************************************************
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.apache.kato.katoview.commands;

import java.util.HashMap;
import java.util.Stack;
import java.util.Iterator;
import java.util.TreeMap;
import java.util.SortedMap;
import java.util.Vector;

import javax.tools.diagnostics.image.*;
import javax.tools.diagnostics.runtime.java.*;

import org.apache.kato.katoview.Output;
import org.apache.kato.katoview.commands.helpers.Exceptions;
import org.apache.kato.katoview.commands.helpers.MonitorNode;
import org.apache.kato.katoview.commands.helpers.NodeList;
import org.apache.kato.katoview.commands.helpers.Utils;


public class DeadlockCommand extends Command {

  public DeadlockCommand(Output o){
    super(o, "deadlock", "displays information about deadlocks if there are any",
        "parameters: none\n\n" +
        "The \"deadlock\" command shows detailed information about deadlocks " +
        "or \"no deadlocks detected\" if there are no deadlocks.  A deadlock " +
        "situation consists of one or more deadlock loops and zero or more " +
        "branches attached to those loops.  This command prints out each " +
        "branch attached to a loop and then the loop itself.  If there is a " +
        "split in a deadlock branch, separate branches will be created for " +
        "each side of the split in the branch.  Deadlock branches start with " +
        "a monitor that has no threads waiting on it and the continues until " +
        "it reaches a monitor that exists in another deadlock branch or loop.  " +
        "Deadlock loops start and end with the same monitor.\n\n" +
        "Monitors are represented by their owner and the object associated with " +
        "the given monitor.  For example, \"3435 (0x45ae67)\" represents the " +
        "monitor that is owned by the thread with id 3435 and is associated " +
        "the object at address 0x45ae67.  Objects can be viewed by using a " +
        "command like \"x/j 0x45ae67\" and threads can be viewed using a " +
        "command like \"info thread 3435\".\n"
    );
    child_commands = null;
  }
 
  public void doCommand(Stack args, Image loadedImage, HashMap properties)
  {
    Iterator itRuntime = Utils.getRuntimes(loadedImage);

    int jrnum = 1;
    while (itRuntime.hasNext())
    {
      SortedMap monitorNodes = new TreeMap();
      JavaRuntime jr = (JavaRuntime)itRuntime.next();
      Iterator itMonitor = jr.getMonitors().iterator();
      int nodeListNum = 0;
     
      out.print("\n  deadlocks for runtime #" + jrnum + "\n");
     
      // Step 1. iterate over all monitors, creating a MonitorNode for each monitor that
      // contains the monitor (JavaMonitor) and some parameters and adding that MonitorNode
      // to a Hashtable, indexed by owner (JavaThread object address)
      while (itMonitor.hasNext()) {
        JavaMonitor monitor = (JavaMonitor)itMonitor.next();
        MonitorNode node = new MonitorNode(monitor);
        JavaThread owner = null;
        Long id = null;
       
        try {
          owner = monitor.getOwner();
        } catch (CorruptDataException e) {
          out.error("exception encountered while getting monitor owner: " +
              Exceptions.getCorruptDataExceptionString());
          return;
        }

        if (null == owner) {
          // A monitor with no owner cannot be involved in a deadlock, according to the
          // algorithm used here anyway, because in order for a monitor to be in a deadlock,
          // its owner must be in a deadlock or an owner somewhere down the chain of
          // ownership must own the given monitor. Since there is no owner, we can't get
          // the monitor's owner or the next monitor in a potential deadlock chain.
          continue;
        } else {
          JavaObject threadObject;
          try {
            threadObject = owner.getObject();
          } catch (CorruptDataException e) {
            out.error("exception encountered while getting owner's JavaObject: " +
                Exceptions.getCorruptDataExceptionString());
            return;
          }
          id = new Long(threadObject.getID().getAddress());
        }
       
        // Note: we used to give up here with an error if there was already
        // a monitor node in the table with the same key (thread). This is very common (a
        // thread owning multiple monitors).
        monitorNodes.put(id, node);
      }

      Iterator values = monitorNodes.values().iterator();
     
      // Step 2. iterate over Hashtable and for every MonitorNode, iterate over monitor m1's
      // enter waiters (JavaMonitor.getEnterWaiters()), which are JavaThreads, and for each
      // enter waiter, set that waiter's MonitorNode's waitingOn to m1.
      while (values.hasNext()) {
        MonitorNode currNode = (MonitorNode)values.next();
        JavaMonitor currMonitor = currNode.getMonitor();
       
        Iterator itWaiters = currMonitor.getEnterWaiters().iterator();
        while (itWaiters.hasNext()) {
          JavaThread waiter = (JavaThread)itWaiters.next();
          JavaObject threadObject;
          Long id = null;
         
          try {
            threadObject = waiter.getObject();
          } catch (CorruptDataException e) {
            out.error("exception encountered while getting waiter's ImageThread: " +
                Exceptions.getCorruptDataExceptionString());
            return;
          }
         
          id = new Long(threadObject.getID().getAddress());         
         
          MonitorNode waiterNode = (MonitorNode)monitorNodes.get(id);
          if (null != waiterNode) {
            waiterNode.waitingOn = currNode;
          }
        }
      }

      values = monitorNodes.values().iterator();
      int visit = 1;
      Vector lists = new Vector();
     
      // Step 3. iterate over Hashtable and for every MonitorNode m1:
      // Step 3a. set a unique visit number, visit > 0 (visit++ would work)
      // Step 3b. iterate over waitingOns, setting visit number, until a null
      //  waitingOn is reached (no deadlock), a deadlocked node is reached
      //  (m1 is part of a branch that joins a deadlock loop), or a node with
      //  the same visit is reached (m1 is part of a deadlock loop)
      // Step 3c. if deadlock found, start at m1 and iterate over all
      //  waitingOns until a deadlocked node is found, setting deadlock
      //  (branch or loop, depending on result in 3b) along the way

      // note: Step 4* are not laid out precisely as specified; the instructions
      //  listed for Step 4* are integrated into Step 3
     
      // Step 4. for each MonitorNode m1 where inList == false and m1 is part
      //  of a deadlock loop *, create a new list and push it on the list
      //  stack right away:
      // Step 4a. iterate over all enter waiters, setting inList to true at
      //  every MonitorNode
      // Step 4b. if there are no enter waiters, terminate the current list
      // Step 4c. if there is one enter waiter: if the enter waiter is the
      //  current list, stop; else continue creating the current list,
      //  iterating to that thread's MonitorNode
      // Step 4d. if there is more than one enter waiter, continue creating
      //  current list and start a new list, pushing it on the list stack
      //  right away
     
      while (values.hasNext())
      {
        MonitorNode startNode = (MonitorNode)values.next();
        MonitorNode currNode = startNode;
        MonitorNode endNode;
       
        if (0 != startNode.visit)
        {
          continue;
        }
       
        while (true)
        {
          currNode.visit = visit;
         
          if (null == currNode.waitingOn)
          {
            currNode.deadlock = MonitorNode.NO_DEADLOCK;
            break;
          }
         
          if (isDeadlocked(currNode.waitingOn))
          {
            // we've encountered a deadlocked node in the chain;
            //  set branch deadlock for all nodes between startNode
            //  and currNode
           
            endNode = currNode.waitingOn;
            currNode = startNode;
            NodeList branchList = null;
            while (currNode != endNode)
            {
              if (null == branchList)
              {
                branchList = new NodeList(currNode, nodeListNum++);
              }
              currNode.deadlock = MonitorNode.BRANCH_DEADLOCK;
              currNode = currNode.waitingOn;
              branchList.add(currNode);
              if (currNode != endNode)
                currNode.inList = branchList;
            }
           
            if (endNode.inList.isLoop())
            {
              lists.insertElementAt(branchList, lists.indexOf(endNode.inList));
            }
            else
            {
              NodeList oldList = endNode.inList;
             
              // FIXME: the below line will cause problems with at least
              //  one case that was not considered when attachOrSplit was
              //  coded: if a NodeList n1 has already been split and another
              //  NodeList n2 tries to attach to the end of n1, then n1 will
              //  allow n2 to attach to n1, while what n1 should really do is
              //  just return n2 and not allow n2 to attach to itself
              NodeList split = endNode.inList.attachOrSplit(branchList, nodeListNum++);
              if (null != split)
              {
                lists.insertElementAt(split, lists.indexOf(oldList));
                lists.insertElementAt(branchList, lists.indexOf(oldList));
              }
            }
            break;
          }
         
          if (currNode.waitingOn.visit == visit)
          {
            // we've encountered a node in the same visit as the current
            //  visit, ie. we've found a loop; first flag the whole loop
            //  with a loop deadlock flag, then flag the rest of the nodes
            //  in the chain with a branch deadlock
           
            endNode = currNode.waitingOn;
            currNode = endNode;
            NodeList loopList = new NodeList(currNode, nodeListNum++);
            lists.insertElementAt(loopList, 0);
           
            do
            {
              currNode.deadlock = MonitorNode.LOOP_DEADLOCK;
              currNode = currNode.waitingOn;
              loopList.add(currNode);
              currNode.inList = loopList;
            } while (currNode != endNode);
           
            currNode = startNode;
            NodeList branchList = null;
            while (currNode != endNode)
            {
              if (null == branchList)
              {
                branchList = new NodeList(currNode, nodeListNum++);
                lists.insertElementAt(branchList, 0);
              }
              currNode.deadlock = MonitorNode.BRANCH_DEADLOCK;
              currNode = currNode.waitingOn;
              branchList.add(currNode);
              if (currNode != endNode)
                currNode.inList = branchList;
            }
            break;
          }
         
          currNode = currNode.waitingOn;
        }
       
        visit++;
      }

      if (lists.isEmpty())
      {
        out.print("\n");
        out.print("\t no deadlocks detected");
        out.print("\n");
        return;
      }
     
      boolean lastListWasLoop = true;
      Iterator itList = lists.iterator();

      // Step 5. print the lists
      while (itList.hasNext())
      {
        NodeList list = (NodeList)itList.next();
       
        if (list.isLoop()) {
          out.print("\n    deadlock loop:\n");
          lastListWasLoop = true;
        } else if (lastListWasLoop)  { // && !list.isLoop()
          out.print("\n\n    deadlock branch(es):\n");
          lastListWasLoop = false;
        }
       
        out.print("\t  " + list.toString());
        out.print("\n");
      }
      out.print("\n");
      jrnum++;
    }
  }
 
  private boolean isDeadlocked(MonitorNode node)
  {
    return MonitorNode.LOOP_DEADLOCK == node.deadlock ||
      MonitorNode.BRANCH_DEADLOCK == node.deadlock;
  }
}
TOP

Related Classes of org.apache.kato.katoview.commands.DeadlockCommand

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.