blob: b9d6b18b66babd0abf8a8b9fc87d1391e199ddfe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2012 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.core.runtime.PlatformObject;
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<PlatformObject> 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);
}
}
}