| /******************************************************************************* |
| * Copyright (c) 2004, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.debug.ui.monitors; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| import org.eclipse.debug.core.DebugEvent; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILaunch; |
| import org.eclipse.debug.core.model.IDebugTarget; |
| import org.eclipse.jdt.debug.core.IJavaObject; |
| import org.eclipse.jdt.debug.core.IJavaThread; |
| |
| /** |
| * Represent a Java monitor in the threads and monitors model. |
| */ |
| public class JavaMonitor { |
| |
| /** |
| * The underlying object. |
| */ |
| private IJavaObject fMonitor; |
| |
| /** |
| * The thread which owns this monitor |
| */ |
| private JavaMonitorThread fOwningThread; |
| /** |
| * The threads waiting for this monitor. |
| */ |
| private JavaMonitorThread[] fWaitingThreads= new JavaMonitorThread[0]; |
| /** |
| * Indicate if this monitor is currently part of a deadlock. |
| */ |
| private boolean fIsInDeadlock; |
| /** |
| * Indicate that the information for this monitor need to be update, it |
| * may have changed. |
| */ |
| private boolean fToUpdate= true; |
| |
| /** |
| * The List of JavaContendedMonitor and JavaOwnedMonitor associated with this |
| * monitor. |
| */ |
| private List fElements= new ArrayList(); |
| |
| public JavaMonitor(IJavaObject monitor) { |
| fMonitor= monitor; |
| } |
| |
| public IJavaObject getMonitor() { |
| return fMonitor; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget() |
| */ |
| public IDebugTarget getDebugTarget() { |
| return fMonitor.getDebugTarget(); |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.IDebugElement#getLaunch() |
| */ |
| public ILaunch getLaunch() { |
| return fMonitor.getLaunch(); |
| } |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier() |
| */ |
| public String getModelIdentifier() { |
| return fMonitor.getModelIdentifier(); |
| } |
| |
| /** |
| * Returns the thread which owns this monitor, refresh the data |
| * first if need. |
| */ |
| protected JavaMonitorThread getOwningThread0() { |
| if (fToUpdate) { |
| update(); |
| } |
| return fOwningThread; |
| } |
| |
| /** |
| * Returns the threads waiting for this monitor, refresh the data |
| * first if need. |
| */ |
| protected JavaMonitorThread[] getWaitingThreads0() { |
| if (fToUpdate) { |
| update(); |
| } |
| return fWaitingThreads; |
| } |
| |
| /** |
| * Update the information for this monitor. |
| * @return <code>true</code> if the owning thread or |
| * the waiting threads changed. |
| */ |
| private boolean update() { |
| boolean changed= false; |
| boolean toRemove= false; |
| ThreadMonitorManager threadMonitorManager= ThreadMonitorManager.getDefault(); |
| synchronized (this) { |
| if (!fToUpdate) { |
| return false; |
| } |
| try { |
| if (fMonitor.isAllocated()) { |
| // update the owning thread |
| IJavaThread owningThread= fMonitor.getOwningThread(); |
| if (owningThread == null) { |
| changed= fOwningThread != null; |
| fOwningThread= null; |
| } else { |
| changed= fOwningThread == null || !owningThread.equals(fOwningThread.getThread()); |
| fOwningThread= ThreadMonitorManager.getDefault().getJavaMonitorThread(owningThread, null); |
| } |
| // update the waiting threads |
| IJavaThread[] waitingThreads= fMonitor.getWaitingThreads(); |
| if (waitingThreads == null || waitingThreads.length == 0) { |
| // if no waiting threads, not much to do |
| changed= fWaitingThreads != null && fWaitingThreads.length != 0; |
| fWaitingThreads= new JavaMonitorThread[0]; |
| toRemove= fOwningThread == null; |
| } else { |
| JavaMonitorThread[] tmp= new JavaMonitorThread[waitingThreads.length]; |
| if (changed || fWaitingThreads.length != waitingThreads.length) { |
| // if we know it changed, we can just create the new list |
| for (int i= 0; i < waitingThreads.length; i++) { |
| tmp[i]= threadMonitorManager.getJavaMonitorThread(waitingThreads[i], null); |
| } |
| changed= true; |
| } else { |
| // we need to check in the new list contains the same threads as the |
| // previous list |
| int sameThread= 0; |
| for (int i= 0; i < waitingThreads.length; i++) { |
| for (int j= 0; j < fWaitingThreads.length; j++) { |
| if (fWaitingThreads[i].getThread().equals(waitingThreads[i])) { |
| sameThread++; |
| break; |
| } |
| } |
| tmp[i]= threadMonitorManager.getJavaMonitorThread(waitingThreads[i], null); |
| } |
| changed= sameThread != waitingThreads.length; |
| } |
| fWaitingThreads= tmp; |
| } |
| } else { |
| toRemove= true; |
| } |
| } catch (DebugException e) { |
| fOwningThread= null; |
| fWaitingThreads= new JavaMonitorThread[0]; |
| } finally { |
| fToUpdate= false; |
| } |
| } |
| |
| if (toRemove) { |
| threadMonitorManager.removeJavaMonitor(this); |
| } else if (changed) { |
| fireChangeEvent(DebugEvent.CONTENT); |
| } |
| return changed; |
| } |
| |
| /** |
| * Send a change event for theJavaContendedMonitor and JavaOwnedMonitor |
| * associated with this monitor |
| */ |
| private void fireChangeEvent(int detail) { |
| Object[] elements= fElements.toArray(); |
| DebugEvent[] changeEvents= new DebugEvent[elements.length]; |
| for (int i= 0; i < elements.length; i++) { |
| changeEvents[i]= new DebugEvent(elements[i], DebugEvent.CHANGE, detail); |
| } |
| DebugPlugin.getDefault().fireDebugEventSet(changeEvents); |
| } |
| |
| public synchronized void setToUpdate() { |
| if (!fToUpdate) { |
| fToUpdate= true; |
| if (fOwningThread != null) { |
| fOwningThread.setToUpdate(); |
| } |
| if (fWaitingThreads != null) { |
| for (int i= 0; i < fWaitingThreads.length; i++) { |
| fWaitingThreads[i].setToUpdate(); |
| } |
| } |
| } |
| } |
| |
| protected void addElement(JavaOwnedMonitor monitor) { |
| fElements.add(monitor); |
| } |
| |
| protected void addElement(JavaContendedMonitor monitor) { |
| fElements.add(monitor); |
| } |
| |
| public void refresh() { |
| if (fToUpdate && !update()) { |
| if (fOwningThread != null) { |
| fOwningThread.refresh(); |
| } |
| for (int i= 0; i < fWaitingThreads.length; i++) { |
| fWaitingThreads[i].refresh(); |
| } |
| } |
| } |
| |
| /** |
| * Indicate if this monitor is currently part of a deadlock |
| */ |
| public boolean isInDeadlock() { |
| return fIsInDeadlock; |
| } |
| /** |
| * Set this monitor as being part of a deadlock. |
| */ |
| public void setInDeadlock(boolean isInDeadlock) { |
| boolean oldValue= fIsInDeadlock; |
| fIsInDeadlock = isInDeadlock; |
| if (oldValue != isInDeadlock) { |
| fireChangeEvent(DebugEvent.STATE); |
| } |
| } |
| } |