diff --git a/debug/org.eclipse.cdt.debug.core/.options b/debug/org.eclipse.cdt.debug.core/.options new file mode 100644 index 00000000000..6b989a05c85 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/.options @@ -0,0 +1,5 @@ +org.eclipse.cdt.debug.core/debug=false + +# Reports activity on the ExecutablesManager and its client (Executables viewer) +org.eclipse.cdt.debug.core/debug/executables=false + diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugCorePlugin.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugCorePlugin.java index b645f121ca4..6788bcf51d3 100644 --- a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugCorePlugin.java +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/core/CDebugCorePlugin.java @@ -30,6 +30,7 @@ import org.eclipse.cdt.debug.internal.core.DebugConfiguration; import org.eclipse.cdt.debug.internal.core.ICDebugInternalConstants; import org.eclipse.cdt.debug.internal.core.ListenerList; import org.eclipse.cdt.debug.internal.core.SessionManager; +import org.eclipse.cdt.debug.internal.core.Trace; import org.eclipse.cdt.debug.internal.core.disassembly.DisassemblyContextService; import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector; import org.eclipse.cdt.debug.internal.core.sourcelookup.CommonSourceLookupDirector; @@ -339,6 +340,8 @@ public class CDebugCorePlugin extends Plugin { @Override public void start(BundleContext context) throws Exception { super.start(context); + + Trace.init(); initializeCommonSourceLookupDirector(); createCommandAdapterFactory(); createBreakpointListenersList(); diff --git a/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/Trace.java b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/Trace.java new file mode 100644 index 00000000000..d5bd44bea43 --- /dev/null +++ b/debug/org.eclipse.cdt.debug.core/src/org/eclipse/cdt/debug/internal/core/Trace.java @@ -0,0 +1,108 @@ +package org.eclipse.cdt.debug.internal.core; + +import org.eclipse.cdt.debug.core.CDebugCorePlugin; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.osgi.service.debug.DebugOptions; +import org.eclipse.osgi.service.debug.DebugTrace; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * Class for getting a singleton instance of DebugTrace, an extremely useful + * utility for tracing multithreaded code, as each trace statement prints out + * the thread and the time (in millisecond granularity). For performance + * reasons, trace statements should explicitly check a trace flag before calling + * into a DebugTrace method. E.g., + * + *

+ * + * if (Trace.DEBUG_EXECUTABLES) DebugTrace.getTrace.trace(null, ...); + * + * + *

+ * The alternative is to have DebugTrace check the debug option for you (i.e., + * don't pass null for first param), but this incurs a relatively heavy price + * considering the trace statements are present in release code. An advantage of + * asking DebugTrace to do the check is that is that it supports trace options + * changing during the workbench lifetime. However that's an unlikely and + * esoteric scenario. + * + *

+ * This class is also a central location for trace flags. They are public static + * fields, so checking them in trace statements is very efficient. They are set + * at plugin startup. + * + *

+ * DebugTrace objects are particular to a plugin. Plugins can reuse most of this + * class definition. However, since it's all based on static methods and fields, + * reuse means copy-n-paste. Making this not rely on statics would complicate + * things and simplicity and efficiency is what we need most when it comes to + * trace. When making a copy of this class for your plugin, make sure to update + * the Activator class reference (appears three times). Also, the DEBUG_XXXX + * fields will need to be whatever options are used in your plugin. + */ +public class Trace { + // See .options file in plugin for description of these flags. DEBUG is the base option. + public static boolean DEBUG; + public static boolean DEBUG_EXECUTABLES; + + /** + * Use a no-op trace when a real one isn't available. Simplifies life for + * clients; no need to check for null. + */ + private static final DebugTrace NULL_TRACE = new DebugTrace() { + public void trace(String option, String message) {} + public void trace(String option, String message, Throwable error) {} + public void traceDumpStack(String option) {} + public void traceEntry(String option) {} + public void traceEntry(String option, Object methodArgument) {} + public void traceEntry(String option, Object[] methodArguments) {} + public void traceExit(String option) {} + public void traceExit(String option, Object result) {} + }; + + /** Should be called by plugin's startup method() */ + public static void init() { + DEBUG = CDebugCorePlugin.getDefault().isDebugging(); + + String option = Platform.getDebugOption(CDebugCorePlugin.PLUGIN_ID + "/debug/executables"); //$NON-NLS-1$ + DEBUG_EXECUTABLES = DEBUG && ((option != null) ? option.equalsIgnoreCase("true") : false); //$NON-NLS-1$ + } + /** Singleton trace object */ + private static DebugTrace trace; + + /** + * Gets the singleton trace object, or a null trace object if a real one + * isn't available + * + * @return trace object; never null + */ + synchronized public static DebugTrace getTrace() { + if (trace == null) { + Plugin plugin = CDebugCorePlugin.getDefault(); + if (plugin != null) { + Bundle bundle = plugin.getBundle(); + if (bundle != null) { + BundleContext context = bundle.getBundleContext(); + if (context != null) { + ServiceTracker tracker = new ServiceTracker(context, DebugOptions.class.getName(), null); + try { + tracker.open(); + DebugOptions debugOptions = tracker.getService(); + if (debugOptions != null) { + trace = debugOptions.newDebugTrace(bundle.getSymbolicName()); + } + } + finally { + tracker.close(); + } + } + } + } + + } + return trace != null ? trace : NULL_TRACE; + } +}