1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-04-21 21:52:10 +02:00

[291684] Equip monitors with a monitor traceback (when tracing)

This commit is contained in:
John Cortell 2009-10-08 22:57:25 +00:00
parent bd20ae7286
commit 4a942b7640
4 changed files with 187 additions and 3 deletions

View file

@ -10,9 +10,15 @@
*******************************************************************************/
package org.eclipse.cdt.dsf.ui.concurrent;
import java.lang.reflect.Field;
import java.util.concurrent.Executor;
import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
import org.eclipse.cdt.dsf.concurrent.DsfExecutable;
import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
import org.eclipse.cdt.dsf.internal.DsfPlugin;
import org.eclipse.cdt.dsf.ui.viewmodel.VMViewerUpdate;
import org.eclipse.core.runtime.Platform;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
/**
@ -23,11 +29,24 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
* @since 1.0
*/
public class ViewerDataRequestMonitor<V> extends DataRequestMonitor<V> {
/**
* Same as {@link DsfExecutable#DEBUG_MONITORS}
*/
static private boolean DEBUG_MONITORS = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.cdt.dsf/debug/monitors")); //$NON-NLS-1$
private final IViewerUpdate fUpdate;
public ViewerDataRequestMonitor(Executor executor, IViewerUpdate update) {
super(executor, null);
fUpdate = update;
if (DEBUG_MONITORS) {
createMonitorBacktrace();
}
}
@Override
@ -51,4 +70,115 @@ public class ViewerDataRequestMonitor<V> extends DataRequestMonitor<V> {
fUpdate.setStatus(getStatus());
fUpdate.done();
}
/**
* Instrument this object with a backtrace of the monitors this instance is
* chained to. See {@link DsfExecutable#DEBUG_MONITORS}. The logic here has
* to subvert Java access protection by using reflection. That's OK; this is
* not production code. This stuff will only ever run when tracing is turned
* on.
*/
private void createMonitorBacktrace() {
StringBuilder str = new StringBuilder();
RequestMonitor nextrm = this;
VMViewerUpdate nextupdate = null;
String type = null;
while (true) {
StackTraceElement topFrame = null;
if (nextupdate != null) {
type = "update "; //$NON-NLS-1$ extra space to match length of 'monitor'
topFrame = getCreatedAtTopFrame(nextupdate);
nextrm = getMonitor(nextupdate);
nextupdate = null;
}
else if (nextrm != null) {
type = "monitor"; //$NON-NLS-1$
topFrame = getCreatedAtTopFrame(nextrm);
if (nextrm instanceof ViewerDataRequestMonitor<?>) {
ViewerDataRequestMonitor<?> vdrm = (ViewerDataRequestMonitor<?>)nextrm;
nextupdate = (vdrm.fUpdate instanceof VMViewerUpdate) ? (VMViewerUpdate)vdrm.fUpdate : null;
nextrm = null;
}
else {
nextrm = getParentMonitor(nextrm);
nextupdate = null;
}
}
else {
break;
}
if (topFrame != null) {
str.append("[" + type + "] " + topFrame + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
else {
str.append("<unknown>\n"); //$NON-NLS-1$
}
}
Field field;
try {
field = RequestMonitor.class.getDeclaredField("fMonitorBacktrace"); //$NON-NLS-1$
field.setAccessible(true);
field.set(this, str.toString());
} catch (IllegalAccessException e) {
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
}
}
/**
* Utility used by {@link #createMonitorBacktrace()}. Subverts access
* protection.
*/
private static RequestMonitor getMonitor(VMViewerUpdate update) {
try {
Field field = VMViewerUpdate.class.getDeclaredField("fRequestMonitor"); //$NON-NLS-1$
field.setAccessible(true);
return (RequestMonitor) field.get(update);
} catch (IllegalAccessException e) {
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
} catch (ClassCastException e) {
}
return null;
}
/**
* Utility used by {@link #createMonitorBacktrace()}. Subverts access
* protection.
*/
private static RequestMonitor getParentMonitor(RequestMonitor rm) {
try {
Field field = RequestMonitor.class.getDeclaredField("fParentRequestMonitor"); //$NON-NLS-1$
field.setAccessible(true);
return (RequestMonitor) field.get(rm);
} catch (IllegalAccessException e) {
} catch (NoSuchFieldException e) {
}
return null;
}
/**
* Utility used by {@link #createMonitorBacktrace()}. Subverts access
* protection.
*/
private static <T extends DsfExecutable> StackTraceElement getCreatedAtTopFrame(T dsfExecutable) {
try {
Field field_fCreatedAt = DsfExecutable.class.getDeclaredField("fCreatedAt"); //$NON-NLS-1$
field_fCreatedAt.setAccessible(true);
Object obj_fCreatedAt = field_fCreatedAt.get(dsfExecutable);
Class<?> class_StackTraceElement = Class.forName("org.eclipse.cdt.dsf.concurrent.StackTraceWrapper"); //$NON-NLS-1$
Field field_fStackTraceElements = class_StackTraceElement.getDeclaredField("fStackTraceElements"); //$NON-NLS-1$
field_fStackTraceElements.setAccessible(true);
StackTraceElement[] frames = (StackTraceElement[])field_fStackTraceElements.get(obj_fCreatedAt);
if (frames != null && frames.length > 0) {
return frames[0];
}
} catch (IllegalAccessException e) {
} catch (NoSuchFieldException e) {
} catch (ClassNotFoundException e) {
}
return null;
}
}

View file

@ -1,8 +1,9 @@
org.eclipse.cdt.dsf/debug = false
org.eclipse.cdt.dsf/debug/executor = false
org.eclipse.cdt.dsf/debug/executorName =
org.eclipse.cdt.dsf/debug/monitors = false
org.eclipse.cdt.dsf/debugCache = false
org.eclipse.cdt.dsf/debug/session = false
org.eclipse.cdt.dsf/debug/session/listeners = false
org.eclipse.cdt.dsf/debug/session/dispatches = false
org.eclipse.cdt.dsf/debug/session/modelAdapters = false
org.eclipse.cdt.dsf/debug/session/modelAdapters = false

View file

@ -59,7 +59,21 @@ public class DsfExecutable {
* runnables that have not been submitted to the executor.
*/
static boolean DEBUG_EXECUTOR = false;
/**
* Flag indicating that monitor objects should be instrumented. A monitor is
* an object that is usually constructed as an anonymous inner classes and
* is used when making an asynchronous call--one that needs to return some
* result or at least notify its caller when it has completed. These objects
* usually end up getting chained together at runtime, forming what is
* effectively a very disjointed code path. When this trace option is
* enabled, these objects are given a String field at construction time that
* contains the instantiation backtrace. This turns out to be a fairly
* dependable alternative to the standard program stack trace, which is of
* virtually no help when debugging asynchronous, monitor-assisted code.
*/
static boolean DEBUG_MONITORS = false;
/**
* Flag indicating that assertions are enabled. It enables storing of the
* "creator" executable for debugging purposes.
@ -70,6 +84,9 @@ public class DsfExecutable {
assert (ASSERTIONS_ENABLED = true) == true;
DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executor")); //$NON-NLS-1$
DEBUG_MONITORS = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
Platform.getDebugOption("org.eclipse.cdt.dsf/debug/monitors")); //$NON-NLS-1$
}
/**
@ -96,7 +113,7 @@ public class DsfExecutable {
@SuppressWarnings("unchecked")
public DsfExecutable() {
// Use assertion flag (-ea) to jre to avoid affecting performance when not debugging.
if (ASSERTIONS_ENABLED || DEBUG_EXECUTOR) {
if (ASSERTIONS_ENABLED || DEBUG_EXECUTOR || DEBUG_MONITORS) {
// Find the runnable/callable that is currently running.
DefaultDsfExecutor executor = DefaultDsfExecutor.fThreadToExecutorMap.get(Thread.currentThread());
if (executor != null) {

View file

@ -110,6 +110,18 @@ public class RequestMonitor extends DsfExecutable {
private boolean fCanceled = false;
private boolean fDone = false;
/**
* This field is never read by any code; its purpose is strictly to assist
* developers debug DPF code. Developer can select this field in the
* Variables view and see a monitor backtrace in the details pane. See
* {@link DsfExecutable#DEBUG_MONITORS}.
*
* <p>
* This field is set only when tracing is enabled.
*/
@SuppressWarnings("unused")
private String fMonitorBacktrace;
/**
* Constructor with an optional parent monitor.
*
@ -139,6 +151,10 @@ public class RequestMonitor extends DsfExecutable {
}
});
}
if (DEBUG_MONITORS) {
createMonitorBacktrace();
}
}
/**
@ -446,4 +462,24 @@ public class RequestMonitor extends DsfExecutable {
DsfPlugin.getDefault().getLog().log(logStatus);
}
}
/**
* Instrument this object with a backtrace of the monitors this instance is
* chained to. See {@link DsfExecutable#DEBUG_MONITORS}
*/
private void createMonitorBacktrace() {
StringBuilder str = new StringBuilder();
for (RequestMonitor nextrm = this; nextrm != null; nextrm = nextrm.fParentRequestMonitor) {
final StackTraceElement[] stackTraceElems = (nextrm.fCreatedAt != null) ? nextrm.fCreatedAt.fStackTraceElements : null;
if (stackTraceElems != null && stackTraceElems.length > 0)
{
str.append(stackTraceElems[0] + "\n"); //$NON-NLS-1$
}
else {
str.append("<unknown>\n"); //$NON-NLS-1$
}
}
fMonitorBacktrace = str.toString();
}
}