Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'dsf/org.eclipse.cdt.dsf/src/org')
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java38
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java99
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java50
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java374
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java139
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java23
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java48
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java59
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java108
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java220
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java401
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java682
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java32
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java35
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java43
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java141
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java31
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java92
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java157
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java60
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java22
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java21
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java42
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html26
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java29
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java634
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java505
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java69
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java886
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java36
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java140
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java28
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java91
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java44
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java22
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java231
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java118
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java51
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java118
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java34
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java100
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java181
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java208
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java127
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java25
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java39
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java111
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java49
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java42
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java54
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java248
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java549
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java45
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java72
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java67
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java64
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java27
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java23
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java19
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java39
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java229
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java100
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java222
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java43
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java41
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java169
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java431
-rw-r--r--dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java99
71 files changed, 9507 insertions, 0 deletions
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java
new file mode 100644
index 00000000000..27452c25061
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ConfinedToDsfExecutor.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given package, class, method, or field can be
+ * access safely only from a DSF executor thread. If declared on package or type,
+ * a field or method could still be declared with an annotation indicating that it's
+ * thread-safe.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ *
+ * @param value The value indicates the method to use to obtain the executor.
+ * It should be null if it cannot be determined from the given object.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
+@Inherited
+@Documented
+public @interface ConfinedToDsfExecutor {
+ String value();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java
new file mode 100644
index 00000000000..ea9fa9d6c72
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/CountingRequestMonitor.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+
+/**
+ * Utility class to collect multiple request monitor results of commands
+ * that are initiated simultaneously. The usage is as follows:
+ * <code><pre>
+ * final CountingRequestMonitor countingRm = new CountingRequestMonitor(fExecutor, null) {
+ * public void handleCompleted() {
+ * System.out.println("All complete, errors=" + !getStatus().isOK());
+ * }
+ * };
+ *
+ * int count = 0;
+ * for (int i : elements) {
+ * service.call(i, countingRm);
+ * count++;
+ * }
+ *
+ * countingRm.setDoneCount(count);
+ * </pre></code>
+ */
+public class CountingRequestMonitor extends RequestMonitor {
+ /**
+ * Counter tracking the remaining number of times that the done() method
+ * needs to be called before this request monitor is actually done.
+ */
+ private int fDoneCounter;
+
+ /**
+ * Flag indicating whether the initial count has been set on this monitor.
+ */
+ private boolean fInitialCountSet = false;
+
+ public CountingRequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ super(executor, parentRequestMonitor);
+ super.setStatus(new MultiStatus(DsfPlugin.PLUGIN_ID, 0, "Collective status for set of sub-operations.", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Sets the number of times that this request monitor needs to be called
+ * before this monitor is truly considered done. This method must be called
+ * exactly once in the life cycle of each counting request monitor.
+ * @param count Number of times that done() has to be called to mark the request
+ * monitor as complete. If count is '0', then the counting request monitor is
+ * marked as done immediately.
+ */
+ public synchronized void setDoneCount(int count) {
+ assert !fInitialCountSet;
+ fInitialCountSet = true;
+ fDoneCounter += count;
+ if (fDoneCounter <= 0) {
+ assert fDoneCounter == 0; // Mismatch in the count.
+ super.done();
+ }
+ }
+
+ /**
+ * Called to indicate that one of the calls using this monitor is finished.
+ * Only when <code>done</done> is called the number of times corresponding to the
+ * count, the request monitor will be considered complete. This method can be
+ * called before {@link #setDoneCount(int)}.
+ */
+ @Override
+ public synchronized void done() {
+ fDoneCounter--;
+ if (fInitialCountSet && fDoneCounter <= 0) {
+ assert fDoneCounter == 0; // Mismatch in the count.
+ super.done();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "CountingRequestMonitor: " + getStatus().toString(); //$NON-NLS-1$
+ }
+
+ @Override
+ public synchronized void setStatus(IStatus status) {
+ if ((getStatus() instanceof MultiStatus)) {
+ ((MultiStatus)getStatus()).add(status);
+ }
+ };
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java
new file mode 100644
index 00000000000..58daf516459
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DataRequestMonitor.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+
+/**
+ * Request monitor that allows data to be returned to the request initiator.
+ *
+ * @param V The type of the data object that this monitor handles.
+ */
+public class DataRequestMonitor<V> extends RequestMonitor {
+
+ /** Data object reference */
+ private V fData;
+
+ public DataRequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ super(executor, parentRequestMonitor);
+ }
+
+ /**
+ * Sets the data object to specified value. To be called by the
+ * asynchronous method implementor.
+ * @param data Data value to set.
+ */
+ public synchronized void setData(V data) { fData = data; }
+
+ /**
+ * Returns the data value, null if not set.
+ */
+ public synchronized V getData() { return fData; }
+
+ @Override
+ public String toString() {
+ if (getData() != null) {
+ return getData().toString();
+ } else {
+ return super.toString();
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java
new file mode 100644
index 00000000000..e2c7efc5642
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DefaultDsfExecutor.java
@@ -0,0 +1,374 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Future;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.ILog;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Default implementation of a DSF executor interfaces, based on the
+ * standard java.util.concurrent.ThreadPoolExecutor.
+ */
+
+public class DefaultDsfExecutor extends ScheduledThreadPoolExecutor
+ implements DsfExecutor
+{
+ /**
+ * Instance counter for DSF executors. Used in the executor's thread name.
+ */
+ private static int fgInstanceCounter = 0;
+
+ /**
+ * Name of the executor, used in the executor's thread name.
+ */
+ private String fName;
+
+ /**
+ * Instance number of this executor, used with the executor name.
+ */
+ private int fInstanceNumber;
+
+ /** Thread factory that creates the single thread to be used for this executor */
+ static class DsfThreadFactory implements ThreadFactory {
+ private String fThreadName;
+ DsfThreadFactory(String name) {
+ fThreadName = name;
+ }
+
+ Thread fThread;
+ public Thread newThread(Runnable r) {
+ assert fThread == null; // Should be called only once.
+ fThread = new Thread(new ThreadGroup(fThreadName), r, fThreadName, 0);
+ return fThread;
+ }
+ }
+
+ public DefaultDsfExecutor() {
+ this("DSF Executor"); //$NON-NLS-1$
+ }
+
+ /**
+ * Creates a new DSF Executor with the given name.
+ * @param name Name used to create executor's thread.
+ */
+ public DefaultDsfExecutor(String name) {
+ super(1, new DsfThreadFactory(name + " - " + fgInstanceCounter)); //$NON-NLS-1$
+ fName = name;
+ fInstanceNumber = fgInstanceCounter++;
+
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ // If tracing, pre-start the dispatch thread, and add it to the map.
+ prestartAllCoreThreads();
+ fThreadToExecutorMap.put(((DsfThreadFactory)getThreadFactory()).fThread, DefaultDsfExecutor.this);
+ }
+ }
+
+ public boolean isInExecutorThread() {
+ return Thread.currentThread().equals( ((DsfThreadFactory)getThreadFactory()).fThread );
+ }
+
+ protected String getName() {
+ return fName;
+ }
+
+ static void logException(Throwable t) {
+ DsfPlugin plugin = DsfPlugin.getDefault();
+ if (plugin == null) return;
+
+ ILog log = plugin.getLog();
+ if (log != null) {
+ log.log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Uncaught exception in DSF executor thread", t)); //$NON-NLS-1$
+ }
+ // Print out the stack trace to console if assertions are enabled.
+ if(ASSERTIONS_ENABLED) {
+ ByteArrayOutputStream outStream = new ByteArrayOutputStream(512);
+ PrintStream printStream = new PrintStream(outStream);
+ try {
+ printStream.write("Uncaught exception in session executor thread: ".getBytes()); //$NON-NLS-1$
+ } catch (IOException e2) {}
+ t.printStackTrace(new PrintStream(outStream));
+ System.err.println(outStream.toString());
+ }
+ }
+
+ //
+ // Utilities used for tracing.
+ //
+ protected static boolean DEBUG_EXECUTOR = false;
+ protected static String DEBUG_EXECUTOR_NAME = ""; //$NON-NLS-1$
+ protected static boolean ASSERTIONS_ENABLED = false;
+ static {
+ DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executor")); //$NON-NLS-1$
+ DEBUG_EXECUTOR_NAME = DsfPlugin.DEBUG
+ ? Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executorName") : ""; //$NON-NLS-1$ //$NON-NLS-2$
+ assert (ASSERTIONS_ENABLED = true) == true;
+ }
+
+ /**
+ * This map is used by DsfRunnable/Query/DsfCallable to track by which executor
+ * an executable object was created.
+ * <br>Note: Only used when tracing.
+ */
+ static Map<Thread, DefaultDsfExecutor> fThreadToExecutorMap = new HashMap<Thread, DefaultDsfExecutor>();
+
+ /**
+ * Currently executing runnable/callable.
+ * <br>Note: Only used when tracing.
+ */
+ TracingWrapper fCurrentlyExecuting;
+
+ /**
+ * Counter number saved by each tracing runnable when executed
+ * <br>Note: Only used when tracing.
+ */
+ int fSequenceCounter;
+
+ /**
+ * Wrapper for runnables/callables, is used to store tracing information
+ * <br>Note: Only used when tracing.
+ */
+ abstract class TracingWrapper {
+ /** Sequence number of this runnable/callable */
+ int fSequenceNumber = -1;
+
+ /** Trace of where the runnable/callable was submitted to the executor */
+ StackTraceWrapper fSubmittedAt = null;
+
+ /** Reference to the runnable/callable that submitted this runnable/callable to the executor */
+ TracingWrapper fSubmittedBy = null;
+
+ /**
+ * @param offset the number of items in the stack trace not to be printed
+ */
+ TracingWrapper(int offset) {
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ // guard against the offset being greater than the stack trace
+ offset = Math.min(offset, stackTrace.length);
+ fSubmittedAt = new StackTraceWrapper(new StackTraceElement[stackTrace.length - offset]);
+ System.arraycopy(stackTrace, offset - 1, fSubmittedAt.fStackTraceElements, 0, fSubmittedAt.fStackTraceElements.length);
+ if (isInExecutorThread() && fCurrentlyExecuting != null) {
+ fSubmittedBy = fCurrentlyExecuting;
+ }
+ }
+
+ void traceExecution() {
+ fSequenceNumber = fSequenceCounter++;
+ fCurrentlyExecuting = this;
+
+ // Write to console only if tracing is enabled (as opposed to tracing or assertions).
+ if (DEBUG_EXECUTOR && ("".equals(DEBUG_EXECUTOR_NAME) || fName.equals(DEBUG_EXECUTOR_NAME))) { //$NON-NLS-1$
+ StringBuilder traceBuilder = new StringBuilder();
+
+ // Record the time
+ traceBuilder.append(DsfPlugin.getDebugTime());
+ traceBuilder.append(' ');
+
+ // Record the executor #
+ traceBuilder.append('#');
+ traceBuilder.append(fSequenceNumber);
+
+ // Record the executor name
+ traceBuilder.append('(');
+ traceBuilder.append(fName);
+ traceBuilder.append(" - "); //$NON-NLS-1$
+ traceBuilder.append(fInstanceNumber);
+ traceBuilder.append(')');
+ traceBuilder.append(' ');
+
+ // Append executable class name
+ traceBuilder.append(getExecutable().getClass().getName());
+
+ // Add executable's toString().
+ traceBuilder.append("\n "); //$NON-NLS-1$
+ traceBuilder.append(getExecutable().toString());
+
+ // Append "create by" info.
+ if (getExecutable() instanceof DsfExecutable) {
+ DsfExecutable dsfExecutable = (DsfExecutable)getExecutable();
+ if (dsfExecutable.fCreatedAt != null || dsfExecutable.fCreatedBy != null) {
+ traceBuilder.append("\n created "); //$NON-NLS-1$
+ if (dsfExecutable.fCreatedBy != null) {
+ traceBuilder.append(" by #"); //$NON-NLS-1$
+ traceBuilder.append(dsfExecutable.fCreatedBy.fSequenceNumber);
+ }
+ if (dsfExecutable.fCreatedAt != null) {
+ traceBuilder.append("\n at "); //$NON-NLS-1$
+ traceBuilder.append(dsfExecutable.fCreatedAt.fStackTraceElements[0].toString());
+ for (int i = 1; i < dsfExecutable.fCreatedAt.fStackTraceElements.length && i < 3; i++) {
+ traceBuilder.append("\n "); //$NON-NLS-1$
+ traceBuilder.append(dsfExecutable.fCreatedAt.fStackTraceElements[i].toString());
+ }
+ }
+ }
+ }
+
+ // Submitted info
+ traceBuilder.append("\n submitted"); //$NON-NLS-1$
+ if (fSubmittedBy != null) {
+ traceBuilder.append(" by #"); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedBy.fSequenceNumber);
+ }
+ traceBuilder.append("\n at "); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedAt.fStackTraceElements[0].toString());
+ for (int i = 1; i < fSubmittedAt.fStackTraceElements.length && i < 3; i++) {
+ traceBuilder.append("\n "); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedAt.fStackTraceElements[i].toString());
+ }
+ traceBuilder.append(" at "); //$NON-NLS-1$
+ traceBuilder.append(fSubmittedAt.fStackTraceElements[0].toString());
+
+ // Finally write out to console
+ DsfPlugin.debug(traceBuilder.toString());
+ }
+ }
+
+ abstract protected Object getExecutable();
+ }
+
+
+ class TracingWrapperRunnable extends TracingWrapper implements Runnable {
+ final Runnable fRunnable;
+ public TracingWrapperRunnable(Runnable runnable, int offset) {
+ super(offset);
+ if (runnable == null) throw new NullPointerException();
+ fRunnable = runnable;
+
+ // Check if executable wasn't executed already.
+ if (DEBUG_EXECUTOR && fRunnable instanceof DsfExecutable) {
+ assert !((DsfExecutable)fRunnable).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
+ ((DsfExecutable)fRunnable).setSubmitted();
+ }
+ }
+
+ @Override
+ protected Object getExecutable() { return fRunnable; }
+
+ public void run() {
+ traceExecution();
+
+ // Finally invoke the runnable code.
+ try {
+ fRunnable.run();
+ } catch (RuntimeException e) {
+ // If an exception was thrown in the Runnable, trace it.
+ // Because there is no one else to catch it, it is a
+ // programming error.
+ logException(e);
+ throw e;
+ }
+ }
+ }
+
+ public class TracingWrapperCallable<T> extends TracingWrapper implements Callable<T> {
+ final Callable<T> fCallable;
+ public TracingWrapperCallable(Callable<T> callable, int offset) {
+ super(offset);
+ if (callable == null) throw new NullPointerException();
+ fCallable = callable;
+ }
+
+ @Override
+ protected Object getExecutable() { return fCallable; }
+
+ public T call() throws Exception {
+ traceExecution();
+
+ // Finally invoke the runnable code.
+ // Note that callables can throw exceptions that can be caught
+ // by clients that invoked them using ExecutionException.
+ return fCallable.call();
+ }
+ }
+
+ @Override
+ public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ if ( !(callable instanceof TracingWrapper) ) {
+ callable = new TracingWrapperCallable<V>(callable, 6);
+ }
+ }
+ return super.schedule(callable, delay, unit);
+ }
+ @Override
+ public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ if ( !(command instanceof TracingWrapper) ) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ }
+ return super.schedule(command, delay, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.scheduleAtFixedRate(command, initialDelay, period, unit);
+ }
+
+ @Override
+ public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.scheduleWithFixedDelay(command, initialDelay, delay, unit);
+ }
+
+ @Override
+ public void execute(Runnable command) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ super.execute(command);
+ }
+
+ @Override
+ public Future<?> submit(Runnable command) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.submit(command);
+ }
+
+ @Override
+ public <T> Future<T> submit(Callable<T> callable) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ callable = new TracingWrapperCallable<T>(callable, 6);
+ }
+ return super.submit(callable);
+ }
+
+ @Override
+ public <T> Future<T> submit(Runnable command, T result) {
+ if(DEBUG_EXECUTOR || ASSERTIONS_ENABLED) {
+ command = new TracingWrapperRunnable(command, 6);
+ }
+ return super.submit(command, result);
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java
new file mode 100644
index 00000000000..52d1d43dd25
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutable.java
@@ -0,0 +1,139 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Base class for DSF-instrumented alternative to the Runnable/Callable interfaces.
+ * <p>
+ * While it is perfectly fine for clients to call the DSF executor with
+ * an object only implementing the Runnable/Callable interface, the DsfExecutable
+ * contains fields and methods that used for debugging and tracing when
+ * tracing is enabled.
+ */
+@Immutable
+public class DsfExecutable {
+ /**
+ * Flag indicating that tracing of the DSF executor is enabled. It enables
+ * storing of the "creator" information as well as tracing of disposed
+ * runnables that have not been submitted to the executor.
+ */
+ static boolean DEBUG_EXECUTOR = false;
+
+ /**
+ * Flag indicating that assertions are enabled. It enables storing of the
+ * "creator" executable for debugging purposes.
+ */
+ static boolean ASSERTIONS_ENABLED = false;
+
+ static {
+ 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$
+ }
+
+ /**
+ * Field that holds the stack trace of where this executable was created.
+ * Used for tracing and debugging only.
+ */
+ final StackTraceWrapper fCreatedAt;
+
+ /**
+ * Field holding the reference of the executable that created this
+ * executable. Used for tracing only.
+ */
+ final DefaultDsfExecutor.TracingWrapper fCreatedBy;
+
+ /**
+ * Flag indicating whether this executable was ever executed by an
+ * executor. Used for tracing only.
+ */
+ private volatile boolean fSubmitted = false;
+
+ @SuppressWarnings("unchecked")
+ public DsfExecutable() {
+ // Use assertion flag (-ea) to jre to avoid affecting performance when not debugging.
+ if (ASSERTIONS_ENABLED || DEBUG_EXECUTOR) {
+ // Find the runnable/callable that is currently running.
+ DefaultDsfExecutor executor = DefaultDsfExecutor.fThreadToExecutorMap.get(Thread.currentThread());
+ if (executor != null) {
+ fCreatedBy = executor.fCurrentlyExecuting;
+ } else {
+ fCreatedBy = null;
+ }
+
+ // Get the stack trace and find the first method that is not a
+ // constructor of this object.
+ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+ Class thisClass = getClass();
+ Set<String> classNamesSet = new HashSet<String>();
+ while(thisClass != null) {
+ classNamesSet.add(thisClass.getName());
+ thisClass = thisClass.getSuperclass();
+ }
+ int i;
+ for (i = 3; i < stackTrace.length; i++) {
+ if ( !classNamesSet.contains(stackTrace[i].getClassName()) ) break;
+ }
+ fCreatedAt = new StackTraceWrapper(new StackTraceElement[stackTrace.length - i]);
+ System.arraycopy(stackTrace, i, fCreatedAt.fStackTraceElements, 0, fCreatedAt.fStackTraceElements.length);
+ } else {
+ fCreatedAt = null;
+ fCreatedBy = null;
+ }
+ }
+
+ public boolean getSubmitted() {
+ return fSubmitted;
+ }
+
+ /**
+ * Marks this executable to indicate that it has been executed by the
+ * executor. To be invoked only by DsfExecutor.
+ */
+ public void setSubmitted() {
+ fSubmitted = true;
+ }
+
+ /**
+ * Returns whether the runnable/callable is expected to be always executed.
+ * Overriding classes can implement this method and return false, to avoid
+ * unnecessary trace output.
+ * @return true if this runnable is expected to run.
+ */
+ protected boolean isExecutionRequired() {
+ return true;
+ }
+
+ @Override
+ protected void finalize() {
+ if (DEBUG_EXECUTOR && !fSubmitted && isExecutionRequired()) {
+ StringBuilder traceBuilder = new StringBuilder();
+
+ // Record the time
+ traceBuilder.append(DsfPlugin.getDebugTime());
+ traceBuilder.append(' ');
+
+ // Record the event
+ traceBuilder.append("DsfExecutable was never executed:\n "); //$NON-NLS-1$
+ traceBuilder.append(this);
+ traceBuilder.append("\nCreated at:"); //$NON-NLS-1$
+ traceBuilder.append(fCreatedAt);
+
+ DsfPlugin.debug(traceBuilder.toString());
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java
new file mode 100644
index 00000000000..8c7cd554bc2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfExecutor.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.ScheduledExecutorService;
+
+/**
+ * DSF executor service. Implementations of this executor must ensure
+ * that all runnables and callables are executed in the same thread: the
+ * executor's single dispatch thread.
+ * <br>Note: A DSF executor dispatch thread does not necessarily have
+ * to be exclusive to the executor, it could be shared with
+ * another event dispatch service, such as the SWT display dispatch thread.
+ */
+@ThreadSafe
+public interface DsfExecutor extends ScheduledExecutorService
+{
+ /**
+ * Checks if the thread that this method is called in is the same as the
+ * executor's dispatch thread.
+ * @return true if in DSF executor's dispatch thread
+ */
+ public boolean isInExecutorThread();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java
new file mode 100644
index 00000000000..f315288668a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/DsfRunnable.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+
+/**
+ * A DSF-instrumented alternative to the Runnable interface.
+ * <p>
+ * While it is perfectly fine for clients to call the DSF executor with
+ * an object only implementing the Runnable interface, the DsfRunnable
+ * contains fields and methods that used for debugging and tracing when
+ * tracing is enabled.
+ */
+abstract public class DsfRunnable extends DsfExecutable implements Runnable {
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java
new file mode 100644
index 00000000000..d7be9a7ad67
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/IDsfStatusConstants.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+/**
+ * Interface that hold the codes used when reporting status using the DSF
+ * Request Monitor.
+ */
+public interface IDsfStatusConstants {
+ /**
+ * Error code indicating that the service is in a state which does not allow the
+ * request to be processed. For example if the client requested target information
+ * after target was disconnected.
+ */
+ final static int INVALID_STATE = 10001;
+
+ /**
+ * Error code indicating that client supplied an invalid handle to the service.
+ * A handle could become invalid after an object it represents is removed from
+ * the system.
+ */
+ final static int INVALID_HANDLE = 10002;
+
+ /**
+ * Error code indicating that the client request is not supported/implemented.
+ */
+ final static int NOT_SUPPORTED = 10003;
+
+ /**
+ * Error code indicating that the request to a sub-service or an external process
+ * failed.
+ */
+ final static int REQUEST_FAILED = 10004;
+
+ /**
+ * Error code indicating an unexpected condition in the service, i.e. programming error.
+ */
+ final static int INTERNAL_ERROR = 10005;
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java
new file mode 100644
index 00000000000..6176514e775
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ImmediateExecutor.java
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.Platform;
+
+/**
+ * Executor that executes a runnable immediately as it is submitted. This
+ * executor is useful for clients that need to create <code>RequestMonitor</code>
+ * objects, but which do not have their own executor.
+ * @see RequestMonitor
+ */
+public class ImmediateExecutor implements Executor {
+
+ /**
+ * Debug flag used for tracking runnables that were never executed,
+ * or executed multiple times.
+ */
+ protected static boolean DEBUG_EXECUTOR = false;
+ static {
+ DEBUG_EXECUTOR = DsfPlugin.DEBUG && "true".equals( //$NON-NLS-1$
+ Platform.getDebugOption("org.eclipse.cdt.dsf/debug/executor")); //$NON-NLS-1$
+ }
+
+ private static ImmediateExecutor fInstance = new ImmediateExecutor();
+
+ /**
+ * The default constructor is hidden. {@link #getInstance()} should be
+ * used instead.
+ */
+ private ImmediateExecutor() {}
+
+ /**
+ * Returns the singleton instance of ImmediateExecutor.
+ */
+ public static Executor getInstance() {
+ return fInstance;
+ }
+
+ public void execute(Runnable command) {
+ // Check if executable wasn't executed already.
+ if (DEBUG_EXECUTOR && command instanceof DsfExecutable) {
+ assert !((DsfExecutable)command).getSubmitted() : "Executable was previously executed."; //$NON-NLS-1$
+ ((DsfExecutable)command).setSubmitted();
+ }
+ command.run();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java
new file mode 100644
index 00000000000..a336b893792
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Immutable.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given class is immutable and thus thread-safe.
+ * This annotation is not automatically inherited by sub-classes, since
+ * sub-classes need to make sure that they are immutable as well.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+@Documented
+public @interface Immutable {
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java
new file mode 100644
index 00000000000..ba127835243
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/MultiRequestMonitor.java
@@ -0,0 +1,108 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.MultiStatus;
+
+/**
+ * Utility class to collect multiple request monitor results of commands
+ * that are initiated simultaneously. The usage is as follows:
+ * <pre>
+ * final MultiRequestMonitor multiRequestMon = new MultiRequestMonitor(fExecutor, null) {
+ * public void handleCompleted() {
+ * System.out.println("All complete, errors=" + !getStatus().isOK());
+ * }
+ * };
+ *
+ * for (int i = 0; i < 10; i++) {
+ * service.call(i, multiRequestMon.addRequestMonitor(
+ * new RequestMonitor(fExecutor, null) {
+ * public void handleCompleted() {
+ * System.out.println(Integer.toString(i) + " complete");
+ * multiRequestMon.requestMonitorDone(this);
+ * }
+ * }));
+ * }
+ * </pre>
+ */
+public class MultiRequestMonitor<V extends RequestMonitor> extends RequestMonitor {
+ private List<V> fRequestMonitorList = new LinkedList<V>();
+ private Map<V,Boolean> fStatusMap = new HashMap<V,Boolean>();
+ private int fDoneCounter;
+
+ public MultiRequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ super(executor, parentRequestMonitor);
+ setStatus(new MultiStatus(DsfPlugin.PLUGIN_ID, 0, "Collective status for set of sub-operations.", null)); //$NON-NLS-1$
+ }
+
+ /**
+ * Adds a new RequestMonitor callback to this tracker's list.
+ * @param <T> Client-specific class of the RequestMonitor callback, it's used here to avoid an
+ * unnecessary cast by the client.
+ * @param rm Request monitor object to add to the tracker
+ * @return The request monitor that was just added, it allows this method to be used
+ * inlined in service method calls
+ */
+ public <T extends V> T add(T rm) {
+ assert !fStatusMap.containsKey(rm);
+ fRequestMonitorList.add(rm);
+ fStatusMap.put(rm, false);
+ fDoneCounter++;
+ return rm;
+ }
+
+ /**
+ * Marks the given RequestMonitor callback as completed. Client implementations of
+ * the RequestMonitor callback have to call this method in order for the tracker
+ * to complete.
+ * <br>
+ * @param requestMonitor
+ */
+ public synchronized void requestMonitorDone(V requestMonitor) {
+ if (getStatus() instanceof MultiStatus) {
+ ((MultiStatus)getStatus()).merge(requestMonitor.getStatus());
+ }
+ assert fStatusMap.containsKey(requestMonitor);
+ fStatusMap.put(requestMonitor, true);
+ assert fDoneCounter > 0;
+ fDoneCounter--;
+ if (fDoneCounter == 0) {
+ assert !fStatusMap.containsValue(false);
+ super.done();
+ }
+ }
+
+ /**
+ * Returns the list of requested monitors, sorted in order as they were added.
+ */
+ public List<V> getRequestMonitors() {
+ return fRequestMonitorList;
+ }
+
+ /**
+ * Returns true if given monitor is finished.
+ */
+ public boolean isRequestMonitorDone(V rm) {
+ return fStatusMap.get(rm);
+ }
+
+ @Override
+ public String toString() {
+ return "Multi-RequestMonitor: " + getStatus().toString(); //$NON-NLS-1$
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java
new file mode 100644
index 00000000000..eff2c70c5b4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Query.java
@@ -0,0 +1,220 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+import org.eclipse.core.runtime.CoreException;
+
+
+/**
+ * A convenience class that allows a client to retrieve data from services
+ * synchronously from a non-dispatch thread. This class is different from
+ * a Callable<V> in that it allows the implementation code to calculate
+ * the result in several dispatches, rather than requiring it to return the
+ * data at end of Callable#call method.
+ * <p>
+ * Usage:<br/>
+ * <pre>
+ * class DataQuery extends Query<Data> {
+ * protected void execute(DataRequestMonitor<Data> rm) {
+ * rm.setData(fSlowService.getData());
+ * rm.done();
+ * }
+ * }
+ *
+ * DsfExecutor executor = getExecutor();
+ * DataQuery query = new DataQuery();
+ * executor.submit(query);
+ *
+ * try {
+ * Data data = query.get();
+ * }
+ *
+ * </pre>
+ * <p>
+ * @see java.util.concurrent.Callable
+ */
+@ThreadSafe
+abstract public class Query<V> extends DsfRunnable
+ implements Future<V>
+{
+ /** The synchronization object for this query */
+ private final Sync fSync = new Sync();
+
+ /**
+ * The Query constructor no longer requires an executor to be specified.
+ * This executor was used to contruct the DataRequestMonitor argument to the
+ * {@link #execute(DataRequestMonitor)} method. But a simplification in the
+ * RequestMonitor object, made this unnecessary.
+ * @param executor
+ */
+ @Deprecated
+ public Query(DsfExecutor executor) {
+ }
+
+ /**
+ * The no-argument constructor
+ */
+ public Query() {}
+
+ public V get() throws InterruptedException, ExecutionException { return fSync.doGet(); }
+
+ public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ return fSync.doGet(unit.toNanos(timeout));
+ }
+
+ /**
+ * Don't try to interrupt the DSF executor thread, just ignore the request
+ * if set.
+ */
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ return fSync.doCancel();
+ }
+
+ public boolean isCancelled() { return fSync.doIsCancelled(); }
+
+ public boolean isDone() { return fSync.doIsDone(); }
+
+
+ protected void doneException(Throwable t) {
+ fSync.doSetException(t);
+ }
+
+ abstract protected void execute(DataRequestMonitor<V> rm);
+
+ public void run() {
+ if (fSync.doRun()) {
+ try {
+ /*
+ * Create the executor which is going to handle the completion of the
+ * request monitor. Normally a DSF executor is supplied here which
+ * causes the request monitor to be invoked in a new dispatch loop.
+ * But since the query is a synchronization object, it can handle
+ * the completion of the request in any thread.
+ * Avoiding the use of a DSF executor is very useful because queries are
+ * meant to be used by clients calling from non-dispatch thread, and there
+ * is a chance that a client may execute a query just as a session is being
+ * shut down. In that case, the DSF executor may throw a
+ * RejectedExecutionException which would have to be handled by the query.
+ */
+ execute(new DataRequestMonitor<V>(ImmediateExecutor.getInstance(), null) {
+ @Override
+ public void handleCompleted() {
+ if (isSuccess()) fSync.doSet(getData());
+ else fSync.doSetException(new CoreException(getStatus()));
+ }
+ });
+ } catch(Throwable t) {
+ /*
+ * Catching the exception here will only work if the exception
+ * happens within the execute. It will not work in cases when
+ * the execute submits other runnables, and the other runnables
+ * encounter the exception.
+ */
+ fSync.doSetException(t);
+
+ /*
+ * Since we caught the exception, it will not be logged by
+ * DefaultDsfExecutable.afterExecution(). So log it here.
+ */
+ DefaultDsfExecutor.logException(t);
+ }
+ }
+ }
+
+ @SuppressWarnings("serial")
+ final class Sync extends AbstractQueuedSynchronizer {
+ private static final int STATE_RUNNING = 1;
+ private static final int STATE_DONE = 2;
+ private static final int STATE_CANCELLED = 4;
+
+ private V fResult;
+ private Throwable fException;
+
+ private boolean ranOrCancelled(int state) {
+ return (state & (STATE_DONE | STATE_CANCELLED)) != 0;
+ }
+
+ @Override
+ protected int tryAcquireShared(int ignore) {
+ return doIsDone()? 1 : -1;
+ }
+
+ @Override
+ protected boolean tryReleaseShared(int ignore) {
+ return true;
+ }
+
+ boolean doIsCancelled() {
+ return getState() == STATE_CANCELLED;
+ }
+
+ boolean doIsDone() {
+ return ranOrCancelled(getState());
+ }
+
+ V doGet() throws InterruptedException, ExecutionException {
+ acquireSharedInterruptibly(0);
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ return fResult;
+ }
+
+ V doGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
+ if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException();
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ return fResult;
+ }
+
+ void doSet(V v) {
+ while(true) {
+ int s = getState();
+ if (ranOrCancelled(s)) return;
+ if (compareAndSetState(s, STATE_DONE)) break;
+ }
+ fResult = v;
+ releaseShared(0);
+ }
+
+ void doSetException(Throwable t) {
+ while(true) {
+ int s = getState();
+ if (ranOrCancelled(s)) return;
+ if (compareAndSetState(s, STATE_DONE)) break;
+ }
+ fException = t;
+ fResult = null;
+ releaseShared(0);
+ }
+
+ boolean doCancel() {
+ while(true) {
+ int s = getState();
+ if (ranOrCancelled(s)) return false;
+ if (compareAndSetState(s, STATE_CANCELLED)) break;
+ }
+ releaseShared(0);
+ return true;
+ }
+
+ boolean doRun() {
+ return compareAndSetState(0, STATE_RUNNING);
+ }
+ }
+}
+
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java
new file mode 100644
index 00000000000..ac5b466e94e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitor.java
@@ -0,0 +1,401 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * Used to monitor the result of an asynchronous request. Because of the
+ * asynchronous nature of DSF code, a very large number of methods needs to
+ * signal the result of an operation through a call-back. This class is the base
+ * class for such call backs.
+ * <p>
+ * The intended use of this class, is that a client who is calling an asynchronous
+ * method, will sub-class RequestMonitor, and implement the method {@link #handleCompleted()},
+ * or any of the other <code>handle...</code> methods, in order to interpret the
+ * results of the request. The object implementing the asynchronous method is required
+ * to call the {@link #done()} method on the request monitor object that it received
+ * as an argument.
+ * </p>
+ * <p>
+ * The severity of the {@link IStatus> returned by #getStatus() can be used to
+ * determine the success or failure of the asynchronous operation. By convention
+ * the error codes returned by asynchronous method should be interpreted as follows:
+ * <ul>
+ * <li>OK and INFO - Result is a success. In DataRequestMonitor, getData() should
+ * return a value.</li>
+ * <li>WARNING - Acceptable error condition (getData() may return null). Where for
+ * example user tried to retrieve variable data, but the program resumed in the
+ * mean time and an event will be generated shortly which will clear the variables
+ * view.</li>
+ * <li>ERROR - An error condition that should probably be reported to the user.</li>
+ * <li>CANCEL - The request was canceled, and the asynchronous method was not
+ * completed.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * The RequestMonitor constructor accepts an optional "parent" request monitor. If a
+ * parent monitor is specified, it will automatically be invoked by this monitor when
+ * the request is completed. The parent option is useful when implementing a method
+ * which is asynchronous (and accepts a request monitor as an argument) and which itself
+ * calls another asynchronous method to complete its operation. For example, in the
+ * request monitor implementation below, the implementation only needs to override
+ * <code>handleOK()</code>, because the base implementation will handle notifying the
+ * parent <code>rm</code> in case the <code>getIngredients()</code> call fails.
+ * <pre>
+ * public void createCupCakes(final DataRequestMonitor<CupCake[]> rm) {
+ * getIngredients(new DataRequestMonitor<Ingredients>(fExecutor, rm) {
+ * public void handleOK() {
+ * rm.setData( new CupCake(getData().getFlour(), getData().getSugar(),
+ * getData().getBakingPowder()));
+ * rm.done();
+ * }
+ * });
+ * }
+ * </pre>
+ * </p>
+ */
+@ThreadSafe
+public class RequestMonitor {
+
+ /**
+ * Interface used by RequestMonitor to notify when a given request monitor
+ * is canceled.
+ *
+ * @see RequestMonitor
+ */
+ public static interface ICanceledListener {
+
+ /**
+ * Called when the given request monitor is canceled.
+ */
+ public void requestCanceled(RequestMonitor rm);
+ }
+
+ /**
+ * The executor that will be used in order to invoke the handler of the results
+ * of the request.
+ */
+ private final Executor fExecutor;
+
+ /**
+ * The request monitor which was used to call into the method that created this
+ * monitor.
+ */
+ private final RequestMonitor fParentRequestMonitor;
+
+ private ListenerList fCancelListeners;
+
+ /**
+ * Status
+ */
+ private IStatus fStatus = Status.OK_STATUS;
+ private boolean fCanceled = false;
+ private boolean fDone = false;
+
+ /**
+ * Constructor with an optional parent monitor.
+ * @param executor This executor will be used to invoke the runnable that
+ * will allow processing the completion code of this request monitor.
+ * @param parentRequestMonitor The optional parent request monitor to be invoked by
+ * default when this request completes. Parameter may be null.
+ */
+ public RequestMonitor(Executor executor, RequestMonitor parentRequestMonitor) {
+ fExecutor = executor;
+ fParentRequestMonitor = parentRequestMonitor;
+
+ // If the parent rm is not null, add ourselves as a listener so that
+ // this request monitor will automatically be canceled when the parent
+ // is canceled.
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.addCancelListener(
+ new ICanceledListener() {
+ public void requestCanceled(RequestMonitor rm) {
+ cancel();
+ }
+ });
+ }
+ }
+
+ /**
+ * Sets the status of the result of the request. If status is OK, this
+ * method does not need to be called.
+ */
+ public synchronized void setStatus(IStatus status) {
+ assert isCanceled() || status.getSeverity() != IStatus.CANCEL;
+ fStatus = status;
+ }
+
+ /** Returns the status of the completed method. */
+ public synchronized IStatus getStatus() {
+ if (isCanceled()) {
+ return Status.CANCEL_STATUS;
+ }
+ return fStatus;
+ }
+
+ /**
+ * Sets this request monitor as canceled and calls the cancel listeners if any.
+ * <p>
+ * Note: Calling cancel() does not automatically complete the RequestMonitor.
+ * The asynchronous call still has to call done().
+ * </p>
+ * <p>
+ * Note: logically a request should only be canceled by the client that issued
+ * the request in the first place. After a request is canceled, the method
+ * that is fulfilling the request may call {@link #setStatus(IStatus)} with
+ * severity of <code>IStatus.CANCEL</code> to indicate that it recognized that
+ * the given request was canceled and it did not perform the given operation.
+ * </p>
+ */
+ public void cancel() {
+ Object[] listeners = null;
+ synchronized (this) {
+ // Check to make sure the request monitor wasn't previously canceled.
+ if (!fCanceled) {
+ fCanceled = true;
+ if (fCancelListeners != null) {
+ listeners = fCancelListeners.getListeners();
+ }
+ }
+ }
+
+ // Call the listeners outside of a synchronized section to reduce the
+ // risk of deadlocks.
+ if (listeners != null) {
+ for (Object listener : listeners) {
+ ((ICanceledListener)listener).requestCanceled(this);
+ }
+ }
+ }
+
+ /**
+ * Returns whether the request was canceled. Even if the request is
+ * canceled by the client, the implementor handling the request should
+ * still call {@link #done()} in order to complete handling
+ * of the request monitor.
+ */
+ public synchronized boolean isCanceled() {
+ return fCanceled || (fParentRequestMonitor != null && fParentRequestMonitor.isCanceled());
+ }
+
+ /**
+ * Adds the given listener to list of listeners that are notified when this
+ * request monitor is canceled.
+ */
+ public synchronized void addCancelListener(ICanceledListener listener) {
+ if (fCancelListeners == null) {
+ fCancelListeners = new ListenerList();
+ }
+ fCancelListeners.add(listener);
+ }
+
+ /**
+ * Removes the given listener from the list of listeners that are notified
+ * when this request monitor is canceled.
+ */
+ public synchronized void removeCancelListener(ICanceledListener listener) {
+ if (fCancelListeners != null) {
+ fCancelListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Marks this request as completed. Once this method is called, the
+ * monitor submits a runnable to the DSF Executor to call the
+ * <code>handle...</code> methods.
+ * <p>
+ * Note: This method should be called once and only once, for every request
+ * issued. Even if the request was canceled.
+ * </p>
+ */
+ public synchronized void done() {
+ if (fDone) {
+ throw new IllegalStateException("RequestMonitor: " + this + ", done() method called more than once"); //$NON-NLS-1$//$NON-NLS-2$
+ }
+ fDone = true;
+ try {
+ fExecutor.execute(new DsfRunnable() {
+ public void run() {
+ RequestMonitor.this.handleCompleted();
+ }
+ @Override
+ public String toString() {
+ return "Completed: " + RequestMonitor.this.toString(); //$NON-NLS-1$
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ handleRejectedExecutionException();
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "RequestMonitor (" + super.toString() + "): " + getStatus().toString(); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Checks whether the given request monitor completed with success or
+ * failure result. If the request monitor was canceled it is considered
+ * that it failed, regardless of the status.
+ */
+ public boolean isSuccess() {
+ return !isCanceled() && getStatus().getSeverity() <= IStatus.INFO;
+ }
+
+ /**
+ * Default handler for the completion of a request. The implementation
+ * calls {@link #handleSuccess()} if the request succeeded, and calls
+ * {@link #handleFailure()} or cancel otherwise.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ handleSuccess();
+ } else {
+ handleFailure();
+ }
+ }
+
+ /**
+ * Default handler for a successful the completion of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is notified. Otherwise this method does nothing.
+ * {@link #handleFailure()} or cancel otherwise.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleSuccess() {
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.done();
+ }
+ }
+
+ /**
+ * The default implementation of a cancellation or an error result of a
+ * request. The implementation delegates to {@link #handleCancel()} and
+ * {@link #handleErrorOrWarning()} as needed.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleFailure() {
+ assert !isSuccess();
+
+ if (isCanceled()) {
+ handleCancel();
+ } else {
+ if (getStatus().getSeverity() == IStatus.CANCEL) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request monitor: '" + this + "' resulted in a cancel status: " + getStatus() + ", even though the request is not set to cancel.", null)); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ handleErrorOrWarning();
+ }
+ }
+
+ /**
+ * The default implementation of an error or warning result of a request.
+ * The implementation delegates to {@link #handleError()} and
+ * {@link #handleWarning()} as needed.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleErrorOrWarning() {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ handleError();
+ } else {
+ handleWarning();
+ }
+ }
+
+ /**
+ * The default implementation of an error result of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is configured with a new status containing this error.
+ * Otherwise the error is logged.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleError() {
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.setStatus(getStatus());
+ fParentRequestMonitor.done();
+ } else {
+ MultiStatus logStatus = new MultiStatus(DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in an error.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ logStatus.merge(getStatus());
+ DsfPlugin.getDefault().getLog().log(logStatus);
+ }
+ }
+
+ /**
+ * The default implementation of an error result of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is configured with a new status containing this warning.
+ * Otherwise the warning is logged.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleWarning() {
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.setStatus(getStatus());
+ fParentRequestMonitor.done();
+ }
+ }
+
+ /**
+ * Default handler for a canceled the completion of a request. If this
+ * monitor has a parent monitor that was configured by the constructor, that
+ * parent monitor is notified. Otherwise this method does nothing.
+ * <br>
+ * Note: Sub-classes may override this method.
+ */
+ @ConfinedToDsfExecutor("fExecutor")
+ protected void handleCancel() {
+ if (fParentRequestMonitor != null) {
+ if (getStatus().getSeverity() == IStatus.CANCEL && !fParentRequestMonitor.isCanceled()) {
+ fParentRequestMonitor.setStatus(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Sub-request " + toString() + " was canceled and not handled.'", null)); //$NON-NLS-1$ //$NON-NLS-2$
+ } else {
+ fParentRequestMonitor.setStatus(getStatus());
+ }
+ fParentRequestMonitor.done();
+ }
+ }
+
+ /**
+ * Default handler for when the executor supplied in the constructor
+ * rejects the runnable that is submitted invoke this request monitor.
+ * This usually happens only when the executor is shutting down.
+ */
+ protected void handleRejectedExecutionException() {
+ MultiStatus logStatus = new MultiStatus(DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INTERNAL_ERROR, "Request for monitor: '" + toString() + "' resulted in a rejected execution exception.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ logStatus.merge(getStatus());
+ if (fParentRequestMonitor != null) {
+ fParentRequestMonitor.setStatus(logStatus);
+ fParentRequestMonitor.done();
+ } else {
+ DsfPlugin.getDefault().getLog().log(logStatus);
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java
new file mode 100644
index 00000000000..7cdd2719799
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/RequestMonitorWithProgress.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.Executor;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+
+/**
+ * A request monitor which uses a progress monitor as a parent. When the parent
+ * progress monitor is canceled, the request monitor will also be canceled,
+ * although the cancellation listeners will not be called.
+ *
+ * @since 1.1
+ */
+public class RequestMonitorWithProgress extends RequestMonitor {
+
+ private final IProgressMonitor fProgressMonitor;
+
+ public RequestMonitorWithProgress(Executor executor, IProgressMonitor progressMonitor) {
+ super(executor, null);
+ fProgressMonitor = progressMonitor;
+ }
+
+ public IProgressMonitor getProgressMonitor() {
+ return fProgressMonitor;
+ }
+
+ @Override
+ public synchronized boolean isCanceled() {
+ return super.isCanceled() || fProgressMonitor.isCanceled();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java
new file mode 100644
index 00000000000..334a7c69e4e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/Sequence.java
@@ -0,0 +1,682 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Nokia - added StepWithProgress. Oct, 2008
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.locks.AbstractQueuedSynchronizer;
+
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor.ICanceledListener;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.SubProgressMonitor;
+
+/**
+ * Convenience class for implementing a series of commands that need to be
+ * executed asynchronously.
+ * <p>
+ * Certain complex tasks require multiple commands to be executed in a chain,
+ * because for example result of one command is used as input into another
+ * command. The typical DSF pattern of solving this problem is the following:
+ * <li>
+ * <br> 1. original caller passes a RequestMonitor callback to a method and invokes it
+ * <br> 2. the method is executed by a subsystem
+ * <br> 3. when the method is finished it calls another method and passes
+ * the original callback to it
+ * <br> 4. steps 2-3 are repeated number of times
+ * <br> 5. when the last method in a chain is executed, it submits the original
+ * RequestMonitor callback
+ * </li>
+ * <p>
+ * This pattern is very useful in itself, but it proves very difficult to follow
+ * because the methods can be scattered accross many classes and systems. Also
+ * if progress reporting, cancellability, and roll-back ability is required, it
+ * has to be re-implemented every time. The Sequence class tries to address
+ * this problem by containing this pattern in a single class.
+ */
+@ThreadSafe
+abstract public class Sequence extends DsfRunnable implements Future<Object> {
+
+ /**
+ * The abstract class that each step has to implement.
+ */
+ abstract public static class Step {
+ private Sequence fSequence;
+
+ /**
+ * Sets the sequence that this step belongs to. It is only accessible
+ * by the sequence itself, and is not meant to be called by sequence
+ * sub-classes.
+ */
+ void setSequence(Sequence sequence) { fSequence = sequence; }
+
+ /** Returns the sequence that this step is running in. */
+ public Sequence getSequence() { return fSequence; }
+
+ /**
+ * Executes the step. Overriding classes should perform the
+ * work in this method.
+ * @param rm Result token to submit to executor when step is finished.
+ */
+ public void execute(RequestMonitor rm) {
+ rm.done();
+ }
+
+ /**
+ * Roll back gives the step implementation a chance to undo the
+ * operation that was performed by execute().
+ * <br>
+ * Note if the {@link #execute(RequestMonitor)} call completes with a
+ * non-OK status, then rollBack will not be called for that step.
+ * Instead it will be called for the previous step.
+ * @param rm Result token to submit to executor when rolling back the step is finished.
+ */
+ public void rollBack(RequestMonitor rm) {
+ rm.done();
+ }
+
+ /**
+ * Returns the number of progress monitor ticks corresponding to this
+ * step.
+ */
+ public int getTicks() { return 1; }
+
+ /**
+ * Task name for this step. This will be displayed in the label of the
+ * progress monitor of the owner sequence.
+ *
+ * @return name of the task carried out by the step, can be
+ * <code>null</code>, in which case the overall task name will be used.
+ *
+ * @since 1.1
+ */
+ public String getTaskName() {
+ return ""; //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * A step that will report execution progress by itself on the progress
+ * monitor of the owner sequence.<br>
+ * <br>
+ * Note we don't offer a rollBack(RequestMonitor, IProgressMonitor) as we
+ * don't want end user to be able to cancel the rollback.
+ *
+ * @since 1.1
+ */
+ abstract public static class StepWithProgress extends Step {
+
+ @Override
+ // don't allow subclass to implement this by "final" it.
+ final public void execute(RequestMonitor rm) {
+ assert false : "execute(RequestMonitor rm, IProgressMonitor pm) should be called instead"; //$NON-NLS-1$
+ }
+
+ /**
+ * Execute the step with a progress monitor. Note the given progress
+ * monitor is a sub progress monitor of the owner sequence which is
+ * supposed to be fully controlled by the step. Namely the step should
+ * call beginTask() and done() of the monitor.
+ *
+ * @param rm
+ * @param pm
+ */
+ public void execute(RequestMonitor rm, IProgressMonitor pm) {
+ rm.done();
+ pm.done();
+ }
+ }
+
+ /** The synchronization object for this future */
+ final Sync fSync = new Sync();
+
+ /**
+ * Executor that this sequence is running in. It is used by the sequence
+ * to submit the runnables for steps, and for submitting the result.
+ */
+ final private DsfExecutor fExecutor;
+
+ /**
+ * Result callback to invoke when the sequence is finished. Intended to
+ * be used when the sequence is created and invoked from the executor
+ * thread. Otherwise, the {@link Future#get()} method is the appropriate
+ * method of retrieving the result.
+ */
+ final private RequestMonitor fRequestMonitor;
+
+ /** Status indicating the success/failure of the test. Used internally only. */
+ @ConfinedToDsfExecutor("getExecutor")
+ private IStatus fStatus = Status.OK_STATUS;
+
+ @ConfinedToDsfExecutor("getExecutor")
+ private int fCurrentStepIdx = 0;
+
+ /** Task name for this sequence used with the progress monitor */
+ final private String fTaskName;
+
+ /** Task name used when the sequence is being rolled back. */
+ final private String fRollbackTaskName;
+
+ final private IProgressMonitor fProgressMonitor;
+
+ /** Convenience constructor with limited arguments. */
+ public Sequence(DsfExecutor executor) {
+ this(executor, new NullProgressMonitor(), "", "", null); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Creates a sequence with a request monitor. If the client cancels the
+ * request monitor, then the request monitors in the
+ * {@link Step#execute(RequestMonitor)}
+ * implementations will immediately call the cancel listeners to notify.
+ *
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param rm The request monitor which will be invoked when the sequence
+ * is completed.
+ */
+ public Sequence(DsfExecutor executor, RequestMonitor rm) {
+ this(executor, new NullProgressMonitor(), "", "", rm); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Creates a sequence with a progress monitor. If the progress monitor is
+ * canceled, then request monitors in the
+ * {@link Step#execute(RequestMonitor)} implementations will need to call
+ * rm.isCanceled() to discover the cancellation.
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param pm Progress monitor for monitoring this sequence.
+ * @param taskName Name that will be used in call to
+ * {@link IProgressMonitor#beginTask(String, int)},when the task is
+ * started.
+ * @param rollbackTaskName Name that will be used in call to
+ * {@link IProgressMonitor#subTask(String)} if the task is canceled or
+ * aborted.
+ *
+ * @since 1.1
+ */
+ public Sequence(DsfExecutor executor, IProgressMonitor pm, String taskName, String rollbackTaskName) {
+ this(executor, pm, taskName, rollbackTaskName, new RequestMonitorWithProgress(ImmediateExecutor.getInstance(), pm));
+ }
+
+ /**
+ * Creates a sequence with a request monitor that includes a progress
+ * monitor.
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param rm The request monitor containing the progress monitor
+ * @param taskName Name that will be used in call to
+ * {@link IProgressMonitor#beginTask(String, int)},when the task is
+ * started.
+ * @param rollbackTaskName Name that will be used in call to
+ * {@link IProgressMonitor#subTask(String)} if the task is canceled or
+ * aborted.
+ *
+ * @since 1.1
+ */
+ public Sequence(DsfExecutor executor, RequestMonitorWithProgress rm, String taskName, String rollbackTaskName) {
+ this(executor, rm.getProgressMonitor(), taskName, rollbackTaskName, rm);
+ }
+
+ /**
+ * Constructor that initialized the steps and the result callback.
+ * @param executor The DSF executor which will be used to invoke all
+ * steps.
+ * @param pm Progress monitor for monitoring this sequence. This
+ * parameter cannot be null.
+ * @param taskName Name that will be used in call to
+ * {@link IProgressMonitor#beginTask(String, int)},when the task is
+ * started.
+ * @param rollbackTaskName Name that will be used in call to
+ * {@link IProgressMonitor#subTask(String)} if the task is canceled or
+ * aborted.
+ * @param Result that will be submitted to executor when sequence is
+ * finished. Can be null if calling from non-executor thread and using
+ * {@link Future#get()} method to wait for the sequence result.
+ *
+ * @deprecated This constructor should not be used because it creates a
+ * potential ambiguity when one of the two monitors is canceled.
+ */
+ @Deprecated
+ public Sequence(DsfExecutor executor, IProgressMonitor pm, String taskName, String rollbackTaskName, RequestMonitor rm) {
+ fExecutor = executor;
+ fProgressMonitor = pm;
+ fTaskName = taskName;
+ fRollbackTaskName = rollbackTaskName;
+ fRequestMonitor = rm;
+
+ if (fRequestMonitor != null) {
+ fRequestMonitor.addCancelListener(new ICanceledListener() {
+ public void requestCanceled(RequestMonitor rm) {
+ fSync.doCancel();
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns the steps to be executed. It is up to the deriving class to
+ * supply the steps and to ensure that the list of steps will not be
+ * modified after the sequence is constructed.
+ * <p>
+ * Steps are purposely not accepted as part of the DsfConstructor, in
+ * order to allow deriving classes to create the steps as a field. And a
+ * setSteps() method is not provided, to guarantee that the steps will not
+ * be modified once set (perhaps this is a bit paranoid, but oh well).
+ */
+ abstract public Step[] getSteps();
+
+
+ /** Returns the DSF executor for this sequence */
+ public DsfExecutor getExecutor() { return fExecutor; }
+
+ /**
+ * Returns the RequestMonitor callback that is registered with the Sequence
+ */
+ public RequestMonitor getRequestMonitor() { return fRequestMonitor; }
+
+ /**
+ * The get method blocks until sequence is complete, but always returns null.
+ * @see java.concurrent.Future#get
+ */
+ public Object get() throws InterruptedException, ExecutionException {
+ fSync.doGet();
+ return null;
+ }
+
+ /**
+ * The get method blocks until sequence is complete or until timeout is
+ * reached, but always returns null.
+ * @see java.concurrent.Future#get
+ */
+ public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
+ fSync.doGet();
+ return null;
+ }
+
+ /**
+ * Don't try to interrupt the DSF executor thread, just ignore the request
+ * if set.
+ * <p>If a request monitor was specified when creating a sequence, that
+ * request monitor will be canceled by this method as well. The client
+ * can also use the request monitor's cancel method to cancel the sequence.
+ *
+ * @see RequestMonitor#cancel()
+ */
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ // Cancel the request monitor first, to avoid a situation where
+ // the request monitor is not canceled but the status is set
+ // to canceled.
+ if (fRequestMonitor != null) {
+ fRequestMonitor.cancel();
+ }
+ return fSync.doCancel();
+ }
+
+ public boolean isCancelled() { return fSync.doIsCancelled(); }
+
+ public boolean isDone() { return fSync.doIsDone(); }
+
+
+ public void run() {
+ // Change the state to running.
+ if (fSync.doRun()) {
+ // Set the reference to this sequence in each step.
+ int totalTicks = 0;
+ for (Step step : getSteps()) {
+ step.setSequence(this);
+ totalTicks += step.getTicks();
+ }
+
+ // Set the task name
+ if (fTaskName != null) {
+ fProgressMonitor.beginTask(fTaskName, totalTicks);
+ }
+
+ // Call the first step
+ executeStep(0);
+ } else {
+ fSync.doFinish();
+ }
+ }
+
+ /**
+ * To be called only by the step implementation, Tells the sequence to
+ * submit the next step.
+ */
+ private void executeStep(int nextStepIndex) {
+ /*
+ * At end of each step check progress monitor to see if it's cancelled.
+ * If progress monitor is cancelled, mark the whole sequence as
+ * cancelled.
+ */
+ if (fProgressMonitor.isCanceled()) {
+ cancel(false);
+ }
+
+ /*
+ * If sequence was cencelled during last step (or before the sequence
+ * was ever executed), start rolling back the execution.
+ */
+ if (isCancelled()) {
+ cancelExecution();
+ return;
+ }
+
+ /*
+ * Check if we've reached the last step. Note that if execution was
+ * cancelled during the last step (and thus the sequence is
+ * technically finished, since it was cancelled it will be rolled
+ * back.
+ */
+ if (nextStepIndex >= getSteps().length) {
+ finish();
+ return;
+ }
+
+ // Proceed with executing next step.
+ fCurrentStepIdx = nextStepIndex;
+ try {
+ Step currentStep = getSteps()[fCurrentStepIdx];
+ final boolean stepControlsProgress = (currentStep instanceof StepWithProgress);
+
+ RequestMonitor rm = new RequestMonitor(fExecutor, fRequestMonitor) {
+ final private int fStepIdx = fCurrentStepIdx;
+
+ @Override
+ public void handleSuccess() {
+ // Check if we're still the correct step.
+ assert fStepIdx == fCurrentStepIdx;
+ if (!stepControlsProgress) {
+ // then sequence handles the progress report.
+ fProgressMonitor.worked(getSteps()[fStepIdx].getTicks());
+ }
+ executeStep(fStepIdx + 1);
+ }
+
+ @Override
+ protected void handleCancel() {
+ Sequence.this.cancel(false);
+ cancelExecution();
+ };
+
+ @Override
+ protected void handleErrorOrWarning() {
+ abortExecution(getStatus());
+ };
+
+ @Override
+ public String toString() {
+ return "Sequence \"" + fTaskName + "\", result for executing step #" + fStepIdx + " = " + getStatus(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ };
+
+ fProgressMonitor.subTask(currentStep.getTaskName());
+
+ if (stepControlsProgress) {
+
+ // Create a sub-monitor that will be controlled by the step.
+ SubProgressMonitor subMon = new SubProgressMonitor(fProgressMonitor, currentStep.getTicks(),
+ SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
+
+ ((StepWithProgress) currentStep).execute(rm, subMon);
+ } else { // regular Step
+ currentStep.execute(rm);
+ }
+
+ } catch (Throwable t) {
+ /*
+ * Catching the exception here will only work if the exception
+ * happens within the execute method. It will not work in cases
+ * when the execute submits other runnables, and the other runnables
+ * encounter the exception.
+ */
+ abortExecution(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, 0,
+ "Unhandled exception when executing Sequence " + this + ", step #" + fCurrentStepIdx, //$NON-NLS-1$ //$NON-NLS-2$
+ t));
+
+ /*
+ * Since we caught the exception, it will not be logged by
+ * DefaultDsfExecutable.afterExecution(). So log it here.
+ */
+ DefaultDsfExecutor.logException(t);
+ }
+ }
+
+ /**
+ * To be called only by the step implementation. Tells the sequence to
+ * roll back next step.
+ */
+ private void rollBackStep(int stepIdx) {
+ // If we reach before step 0, finish roll back.
+ if (stepIdx < 0) {
+ finish();
+ return;
+ }
+
+ // Proceed with rolling back given step.
+ fCurrentStepIdx = stepIdx;
+ try {
+ getSteps()[fCurrentStepIdx].rollBack(new RequestMonitor(fExecutor, null) {
+ final private int fStepIdx = fCurrentStepIdx;
+ @Override
+ public void handleCompleted() {
+ // Check if we're still the correct step.
+ assert fStepIdx == fCurrentStepIdx;
+
+ // Proceed to the next step.
+ if (isSuccess()) {
+ // NOTE: The getTicks() is ticks for executing the step,
+ // not for rollBack,
+ // though it does not really hurt to use it here.
+ fProgressMonitor.worked(getSteps()[fStepIdx].getTicks());
+
+ rollBackStep(fStepIdx - 1);
+ } else {
+ abortRollBack(getStatus());
+ }
+ }
+ @Override
+ public String toString() {
+ return "Sequence \"" + fTaskName + "\", result for rolling back step #" + fStepIdx + " = " + getStatus(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ });
+ } catch(Throwable t) {
+ /*
+ * Catching the exception here will only work if the exception
+ * happens within the execute method. It will not work in cases
+ * when the execute submits other runnables, and the other runnables
+ * encounter the exception.
+ */
+ abortRollBack(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, 0,
+ "Unhandled exception when rolling back Sequence " + this + ", step #" + fCurrentStepIdx, //$NON-NLS-1$ //$NON-NLS-2$
+ t));
+
+ /*
+ * Since we caught the exception, it will not be logged by
+ * DefaultDsfExecutable.afterExecution(). So log it here.
+ */
+ DefaultDsfExecutor.logException(t);
+ }
+ }
+
+ /**
+ * Tells the sequence that its execution is to be aborted and it
+ * should start rolling back the sequence as if it was cancelled by user.
+ */
+ private void cancelExecution() {
+ if (fRollbackTaskName != null) {
+ fProgressMonitor.subTask(fRollbackTaskName);
+ }
+ fStatus = new Status(IStatus.CANCEL, DsfPlugin.PLUGIN_ID, -1, "Sequence \"" + fTaskName + "\" cancelled.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ if (fRequestMonitor != null) {
+ fRequestMonitor.setStatus(fStatus);
+ }
+
+ /*
+ * No need to call fSync, it should have been taken care of by
+ * Future#cancel method.
+ *
+ * Note that we're rolling back starting with the current step,
+ * because the current step was fully executed. This is unlike
+ * abortExecution() where the current step caused the roll-back.
+ */
+ rollBackStep(fCurrentStepIdx);
+ }
+
+ /**
+ * Tells the sequence that its execution is to be aborted and it
+ * should start rolling back the sequence as if it was cancelled by user.
+ */
+ private void abortExecution(final IStatus error) {
+ if (fRollbackTaskName != null) {
+ fProgressMonitor.subTask(fRollbackTaskName);
+ }
+ fStatus = error;
+ if (fRequestMonitor != null) {
+ fRequestMonitor.setStatus(error);
+ }
+ fSync.doAbort(new CoreException(error));
+
+ // Roll back starting with previous step, since current step failed.
+ rollBackStep(fCurrentStepIdx - 1);
+ }
+
+ /**
+ * Tells the sequence that that is rolling back, to abort roll back, and
+ * notify the clients.
+ */
+ private void abortRollBack(final IStatus error) {
+ if (fRollbackTaskName != null) {
+ fProgressMonitor.subTask(fRollbackTaskName);
+ }
+
+ /*
+ * Compose new status based on previous status information and new
+ * error information.
+ */
+ MultiStatus newStatus =
+ new MultiStatus(DsfPlugin.PLUGIN_ID, error.getCode(),
+ "Sequence \"" + fTaskName + "\" failed while rolling back.", null); //$NON-NLS-1$ //$NON-NLS-2$
+ newStatus.merge(error);
+ newStatus.merge(fStatus);
+ fStatus = newStatus;
+
+ if (fRequestMonitor != null) {
+ fRequestMonitor.setStatus(newStatus);
+ }
+
+ finish();
+ }
+
+ private void finish() {
+ if (fRequestMonitor != null) fRequestMonitor.done();
+ fSync.doFinish();
+ }
+
+ @SuppressWarnings("serial")
+ final class Sync extends AbstractQueuedSynchronizer {
+ private static final int STATE_RUNNING = 1;
+ private static final int STATE_FINISHED = 2;
+ private static final int STATE_ABORTING = 4;
+ private static final int STATE_ABORTED = 8;
+ private static final int STATE_CANCELLING = 16;
+ private static final int STATE_CANCELLED = 32;
+
+ private Throwable fException;
+
+ private boolean isFinished(int state) {
+ return (state & (STATE_FINISHED | STATE_CANCELLED | STATE_ABORTED)) != 0;
+ }
+
+ @Override
+ protected int tryAcquireShared(int ignore) {
+ return doIsDone()? 1 : -1;
+ }
+
+ @Override
+ protected boolean tryReleaseShared(int ignore) {
+ return true;
+ }
+
+ boolean doIsCancelled() {
+ int state = getState();
+ return (state & (STATE_CANCELLING | STATE_CANCELLED)) != 0;
+ }
+
+ boolean doIsDone() {
+ return isFinished(getState());
+ }
+
+ void doGet() throws InterruptedException, ExecutionException {
+ acquireSharedInterruptibly(0);
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ }
+
+ void doGet(long nanosTimeout) throws InterruptedException, ExecutionException, TimeoutException {
+ if (!tryAcquireSharedNanos(0, nanosTimeout)) throw new TimeoutException();
+ if (getState() == STATE_CANCELLED) throw new CancellationException();
+ if (fException != null) throw new ExecutionException(fException);
+ }
+
+ void doAbort(Throwable t) {
+ while(true) {
+ int s = getState();
+ if (isFinished(s)) return;
+ if (compareAndSetState(s, STATE_ABORTING)) break;
+ }
+ fException = t;
+ }
+
+ boolean doCancel() {
+ while(true) {
+ int s = getState();
+ if (isFinished(s)) return false;
+ if (s == STATE_ABORTING) return false;
+ if (compareAndSetState(s, STATE_CANCELLING)) break;
+ }
+ return true;
+ }
+
+ void doFinish() {
+ while(true) {
+ int s = getState();
+ if (isFinished(s)) return;
+ if (s == STATE_ABORTING) {
+ if (compareAndSetState(s, STATE_ABORTED)) break;
+ } else if (s == STATE_CANCELLING) {
+ if (compareAndSetState(s, STATE_CANCELLED)) break;
+ } else {
+ if (compareAndSetState(s, STATE_FINISHED)) break;
+ }
+ }
+ releaseShared(0);
+ }
+
+ boolean doRun() {
+ return compareAndSetState(0, STATE_RUNNING);
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java
new file mode 100644
index 00000000000..b48d69afa7b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/StackTraceWrapper.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+/**
+ * Untility class for easy pretty-printing stack traces. Local to the
+ * concurrent package.
+ */
+@Immutable
+class StackTraceWrapper {
+ final StackTraceElement[] fStackTraceElements;
+
+ StackTraceWrapper(StackTraceElement[] elements) { fStackTraceElements = elements; }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(fStackTraceElements.length * 30);
+ for (int i = 0; i < fStackTraceElements.length && i < 10; i++) {
+ builder.append(fStackTraceElements[i]);
+ if (i < fStackTraceElements.length && i < 10) builder.append("\n at "); //$NON-NLS-1$
+ }
+ return builder.toString();
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java
new file mode 100644
index 00000000000..5ebcdec963a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafe.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given package, class, method, or field can be
+ * access safely from any thread. If declared on package or type, a field
+ * or method could still be declared with an annotation indicating that it's
+ * not thread-safe.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
+@Inherited
+@Documented
+public @interface ThreadSafe {
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java
new file mode 100644
index 00000000000..4f3188b468d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/concurrent/ThreadSafeAndProhibitedFromDsfExecutor.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.concurrent;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation idicating that given package, class, method, can be accessed on
+ * any thread, except on the dispatch thread of given DsfExecutor.
+ * <br> This restriction is desirable if it is expected that the implementation
+ * behavior is to block the calling thread and execute a transaction using an
+ * executor. In this situation, if the call is made on the executor's dispach
+ * thread, the execution would dead-lock.
+ * <br>
+ * If declared on package or type, a field or method could still be declared
+ * with an annotation indicating that it's thread-safe.
+ * <p>
+ * Note: the runtime retention policy is there to allow automated testing
+ * and validation code.
+ *
+ * @param value The value indicates the method to use to obtain the executor.
+ * It should be null if it cannot be determined from the given object.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PACKAGE, ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
+@Inherited
+@Documented
+public @interface ThreadSafeAndProhibitedFromDsfExecutor {
+ String value();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java
new file mode 100644
index 00000000000..fd96e0d99f3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMContext.java
@@ -0,0 +1,141 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.PlatformObject;
+
+/**
+ * Base implementation of the IDMContext interface. There are two pieces of
+ * functionality here: <br>
+ * 1) The {@link #getAdapter(Class)} implementation which retrieves model
+ * adapters registered with the session. <br>
+ * 2) Methods to help compare DM Contexts. <br>
+ * <p>
+ * Note: The {@link #equals(Object)} and {@link #hashCode()} methods are
+ * made abstract to force the deriving classes to provide a proper
+ * implementation. Data Model Context objects are meant to be used as handles,
+ * therefore a proper equals implementation is critical.
+ * </p>
+ * @param <V> Data Model data type that this context is for.
+ */
+@Immutable
+abstract public class AbstractDMContext extends PlatformObject
+ implements IDMContext
+{
+ private final String fSessionId;
+ private final IDMContext[] fParents;
+
+ /**
+ * Main constructor provides all data needed to implement the IModelContext
+ * interface.
+ */
+ public AbstractDMContext(String sessionId, IDMContext[] parents) {
+ fSessionId = sessionId;
+ fParents = parents;
+ for (IDMContext parent : parents) {
+ assert(parent != null);
+ }
+ }
+
+ /** Convenience constructor */
+ public AbstractDMContext(IDsfService service, IDMContext[] parents) {
+ this(service.getSession().getId(), parents);
+ }
+
+ /**
+ * Should be used by the deriving class to compare the basic context object
+ * information.
+ * @param other the other service to compare to
+ * @return true if contexts are equal
+ */
+ protected boolean baseEquals(Object other) {
+ if (other == null) return false;
+ if ( !(other.getClass().equals(getClass()))) return false;
+ IDMContext otherCtx = (IDMContext)other;
+ return getSessionId().equals(otherCtx.getSessionId()) &&
+ areParentsEqual(otherCtx.getParents());
+ }
+
+ private boolean areParentsEqual(IDMContext[] otherParents) {
+ if ( !(fParents.length == otherParents.length) ) return false;
+ for (int i = 0; i < fParents.length; i++) {
+ if (!fParents[i].equals(otherParents[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected int baseHashCode() {
+ int parentsHash = 0;
+ for (Object parent : getParents()) {
+ parentsHash += parent.hashCode();
+ }
+ return getSessionId().hashCode() + parentsHash;
+ }
+
+ protected String baseToString() {
+ StringBuffer retVal = new StringBuffer();
+ for (IDMContext parent : fParents) {
+ retVal.append(parent);
+ }
+ return retVal.toString();
+ }
+
+ public String getSessionId() { return fSessionId; }
+ public IDMContext[] getParents() { return fParents; }
+
+ /**
+ * Overrides the standard platform getAdapter to provide session-specific
+ * adapters.
+ * <p>
+ * ModelContext is intended to be used in views, which call the
+ * contexts.getAdapter() method to retrieve model-specific content and
+ * label providers. But since many different sessions could be active
+ * at the same time, each requiring different content providers, the
+ * standard platform <code>IAdapterManager</code> is not sufficient in
+ * handling adapters for the model context object. This is because
+ * <code>IAdapterManager</code> uses only the class of the adaptable to
+ * select the correct adapter factoru, while for model context, the
+ * session is equally important.
+ * @see org.eclipse.runtime.IAdapterManager
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapterType) {
+ Object retVal = null;
+ DsfSession session = DsfSession.getSession(fSessionId);
+ if (session != null) {
+ retVal = session.getModelAdapter(adapterType);
+ }
+ if (retVal == null) {
+ retVal = super.getAdapter(adapterType);
+ }
+ return retVal;
+ }
+
+ /**
+ * Deriving classes must implement proper equals and hashCode operations
+ * based on context data.
+ */
+ @Override
+ abstract public boolean equals(Object obj);
+
+ /**
+ * Deriving classes must implement proper equals and hashCode operations
+ * based on context data.
+ */
+ @Override
+ abstract public int hashCode();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java
new file mode 100644
index 00000000000..296433e85fd
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/AbstractDMEvent.java
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+/**
+ * Base implementation of the IDMEvent interface. It only handles the
+ * required DM-Context reference.
+ */
+@Immutable
+abstract public class AbstractDMEvent<V extends IDMContext> implements IDMEvent<V> {
+
+ private final V fModelContext;
+ public AbstractDMEvent(V context) {
+ fModelContext = context;
+ }
+
+ public V getDMContext() {
+ return fModelContext;
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java
new file mode 100644
index 00000000000..8f114e2dd44
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/CompositeDMContext.java
@@ -0,0 +1,92 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import java.util.Arrays;
+
+/**
+ * Generic DM context used to combine several DM Contexts. This object allows
+ * clients and other services to combine several contexts into one in order to
+ * pass them as an argument to a method which takes a generic context as an
+ * argument.
+ */
+public class CompositeDMContext implements IDMContext {
+
+ public static String INVALID_SESSION_ID = ""; //$NON-NLS-1$
+
+ /**
+ * The list of parent contexts that this composite context is made up of.
+ */
+ private final IDMContext[] fParents;
+
+ /**
+ * Main constructor provides all data needed to implement the IModelContext
+ * interface.
+ * @param parents Array of parent contexts that this composite context is
+ * made up of. It can be an empty array, but it cannot be null.
+ */
+ public CompositeDMContext(IDMContext[] parents) {
+ fParents = parents;
+ }
+
+ /**
+ * Returns the session ID of the first element in the array of parents of this
+ * context. May return an empty string if the parents array has no elements.
+ * <p>
+ * Note: The session ID is primarily used by UI components to get access to the
+ * correct session and executor for the given context. The composite context is
+ * intended to be created by clients which already know the session ID so
+ * the fact that this method may not return a reliable result is acceptable.
+ * </p>
+ */
+ public String getSessionId() {
+ IDMContext[] parents = getParents();
+ if (parents.length > 0) {
+ return parents[0].getSessionId();
+ } else {
+ return INVALID_SESSION_ID;
+ }
+ }
+
+ /**
+ * Returns the list of parents that this composite context is based on. Subclasses
+ * may override this method to calculate their own set of parents.
+ */
+ public IDMContext[] getParents() {
+ return fParents;
+ }
+
+ /**
+ * Returns the given adapter of the last DMVMContext element found in the tree
+ * path of this composite context. Will return null if no DMVMContext is found
+ * in path.
+ * @see #getSessionId()
+ */
+ @SuppressWarnings("unchecked")
+ public Object getAdapter(Class adapterType) {
+ IDMContext[] parents = getParents();
+ if (parents.length > 0) {
+ return parents[0].getAdapter(adapterType);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof CompositeDMContext && Arrays.equals(((CompositeDMContext)obj).getParents(), getParents());
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(getParents());
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java
new file mode 100644
index 00000000000..bf0c7102c5c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/DMContexts.java
@@ -0,0 +1,157 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson - Modified for additional features in DSF Reference implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+
+
+/**
+ * Holder for utility static methods for manipulating IDMContext objects.
+ */
+public class DMContexts {
+
+ /**
+ * Convenience constant.
+ */
+ public static final IDMContext[] EMPTY_CONTEXTS_ARRAY = new IDMContext[0];
+
+ /**
+ * Finds a data model context of given type among ancestors of the
+ * specified context. The returned ancestor is the one closest to the
+ * specified context, in terms of depth.
+ *
+ * Note that for efficiency, this method does not re-use getAllAncestorsOfType()
+ * to avoid the unnecessary creation of an array.
+ *
+ * @param ctx DMC to search.
+ * @param ancestorType Class type of the desired DMC ancestor.
+ * @return Returns the ancestor if found, null otherwise.
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public static <V extends IDMContext> V getAncestorOfType(IDMContext ctx, Class<V> ancestorType) {
+ if(ctx == null)
+ return null;
+ // Check the first context here for efficiency
+ if (ancestorType.isAssignableFrom(ctx.getClass())) {
+ return (V)ctx;
+ }
+
+ // Use a LinkedHashSet to avoid duplicates and preserver insertion-order
+ Set<IDMContext> nodes = new LinkedHashSet<IDMContext>();
+ nodes.addAll(Arrays.asList(ctx.getParents()));
+ while (nodes.isEmpty() == false) {
+ Set<IDMContext> parents = nodes;
+ nodes = new LinkedHashSet<IDMContext>();
+ for (IDMContext parent : parents) {
+ if (ancestorType.isAssignableFrom(parent.getClass())) {
+ return (V)parent;
+ }
+
+ nodes.addAll(Arrays.asList(parent.getParents()));
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Finds all data model contexts of given type among ancestors of the
+ * specified context. Ancestors are returned in order of closest to farthest,
+ * in terms of depth.
+ * @param ctx DMC to search.
+ * @param ancestorType Class type of the desired DMC ancestor.
+ * @return Returns all ancestors found, null if none.
+ * @since 1.1
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public static <V extends IDMContext> V[] getAllAncestorsOfType(IDMContext ctx, Class<V> ancestorType) {
+ if(ctx == null)
+ return null;
+
+ // Use a LinkedHashSet to avoid duplicates and preserver insertion-order
+ Set<V> requestedAncestors = new LinkedHashSet<V>();
+ Set<IDMContext> nodes = new LinkedHashSet<IDMContext>();
+ nodes.add(ctx);
+ while (nodes.isEmpty() == false) {
+ Set<IDMContext> parents = nodes;
+ nodes = new LinkedHashSet<IDMContext>();
+ for (IDMContext parent : parents) {
+ if (ancestorType.isAssignableFrom(parent.getClass())) {
+ requestedAncestors.add((V)parent);
+ }
+
+ nodes.addAll(Arrays.asList(parent.getParents()));
+ }
+ }
+
+ if (requestedAncestors.isEmpty()) return null;
+ else {
+ V[] v = (V[])Array.newInstance(ancestorType, 0);
+ return requestedAncestors.toArray(v);
+ }
+ }
+
+ /**
+ * Checks all ancestors for a given context to see if the given
+ * potentialAncestor is in fact an ancestor.
+ * @param dmc DM Contexts who's ancestors to check.
+ * @param potentialAncestor Ancestor context to look for.
+ * @return true if a match is found.
+ */
+ @ThreadSafe
+ public static boolean isAncestorOf(IDMContext dmc, IDMContext potentialAncestor) {
+ // Check the direct parents for a match.
+ for (IDMContext parentDmc : dmc.getParents()) {
+ if (potentialAncestor.equals(parentDmc)) {
+ return true;
+ }
+ }
+
+ // Recursively check the parents' parents for a match.
+ for (IDMContext parentDmc : dmc.getParents()) {
+ if (isAncestorOf(parentDmc, potentialAncestor)) {
+ return true;
+ }
+ }
+
+ // No match.
+ return false;
+ }
+
+ /**
+ * Traverses all the parents of a context and converts the whole
+ * into a list.
+ */
+ @ThreadSafe
+ public static List<IDMContext> toList(IDMContext dmc) {
+ /*
+ * This method is implemented recursively, which is not necessarily
+ * the most efficient way to do this.
+ */
+ List<IDMContext> list = new ArrayList<IDMContext>();
+ list.add(dmc);
+
+ for (IDMContext parentDmc : dmc.getParents()) {
+ list.addAll(toList(parentDmc));
+ }
+ return list;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java
new file mode 100644
index 00000000000..2d8292ba17d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMContext.java
@@ -0,0 +1,60 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.core.runtime.IAdaptable;
+
+/**
+ * The base class for data model objects.
+ * <p>
+ * DSF services need to return objects to clients which can be used as
+ * handles to track data stored in the service. Clients such as lazy-loading
+ * tree and table views retrieve a list of handles, then as needed, they
+ * retrieve the children and label information for these handles. Because of
+ * this pattern, services need to be able to return a set of handle objects,
+ * then as needed clients can retrieve data corresponding to these handles.
+ * The Data Model Context object is the interface that DSF services should use
+ * to represent the handle objects that are to be referenced by view model.
+ * <p>
+ * <i>Note: DM contexts are meant to be immutable and thus accessible from
+ * any thread instead of just the services dispatch thread. This is because
+ * clients may need to call context objects' methods on non-dispatch thread,
+ * especially equals and hashCode.</i>
+ * <p>
+ * <i>Note #2: DM Contexts should also avoid holding references to service
+ * instances or other large chunks of data, because some of the clients may
+ * hold onto these objects for longer time than the life of the service.
+ * This may prevent the service from being garbage collected, possibly keeping
+ * a lot of resources tied up.
+ *
+ */
+@Immutable
+public interface IDMContext extends IAdaptable
+{
+ /**
+ * Each model context object needs to track the session from which it
+ * originated. The session ID allows clients to choose the correct
+ * dispatch thread with which to access the service, and it allows the
+ * service to be uniquely identified among other sessions.
+ * @return Session ID of the service that originated the context.
+ */
+ public String getSessionId();
+
+ /**
+ * Returns the parent context of this context. ModelContext objects can be
+ * chained this way to allow methods that require context from multiple
+ * services to retrieve this context from a single handle that comes from
+ * the client.
+ * @return parent context of this context.
+ */
+ public IDMContext[] getParents();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java
new file mode 100644
index 00000000000..045f8c92013
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMData.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+
+/**
+ * Marker interface for data corresponding to IDMContext, retrieved from a
+ * service. These data objects are meant to be processed by clients on
+ * different threads, therefore they should be immutable.
+ */
+@Immutable
+public interface IDMData {
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java
new file mode 100644
index 00000000000..40edf672e51
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMEvent.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+/**
+ * Common interface for events that signify changes in the data model.
+ * The sub-classes should contain specific information about the event, while
+ * this base class only identifies the DM Context that is affected.
+ * @param <V> Data Model context type that is affected by this event.
+ */
+public interface IDMEvent <V extends IDMContext> {
+ V getDMContext();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java
new file mode 100644
index 00000000000..f0071711a62
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/IDMService.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.datamodel;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Interface for DSF services that provide model data to clients.
+ * <p>
+ * For completeness this service interface derives from <code>IDMData</data>
+ * and has a method which allows clients to retrieve the DM Context that
+ * represents the service data.
+ *
+ * @deprecated Without getModelData method this service has no function.
+ * There's also no need for it as a marker interface so we may as well
+ * get rid of it.
+ */
+public interface IDMService extends IDsfService {
+ /**
+ * Retrieves model data object for given context. This method makes it
+ * un-necessary for every model service to declare a separate method
+ * for retrieving model data of specific type.
+ *
+ * @param <V> The Data Model Data type that is to be retrieved.
+ * @param dmc Data Model Context for the data model data object to be retrieved.
+ * @param rm Request completion monitor to be filled in with the Data Model Data.
+ *
+ * @deprecated This method is now deprecated as there is no compile-time linking
+ * between IDMContext and IDMData objects (see bug 205132)
+ */
+ @Deprecated
+ void getModelData(IDMContext dmc, DataRequestMonitor<?> rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html
new file mode 100644
index 00000000000..2ea664a1ee4
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/datamodel/package.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <meta content="text/html; charset=ISO-8859-1"
+ http-equiv="content-type">
+ <title>Eclipse Device Debug - Debugger Services Framework - Data Model</title>
+</head>
+<body>
+Provides a base API and utilities for expoding data model through DSF
+services.<br>
+<br>
+<h2>Package Specification</h2>
+Practically speaking, all state data held by the DSF services makes up
+the "data mode" of the service session.&nbsp; However, to make it easy
+to present this data in standard debug views, as well as customizable
+views, it is useful to present the data using a consisten pattern and
+with a set of published APIs and utilities.&nbsp; This package aims to
+provide these APIs and utilities.<br>
+<h3>Development Plans</h3>
+This package is a work in progress and it is missing a major
+feature.&nbsp; This feature is being able to automatically parametrize
+the contents of the data model in order to generically traverse it, and
+to write data-driven framework for populating views with model data.<br>
+<br>
+</body>
+</html>
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java
new file mode 100644
index 00000000000..7f57a6c812c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/internal/provisional/model/IMemoryBlockUpdatePolicyProvider.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - Ted Williams - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.internal.provisional.model;
+
+/*
+ * This interface is EXPERIMENTAL.
+*/
+
+public interface IMemoryBlockUpdatePolicyProvider
+{
+ public String[] getUpdatePolicies();
+
+ public String getUpdatePolicyDescription(String id);
+
+ public String getUpdatePolicy();
+
+ public void setUpdatePolicy(String id);
+
+ public void clearCache();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java
new file mode 100644
index 00000000000..88c8a119eb1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlock.java
@@ -0,0 +1,634 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson Communication - upgrade IF to IMemoryBlockExtension
+ * Ericsson Communication - added support for 64 bit processors
+ * Ericsson Communication - added support for changed bytes
+ * Ericsson Communication - better management of exceptions
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.model;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.debug.internal.provisional.model.IMemoryBlockUpdatePolicyProvider;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IRunControl;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryChangedEvent;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.utils.Addr64;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+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.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.IMemoryBlockRetrieval;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * This class manages the memory block retrieved from the target as a result
+ * of a getBytesFromAddress() call from the platform.
+ *
+ * It performs its read/write functions using the MemoryService.
+ */
+public class DsfMemoryBlock extends PlatformObject implements IMemoryBlockExtension, IMemoryBlockUpdatePolicyProvider
+{
+ private final static String UPDATE_POLICY_AUTOMATIC = "Automatic"; //$NON-NLS-1$
+ private final static String UPDATE_POLICY_MANUAL = "Manual"; //$NON-NLS-1$
+ private final static String UPDATE_POLICY_BREAKPOINT = "On Breakpoint"; //$NON-NLS-1$
+
+ private final IMemoryDMContext fContext;
+ private final ILaunch fLaunch;
+ private final IDebugTarget fDebugTarget;
+ private final DsfMemoryBlockRetrieval fRetrieval;
+ private final String fModelId;
+ private final String fExpression;
+ private final BigInteger fBaseAddress;
+
+ private BigInteger fBlockAddress;
+ private int fLength;
+ private int fWordSize;
+ private MemoryByte[] fBlock;
+
+ private String fUpdatePolicy = UPDATE_POLICY_AUTOMATIC;
+
+ private ArrayList<Object> fConnections = new ArrayList<Object>();
+
+ @SuppressWarnings("unused")
+ private boolean isEnabled;
+
+ /**
+ * Constructor.
+ *
+ * @param retrieval - the MemoryBlockRetrieval (session context)
+ * @param modelId -
+ * @param expression - the displayed expression in the UI
+ * @param address - the actual memory block start address
+ * @param word_size - the number of bytes per address
+ * @param length - the requested block length (could be 0)
+ */
+ DsfMemoryBlock(DsfMemoryBlockRetrieval retrieval, IMemoryDMContext context, String modelId, String expression, BigInteger address, int word_size, long length) {
+ fLaunch = retrieval.getLaunch();
+ fDebugTarget = retrieval.getDebugTarget();
+ fRetrieval = retrieval;
+ fContext = context;
+ fModelId = modelId;
+ fExpression = expression;
+ fBaseAddress = address;
+
+ // Current block information
+ fBlockAddress = address;
+ fWordSize = word_size;
+ fLength = (int) length;
+ fBlock = null;
+
+ try {
+ fRetrieval.getExecutor().execute(new Runnable() {
+ public void run() {
+ fRetrieval.getSession().addServiceEventListener(DsfMemoryBlock.this, null);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session is shut down.
+ }
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IAdaptable
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (adapter.isAssignableFrom(DsfMemoryBlockRetrieval.class)) {
+ return fRetrieval;
+ }
+ return super.getAdapter(adapter);
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IDebugElement
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IDebugElement#getDebugTarget()
+ */
+ public IDebugTarget getDebugTarget() {
+ return fDebugTarget;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IDebugElement#getModelIdentifier()
+ */
+ public String getModelIdentifier() {
+ return fModelId;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IDebugElement#getLaunch()
+ */
+ public ILaunch getLaunch() {
+ return fLaunch;
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IMemoryBock interface - obsoleted by IMemoryBlockExtension
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#getStartAddress()
+ */
+ public long getStartAddress() {
+ // Not implemented (obsolete)
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#getLength()
+ */
+ public long getLength() {
+ // Not implemented (obsolete)
+ return 0;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#getBytes()
+ */
+ public byte[] getBytes() throws DebugException {
+ // Not implemented (obsolete)
+ return new byte[0];
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#supportsValueModification()
+ */
+ public boolean supportsValueModification() {
+ return fRetrieval.supportsValueModification();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlock#setValue(long, byte[])
+ */
+ public void setValue(long offset, byte[] bytes) throws DebugException {
+ // Not implemented (obsolete)
+ }
+
+ // ////////////////////////////////////////////////////////////////////////
+ // IMemoryBlockExtension interface
+ // ////////////////////////////////////////////////////////////////////////
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getExpression()
+ */
+ public String getExpression() {
+ return fExpression;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigBaseAddress()
+ */
+ public BigInteger getBigBaseAddress() throws DebugException {
+ return fBaseAddress;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockStartAddress()
+ */
+ public BigInteger getMemoryBlockStartAddress() throws DebugException {
+ // Null indicates that memory can be retrieved at addresses lower than the block base address
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockEndAddress()
+ */
+ public BigInteger getMemoryBlockEndAddress() throws DebugException {
+ // Null indicates that memory can be retrieved at addresses higher the block base address
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBigLength()
+ */
+ public BigInteger getBigLength() throws DebugException {
+ // -1 indicates that memory block is unbounded
+ return BigInteger.valueOf(-1);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getAddressSize()
+ */
+ public int getAddressSize() throws DebugException {
+ return fRetrieval.getAddressSize();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportBaseAddressModification()
+ */
+ public boolean supportBaseAddressModification() throws DebugException {
+ return fRetrieval.supportBaseAddressModification();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#supportsChangeManagement()
+ */
+ public boolean supportsChangeManagement() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#setBaseAddress(java.math.BigInteger)
+ */
+ public void setBaseAddress(BigInteger address) throws DebugException {
+ fBlockAddress = address;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBytesFromOffset(java.math.BigInteger, long)
+ */
+ public MemoryByte[] getBytesFromOffset(BigInteger offset, long units) throws DebugException {
+ return getBytesFromAddress(fBlockAddress.add(offset), units);
+ }
+
+ private boolean fUseCachedData = false;
+
+ public void clearCache() {
+ fUseCachedData = false;
+ }
+
+ @DsfServiceEventHandler
+ public void handleCacheSuspendEvent(IRunControl.ISuspendedDMEvent e) {
+ if (e.getReason() == StateChangeReason.BREAKPOINT)
+ fUseCachedData = false;
+ }
+
+ private boolean isUseCacheData()
+ {
+ if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_BREAKPOINT))
+ return fUseCachedData;
+
+ if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_MANUAL))
+ return fUseCachedData;
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getBytesFromAddress(java.math.BigInteger, long)
+ */
+ public MemoryByte[] getBytesFromAddress(BigInteger address, long units) throws DebugException {
+
+ if (isUseCacheData() && fBlockAddress.compareTo(address) == 0 && units * getAddressableSize() <= fBlock.length)
+ return fBlock;
+
+ MemoryByte[] newBlock = fetchMemoryBlock(address, units);
+ int newLength = (newBlock != null) ? newBlock.length : 0;
+
+ // If the retrieved block overlaps with the cached block, flag the changed bytes
+ // so they can be properly highlighted in the platform Memory view.
+ // Note: In the standard Memory view, the values are displayed in cells of 4 bytes
+ // (on 4-bytes address boundaries) and all 4 bytes have to be flagged so the
+ // cell is highlighted (and the delta sigh is shown).
+ if (fBlock != null && newLength > 0) {
+ switch (fBlockAddress.compareTo(address)) {
+ // Cached block begins before the retrieved block location
+ // If there is no overlap, there are no bytes to flag
+ case -1:
+ {
+ // Determine the distance between the cached and the
+ // requested block addresses
+ BigInteger bigDistance = address.subtract(fBlockAddress);
+
+ // If the distance does not exceed the length of the cached block,
+ // then there is some overlap between the blocks and we have to
+ // mark the changed bytes (if applicable)
+ if (bigDistance.compareTo(BigInteger.valueOf(fLength)) == -1) {
+ // Here we can reasonably assume that java integers are OK
+ int distance = bigDistance.intValue();
+ int length = fLength - distance;
+
+ // Work by cells of 4 bytes
+ for (int i = 0; i < length; i += 4) {
+ // Determine if any byte within the cell was modified
+ boolean changed = false;
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[j].setFlags(fBlock[distance + j].getFlags());
+ if (newBlock[j].getValue() != fBlock[distance + j].getValue())
+ changed = true;
+ }
+ // If so, flag the whole cell as modified
+ if (changed)
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[j].setHistoryKnown(true);
+ newBlock[j].setChanged(true);
+ }
+ }
+
+ }
+ break;
+ }
+
+ // Cached block begins before the retrieved block location
+ // If there is no overlap, there are no bytes to flag
+ // (this block of code is symmetric with the previous one)
+ case 0:
+ case 1:
+ {
+ // Determine the distance between the cached and the
+ // requested block addresses
+ BigInteger bigDistance = fBlockAddress.subtract(address);
+
+ // If the distance does not exceed the length of the new block,
+ // then there is some overlap between the blocks and we have to
+ // mark the changed bytes (if applicable)
+ if (bigDistance.compareTo(BigInteger.valueOf(newLength)) == -1) {
+ // Here we can reasonably assume that java integers are OK
+ int distance = bigDistance.intValue();
+ int length = newLength - distance;
+
+ // Work by cells of 4 bytes
+ for (int i = 0; i < length; i += 4) {
+ // Determine if any byte within the cell was modified
+ boolean changed = false;
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[distance + j].setFlags(fBlock[j].getFlags());
+ if (newBlock[distance + j].getValue() != fBlock[j].getValue())
+ changed = true;
+ }
+ // If so, flag the whole cell as modified
+ if (changed)
+ for (int j = i; j < (i + 4) && j < length; j++) {
+ newBlock[distance + j].setHistoryKnown(true);
+ newBlock[distance + j].setChanged(true);
+ }
+ }
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ // Update the internal state
+ fBlock = newBlock;
+ fBlockAddress = address;
+ fLength = newLength;
+
+ if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_BREAKPOINT))
+ fUseCachedData = true;
+ else if (fUpdatePolicy.equals(DsfMemoryBlock.UPDATE_POLICY_MANUAL))
+ fUseCachedData = true;
+
+ return fBlock;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#setValue(java.math.BigInteger, byte[])
+ */
+ public void setValue(BigInteger offset, byte[] bytes) throws DebugException {
+ writeMemoryBlock(offset.longValue(), bytes);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#connect(java.lang.Object)
+ */
+ public void connect(Object client) {
+ if (!fConnections.contains(client))
+ fConnections.add(client);
+ if (fConnections.size() == 1)
+ enable();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#disconnect(java.lang.Object)
+ */
+ public void disconnect(Object client) {
+ if (fConnections.contains(client))
+ fConnections.remove(client);
+ if (fConnections.size() == 0)
+ disable();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getConnections()
+ */
+ public Object[] getConnections() {
+ return fConnections.toArray();
+ }
+
+ private void enable() {
+ isEnabled = true;
+ }
+
+ private void disable() {
+ isEnabled = false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#dispose()
+ */
+ public void dispose() throws DebugException {
+ try {
+ fRetrieval.getExecutor().execute(new Runnable() {
+ public void run() {
+ fRetrieval.getSession().removeServiceEventListener(DsfMemoryBlock.this);
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ // Session is down.
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getMemoryBlockRetrieval()
+ */
+ public IMemoryBlockRetrieval getMemoryBlockRetrieval() {
+ return fRetrieval;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.model.IMemoryBlockExtension#getAddressableSize()
+ */
+ public int getAddressableSize() throws DebugException {
+ return fRetrieval.getAddressableSize();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Helper functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * The real thing. Since the original call is synchronous (from a platform
+ * Job), we use a Query that will patiently wait for the underlying
+ * asynchronous calls to complete before returning.
+ *
+ * @param bigAddress
+ * @param length
+ * @return MemoryByte[]
+ * @throws DebugException
+ */
+ private MemoryByte[] fetchMemoryBlock(BigInteger bigAddress, final long length) throws DebugException {
+
+ // For the IAddress interface
+ final Addr64 address = new Addr64(bigAddress);
+
+ // Use a Query to synchronize the downstream calls
+ Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
+ @Override
+ protected void execute(final DataRequestMonitor<MemoryByte[]> drm) {
+ IMemory memoryService = (IMemory) fRetrieval.getServiceTracker().getService();
+ if (memoryService != null) {
+ // Go for it
+ memoryService.getMemory(
+ fContext, address, 0, fWordSize, (int) length,
+ new DataRequestMonitor<MemoryByte[]>(fRetrieval.getExecutor(), drm) {
+ @Override
+ protected void handleSuccess() {
+ drm.setData(getData());
+ drm.done();
+ }
+ });
+ }
+
+ }
+ };
+ fRetrieval.getExecutor().execute(query);
+
+ try {
+ return query.get();
+ } catch (InterruptedException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error reading memory block (InterruptedException)", e)); //$NON-NLS-1$
+ } catch (ExecutionException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error reading memory block (ExecutionException)", e)); //$NON-NLS-1$
+ }
+ }
+
+ /* Writes an array of bytes to memory.
+ *
+ * @param offset
+ * @param bytes
+ * @throws DebugException
+ */
+ private void writeMemoryBlock(final long offset, final byte[] bytes) throws DebugException {
+
+ // For the IAddress interface
+ final Addr64 address = new Addr64(fBaseAddress);
+
+ // Use a Query to synchronize the downstream calls
+ Query<MemoryByte[]> query = new Query<MemoryByte[]>() {
+ @Override
+ protected void execute(final DataRequestMonitor<MemoryByte[]> drm) {
+ IMemory memoryService = (IMemory) fRetrieval.getServiceTracker().getService();
+ if (memoryService != null) {
+ // Go for it
+ memoryService.setMemory(
+ fContext, address, offset, fWordSize, bytes.length, bytes,
+ new RequestMonitor(fRetrieval.getExecutor(), null));
+ }
+
+ }
+ };
+ fRetrieval.getExecutor().execute(query);
+
+ try {
+ query.get();
+ } catch (InterruptedException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error writing memory block (InterruptedException)", e)); //$NON-NLS-1$
+ } catch (ExecutionException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error writing memory block (ExecutionException)", e)); //$NON-NLS-1$
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Event Handlers
+ ///////////////////////////////////////////////////////////////////////////
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IRunControl.ISuspendedDMEvent e) {
+
+ // Clear the "Changed" flags after each run/resume/step
+ for (int i = 0; i < fLength; i++)
+ fBlock[i].setChanged(false);
+
+ // Generate the MemoryChangedEvents
+ handleMemoryChange(BigInteger.ZERO);
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(IMemoryChangedEvent e) {
+
+ // Check if we are in the same address space
+ if (e.getDMContext().equals(fContext)) {
+ IAddress[] addresses = e.getAddresses();
+ for (int i = 0; i < addresses.length; i++)
+ handleMemoryChange(addresses[i].getValue());
+ }
+ }
+
+ /**
+ * @param address
+ * @param length
+ */
+ public void handleMemoryChange(BigInteger address) {
+
+ // Check if the change affects this particular block (0 is universal)
+ BigInteger fEndAddress = fBlockAddress.add(BigInteger.valueOf(fLength));
+ if (address.equals(BigInteger.ZERO) ||
+ ((fBlockAddress.compareTo(address) != 1) && (fEndAddress.compareTo(address) == 1)))
+ {
+ // Notify the event listeners
+ DebugEvent debugEvent = new DebugEvent(this, DebugEvent.CHANGE, DebugEvent.CONTENT);
+ DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] { debugEvent });
+ }
+ }
+
+ public String[] getUpdatePolicies() {
+ return new String[] {UPDATE_POLICY_AUTOMATIC, UPDATE_POLICY_MANUAL, UPDATE_POLICY_BREAKPOINT};
+ }
+
+ public String getUpdatePolicy()
+ {
+ return fUpdatePolicy;
+ }
+
+ public void setUpdatePolicy(String policy)
+ {
+ fUpdatePolicy = policy;
+ }
+
+ public String getUpdatePolicyDescription(String id) {
+ return id;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java
new file mode 100644
index 00000000000..6c224b78c11
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/model/DsfMemoryBlockRetrieval.java
@@ -0,0 +1,505 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson Communication - upgrade IF to IMemoryBlockRetrievalExtension
+ * Ericsson Communication - added Expression evaluation
+ * Ericsson Communication - added support for 64 bit processors
+ * Ericsson Communication - added support for event handling
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.model;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IExpressions;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues;
+import org.eclipse.cdt.dsf.debug.service.IMemory;
+import org.eclipse.cdt.dsf.debug.service.IExpressions.IExpressionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMContext;
+import org.eclipse.cdt.dsf.debug.service.IFormattedValues.FormattedValueDMData;
+import org.eclipse.cdt.dsf.debug.service.IMemory.IMemoryDMContext;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfServices;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
+import org.eclipse.debug.core.model.IDebugTarget;
+import org.eclipse.debug.core.model.IMemoryBlock;
+import org.eclipse.debug.core.model.IMemoryBlockExtension;
+import org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.util.tracker.ServiceTracker;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * Implementation of memory access API of the Eclipse standard debug model.
+ *
+ * The DsfMemoryBlockRetrieval is not an actual memory block but rather a
+ * reference to the memory address space for an execution context (e.g. a
+ * process) within a debug session. From this debug 'context', memory blocks
+ * can then be read/written.
+ *
+ * Note: For the reference application, The IMemoryBlockRetrievalExtension
+ * is implemented. This will result in getExtendedMemoryBlock() being called
+ * when a memory block is selected from the platform memory pane.
+ *
+ * However, if the 'simpler' IMemoryBlockRetrieval is to be implemented, the
+ * code will still be functional after some trivial adjustments.
+ *
+ */
+public class DsfMemoryBlockRetrieval extends PlatformObject implements IMemoryBlockRetrievalExtension
+{
+ private final String fModelId;
+ private final DsfSession fSession;
+ private final DsfExecutor fExecutor;
+ private final String fContextString;
+ private final ServiceTracker fMemoryServiceTracker;
+ private final ServiceTracker fExpressionServiceTracker;
+
+ private final ILaunchConfiguration fLaunchConfig;
+ private final ILaunch fLaunch;
+ private final IDebugTarget fDebugTarget;
+ private final boolean fSupportsValueModification;
+ private final boolean fSupportBaseAddressModification;
+ private final int fAddressSize;
+ private final int fWordSize; // Number of bytes per address
+
+ /**
+ * Constructor
+ *
+ * @param modelId
+ * @param dmc
+ * @throws DebugException
+ */
+ public DsfMemoryBlockRetrieval(String modelId, ILaunchConfiguration config, DsfSession session) throws DebugException {
+
+ // DSF stuff
+ fModelId = modelId;
+
+ // FIXME: (Bug228573) Currently memory contexts are differentiated by
+ // sessionID so there is no way to guarantee the memory blocks will be
+ // reinstated in the correct memory space.
+ // Need a way to create deterministically the context ID from a unique
+ // target, ideally from the launch configuration (or derived from it).
+ // For the time being, just put some constant. This will work until we
+ // support multiple targets in the same launch.
+ // fContextString = fContext.toString();
+ fContextString = "Context string"; //$NON-NLS-1$
+
+ fSession = session;
+ if (fSession == null) {
+ throw new IllegalArgumentException(
+ "Session " + session + " is not active"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ fExecutor = fSession.getExecutor();
+ BundleContext bundle = DsfPlugin.getBundleContext();
+
+ // Here we chose to use 2 distinct service trackers instead of an
+ // amalgamated one because it is less error prone (and we are lazy).
+
+ // Create a tracker for the MemoryService
+ String memoryServiceFilter = DsfServices.createServiceFilter(IMemory.class, session.getId());
+
+ try {
+ fMemoryServiceTracker = new ServiceTracker(
+ bundle, bundle.createFilter(memoryServiceFilter), null);
+ } catch (InvalidSyntaxException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error creating service filter.", e)); //$NON-NLS-1$
+ }
+ fMemoryServiceTracker.open();
+
+ // Create a tracker for the ExpressionService
+ String expressionServiceFilter = "(&" + //$NON-NLS-1$
+ "(OBJECTCLASS=" //$NON-NLS-1$
+ + IExpressions.class.getName()
+ + ")" + //$NON-NLS-1$
+ "(" + IDsfService.PROP_SESSION_ID //$NON-NLS-1$
+ + "=" + session.getId() + ")" + //$NON-NLS-1$//$NON-NLS-2$
+ ")"; //$NON-NLS-1$
+
+ try {
+ fExpressionServiceTracker = new ServiceTracker(
+ bundle, bundle.createFilter(expressionServiceFilter), null);
+ } catch (InvalidSyntaxException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error creating service filter.", e)); //$NON-NLS-1$
+ }
+ fExpressionServiceTracker.open();
+
+ // Launch configuration information
+ fLaunchConfig = config;
+ fLaunch = null;
+ fDebugTarget = null;
+ fAddressSize = 4; // Get this from the launch configuration
+ fWordSize = 1; // Get this from the launch configuration
+ fSupportsValueModification = true; // Get this from the launch configuration
+ fSupportBaseAddressModification = false; // Get this from the launch configuration
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Memory monitors persistence
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * In the launch configuration file, the memory block entry is structured
+ * as follows (note: this differs from CDI):
+ *
+ * <stringAttribute
+ * key="org.eclipse.dsf.launch.MEMORY_BLOCKS"
+ * value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+ * <memoryBlockExpressionList context=[memory context ID]>
+ * <memoryBlockExpression label=[monitor label] address=[base address]/>
+ * <memoryBlockExpression ...>
+ * ...
+ * </memoryBlockExpressionList>
+ * ...
+ * <memoryBlockExpressionList context=...>
+ * ...
+ * </memoryBlockExpressionList>"
+ * />
+ */
+
+ //-------------------------------------------------------------------------
+ // Memory blocks memento tags
+ //-------------------------------------------------------------------------
+
+ // These 2 really belong in the DSF launch configuration class...
+ private static final String DSF_LAUNCH_ID = "org.eclipse.dsf.launch"; //$NON-NLS-1$
+ private static final String ATTR_DEBUGGER_MEMORY_BLOCKS = DSF_LAUNCH_ID + ".MEMORY_BLOCKS"; //$NON-NLS-1$
+
+ private static final String MEMORY_BLOCK_EXPRESSION_LIST = "memoryBlockExpressionList"; //$NON-NLS-1$
+ private static final String ATTR_EXPRESSION_LIST_CONTEXT = "context"; //$NON-NLS-1$
+ private static final String MEMORY_BLOCK_EXPRESSION = "memoryBlockExpression"; //$NON-NLS-1$
+ private static final String ATTR_MEMORY_BLOCK_EXPR_LABEL = "label"; //$NON-NLS-1$
+ private static final String ATTR_MEMORY_BLOCK_EXPR_ADDRESS = "address"; //$NON-NLS-1$
+
+ //-------------------------------------------------------------------------
+ // Install persisted memory monitors
+ //-------------------------------------------------------------------------
+
+ /**
+ * Restore the memory monitors from the memento in the launch configuration
+ */
+ public void initialize(final IMemoryDMContext memoryCtx) {
+ try {
+ final String memento = fLaunchConfig.getAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, ""); //$NON-NLS-1$
+ if (memento != null && memento.trim().length() != 0) {
+ // Submit the runnable to install the monitors on dispatch thread.
+ getExecutor().submit(new Runnable() {
+ public void run() {
+ try {
+ createBlocksFromConfiguration(memoryCtx, memento);
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ }
+ });
+ }
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ }
+
+ private void createBlocksFromConfiguration(IMemoryDMContext memoryCtx, String memento) throws CoreException {
+
+ // Parse the memento and validate its type
+ Element root = DebugPlugin.parseDocument(memento);
+ if (!root.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION_LIST)) {
+ IStatus status = new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, DebugPlugin.INTERNAL_ERROR,
+ "Memory monitor initialization: invalid memento", null);//$NON-NLS-1$
+ throw new CoreException(status);
+ }
+
+ // Process the block list specific to this memory context
+ // FIXME: (Bug228573) We only process the first entry...
+ if (root.getAttribute(ATTR_EXPRESSION_LIST_CONTEXT).equals(fContextString)) {
+ List<IMemoryBlock> blocks = new ArrayList<IMemoryBlock>();
+ NodeList expressionList = root.getChildNodes();
+ int length = expressionList.getLength();
+ for (int i = 0; i < length; ++i) {
+ Node node = expressionList.item(i);
+ if (node.getNodeType() == Node.ELEMENT_NODE) {
+ Element entry = (Element) node;
+ if (entry.getNodeName().equalsIgnoreCase(MEMORY_BLOCK_EXPRESSION)) {
+ String label = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL);
+ String address = entry.getAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS);
+ BigInteger blockAddress = new BigInteger(address);
+ DsfMemoryBlock block = new DsfMemoryBlock(this, memoryCtx, fModelId, label, blockAddress, fWordSize, 0);
+ blocks.add(block);
+ }
+ }
+ }
+ DebugPlugin.getDefault().getMemoryBlockManager().addMemoryBlocks( blocks.toArray(new IMemoryBlock[blocks.size()]));
+ }
+ }
+
+ // FIXME: (Bug228573) Each retrieval overwrites the previous one :-(
+
+ // In theory, we should make this a Job since we are writing to the file system.
+ // However, this would cause the same racing condition as Bug228308. Finally, we
+ // don't care too much about the UI responsiveness since we are in the process of
+ // shutting down :-)
+ public void saveMemoryBlocks() {
+ try {
+ ILaunchConfigurationWorkingCopy wc = fLaunchConfig.getWorkingCopy();
+ wc.setAttribute(ATTR_DEBUGGER_MEMORY_BLOCKS, getMemento());
+ wc.doSave();
+ }
+ catch( CoreException e ) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ }
+ }
+
+ public String getMemento() throws CoreException {
+ IMemoryBlock[] blocks = DebugPlugin.getDefault().getMemoryBlockManager().getMemoryBlocks(this);
+ Document document = DebugPlugin.newDocument();
+ Element expressionList = document.createElement(MEMORY_BLOCK_EXPRESSION_LIST);
+ expressionList.setAttribute(ATTR_EXPRESSION_LIST_CONTEXT, fContextString);
+ for (IMemoryBlock block : blocks) {
+ if (block instanceof IMemoryBlockExtension) {
+ IMemoryBlockExtension memoryBlock = (IMemoryBlockExtension) block;
+ Element expression = document.createElement(MEMORY_BLOCK_EXPRESSION);
+ expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_LABEL, memoryBlock.getExpression());
+ expression.setAttribute(ATTR_MEMORY_BLOCK_EXPR_ADDRESS, memoryBlock.getBigBaseAddress().toString());
+ expressionList.appendChild(expression);
+ }
+ }
+ document.appendChild(expressionList);
+ return DebugPlugin.serializeDocument(document);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Accessors
+ ///////////////////////////////////////////////////////////////////////////
+
+ public DsfSession getSession() {
+ return fSession;
+ }
+
+ public DsfExecutor getExecutor() {
+ return fExecutor;
+ }
+
+ public ServiceTracker getServiceTracker() {
+ return fMemoryServiceTracker;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Launch/Target specific information
+ ///////////////////////////////////////////////////////////////////////////
+
+ public ILaunch getLaunch() {
+ return fLaunch;
+ }
+
+ public IDebugTarget getDebugTarget() {
+ return fDebugTarget;
+ }
+
+ public int getAddressSize() {
+ return fAddressSize;
+ }
+
+ public int getAddressableSize() {
+ return fWordSize;
+ }
+
+ public boolean supportsValueModification() {
+ return fSupportsValueModification;
+ }
+
+ public boolean supportBaseAddressModification() {
+ return fSupportBaseAddressModification;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IMemoryBlockRetrieval - obsoleted by IMemoryBlockRetrievalExtension
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#supportsStorageRetrieval()
+ */
+ public boolean supportsStorageRetrieval() {
+ return true;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IMemoryBlockRetrieval#getMemoryBlock(long,
+ * long)
+ */
+ public IMemoryBlock getMemoryBlock(final long startAddress, final long length) throws DebugException {
+ throw new DebugException(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, DebugException.NOT_SUPPORTED,
+ "getMemoryBlock() not supported, use getExtendedMemoryBlock()", null)); //$NON-NLS-1$
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IMemoryBlockRetrievalExtension
+ ///////////////////////////////////////////////////////////////////////////
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.debug.core.model.IMemoryBlockRetrievalExtension#getExtendedMemoryBlock(java.lang.String,
+ * java.lang.Object)
+ */
+ public IMemoryBlockExtension getExtendedMemoryBlock(String expression, Object context) throws DebugException {
+ // Drill for the actual DMC
+ IMemoryDMContext memoryDmc = null;
+ IDMContext dmc = null;
+ if (context instanceof IAdaptable) {
+ dmc = (IDMContext)((IAdaptable)context).getAdapter(IDMContext.class);
+ if (dmc != null) {
+ memoryDmc = DMContexts.getAncestorOfType(dmc, IMemoryDMContext.class);
+ }
+ }
+
+ if (memoryDmc == null) {
+ return null;
+ }
+
+ // The block start address (supports 64-bit processors)
+ BigInteger blockAddress;
+
+ /*
+ * See if the expression is a simple numeric value; if it is, we can
+ * avoid some costly processing (calling the back-end to resolve the
+ * expression and obtain an address)
+ */
+ try {
+ // First, assume a decimal address
+ int base = 10;
+ int offset = 0;
+
+ // Check for "hexadecimality"
+ if (expression.startsWith("0x") || expression.startsWith("0X")) { //$NON-NLS-1$//$NON-NLS-2$
+ base = 16;
+ offset = 2;
+ }
+ // Check for "binarity"
+ else if (expression.startsWith("0b")) { //$NON-NLS-1$
+ base = 2;
+ offset = 2;
+ }
+ // Check for "octality"
+ else if (expression.startsWith("0")) { //$NON-NLS-1$
+ base = 8;
+ offset = 1;
+ }
+ // Now, try to parse the expression. If a NumberFormatException is
+ // thrown, then it wasn't a simple numerical expression and we go
+ // to plan B (attempt an expression evaluation)
+ blockAddress = new BigInteger(expression.substring(offset), base);
+
+ } catch (NumberFormatException nfexc) {
+ // OK, expression is not a simple, absolute numeric value;
+ // try to resolve as an expression.
+ // In case of failure, simply return 'null'
+
+ // Resolve the expression
+ blockAddress = resolveMemoryAddress(dmc, expression);
+ if (blockAddress == null) {
+ return null;
+ }
+ }
+
+ /*
+ * At this point, we only resolved the requested memory block
+ * start address and we have no idea of the block's length.
+ *
+ * The renderer will provide this information when it calls
+ * getBytesFromAddress() i.e. after the memory block holder has
+ * been instantiated.
+ *
+ * The down side is that every time we switch renderer, for the
+ * same memory block, a trip to the target could result. However,
+ * the memory request cache should save the day.
+ */
+
+ return new DsfMemoryBlock(this, memoryDmc, fModelId, expression, blockAddress, fWordSize, 0);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Helper functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ private BigInteger resolveMemoryAddress(final IDMContext dmc, final String expression) throws DebugException {
+
+ // Use a Query to "synchronize" the downstream calls
+ Query<BigInteger> query = new Query<BigInteger>() {
+ @Override
+ protected void execute(final DataRequestMonitor<BigInteger> drm) {
+ // Lookup for the ExpressionService
+ final IExpressions expressionService = (IExpressions) fExpressionServiceTracker.getService();
+ if (expressionService != null) {
+ // Create the expression
+ final IExpressionDMContext expressionDMC = expressionService.createExpression(dmc, expression);
+ String formatId = IFormattedValues.HEX_FORMAT;
+ FormattedValueDMContext valueDmc = expressionService.getFormattedValueContext(expressionDMC, formatId);
+ expressionService.getFormattedExpressionValue(
+ valueDmc,
+ new DataRequestMonitor<FormattedValueDMData>(getExecutor(), drm) {
+ @Override
+ protected void handleSuccess() {
+ // Store the result
+ FormattedValueDMData data = getData();
+ String value = data.getFormattedValue().substring(2); // Strip the "0x"
+ drm.setData(new BigInteger(value, 16));
+ drm.done();
+ }
+ }
+ );
+ }
+ }
+ };
+ fExecutor.execute(query);
+
+ try {
+ // The happy case
+ return query.get();
+ } catch (InterruptedException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error evaluating memory address (InterruptedException).", e)); //$NON-NLS-1$
+
+ } catch (ExecutionException e) {
+ throw new DebugException(new Status(IStatus.ERROR,
+ DsfPlugin.PLUGIN_ID, DebugException.INTERNAL_ERROR,
+ "Error evaluating memory address (ExecutionException).", e)); //$NON-NLS-1$
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java
new file mode 100644
index 00000000000..f93655ba9d2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/AbstractDsfDebugServicesFactory.java
@@ -0,0 +1,69 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.debug.service.command.ICommandControl;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * Convenience base class for {@link IDsfDebugServicesFactory}
+ * @since 1.1
+ */
+public abstract class AbstractDsfDebugServicesFactory implements IDsfDebugServicesFactory {
+
+ @SuppressWarnings("unchecked")
+ public <V> V createService(Class<V> clazz, DsfSession session, Object ... optionalArguments) {
+ if (IBreakpoints.class.isAssignableFrom(clazz)) {
+ return (V)createBreakpointService(session);
+ } else if (ICommandControl.class.isAssignableFrom(clazz)) {
+ return (V)createCommandControl(session);
+ } else if (IDisassembly.class.isAssignableFrom(clazz)) {
+ return (V)createDisassemblyService(session);
+ } else if (IExpressions.class.isAssignableFrom(clazz)) {
+ return (V)createExpressionService(session);
+ } else if (IMemory.class.isAssignableFrom(clazz)) {
+ return (V)createMemoryService(session);
+ } else if (IModules.class.isAssignableFrom(clazz)) {
+ return (V)createModulesService(session);
+ } else if (IProcesses.class.isAssignableFrom(clazz)) {
+ return (V)createProcessesService(session);
+ } else if (IRegisters.class.isAssignableFrom(clazz)) {
+ return (V)createRegistersService(session);
+ } else if (IRunControl.class.isAssignableFrom(clazz)) {
+ return (V)createRunControlService(session);
+ } else if (ISourceLookup.class.isAssignableFrom(clazz)) {
+ return (V)createSourceLookupService(session);
+ } else if (ISignals.class.isAssignableFrom(clazz)) {
+ return (V)createSignalsService(session);
+ } else if (IStack.class.isAssignableFrom(clazz)) {
+ return (V)createStackService(session);
+ } else if (ISymbols.class.isAssignableFrom(clazz)) {
+ return (V)createSymbolsService(session);
+ }
+
+ return null;
+ }
+
+ protected IBreakpoints createBreakpointService(DsfSession session) { return null; }
+ protected ICommandControl createCommandControl(DsfSession session) { return null; }
+ protected IDisassembly createDisassemblyService(DsfSession session) { return null; }
+ protected IExpressions createExpressionService(DsfSession session) { return null; }
+ protected IMemory createMemoryService(DsfSession session) { return null; }
+ protected IModules createModulesService(DsfSession session) { return null; }
+ protected IProcesses createProcessesService(DsfSession session) { return null; }
+ protected IRegisters createRegistersService(DsfSession session) { return null; }
+ protected IRunControl createRunControlService(DsfSession session) { return null; }
+ protected ISourceLookup createSourceLookupService(DsfSession session) { return null; }
+ protected ISignals createSignalsService(DsfSession session) { return null; }
+ protected IStack createStackService(DsfSession session) { return null; }
+ protected ISymbols createSymbolsService(DsfSession session) { return null; }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java
new file mode 100644
index 00000000000..864c3400f20
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/BreakpointsMediator.java
@@ -0,0 +1,886 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River 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:
+ * Wind River - Initial API and implementation
+ * Ericsson - Low-level breakpoints integration
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.RejectedExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.CountingRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.resources.IMarkerDelta;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IBreakpointListener;
+import org.eclipse.debug.core.IBreakpointManager;
+import org.eclipse.debug.core.IBreakpointManagerListener;
+import org.eclipse.debug.core.model.IBreakpoint;
+import org.osgi.framework.BundleContext;
+
+/**
+ *
+ */
+public class BreakpointsMediator extends AbstractDsfService implements IBreakpointManagerListener, IBreakpointListener
+{
+
+ /**
+ * The attribute translator that this service will use to map the platform
+ * breakpiont attributes to the corresponding target attributes, and vice
+ * versa.
+ */
+ private IBreakpointAttributeTranslator fAttributeTranslator;
+
+ /**
+ * DSF Debug service for creating breakpoints.
+ */
+ IBreakpoints fBreakpoints;
+
+ /**
+ * Platform breakpoint manager
+ */
+ IBreakpointManager fBreakpointManager;
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Breakpoints tracking
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Holds the set of platform breakpoints with their corresponding back-end
+ * breakpoint attributes, per context (i.e. each platform breakpoint is
+ * replicated for each execution context).
+ * - Context entry added/removed on start/stopTrackingBreakpoints()
+ * - Augmented on breakpointAdded()
+ * - Modified on breakpointChanged()
+ * - Diminished on breakpointRemoved()
+ */
+ private Map<IBreakpointsTargetDMContext, Map<IBreakpoint, List<Map<String, Object>>>> fPlatformBPs =
+ new HashMap<IBreakpointsTargetDMContext, Map<IBreakpoint, List<Map<String, Object>>>>();
+
+ /**
+ * Holds the mapping from platform breakpoint to the corresponding target
+ * breakpoint(s), per context. There can be multiple back-end BPs for a
+ * single platform BP in the case of [1] multiple target contexts, and/or
+ * [2] thread filtering.
+ * Updated when:
+ * - We start/stop tracking an execution context
+ * - A platform breakpoint is added/removed
+ * - A thread filter is applied/removed
+ */
+ private Map<IBreakpointsTargetDMContext, Map<IBreakpoint, List<IBreakpointDMContext>>> fBreakpointDMContexts =
+ new HashMap<IBreakpointsTargetDMContext, Map<IBreakpoint, List<IBreakpointDMContext>>>();
+
+ /**
+ * Due to the very asynchronous nature of DSF, a new breakpoint request can
+ * pop up at any time before an ongoing one is completed. The following set
+ * is used to store requests until the ongoing operation completes.
+ */
+ private Set<IBreakpoint> fPendingRequests = new HashSet<IBreakpoint>();
+
+ /**
+ * @see fPendingRequests
+ */
+ private Set<IBreakpoint> fPendingBreakpoints = new HashSet<IBreakpoint>();
+
+ ///////////////////////////////////////////////////////////////////////////
+ // AbstractDsfService
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * The service constructor
+ *
+ * @param session
+ * @param debugModelId
+ */
+ public BreakpointsMediator(DsfSession session, IBreakpointAttributeTranslator attributeTranslator) {
+ super(session);
+ fAttributeTranslator = attributeTranslator;
+ }
+
+ @Override
+ public void initialize(final RequestMonitor rm) {
+ // - Collect references for the services we interact with
+ // - Register to interesting events
+ // - Obtain the list of platform breakpoints
+ // - Register the service for interested parties
+ super.initialize(
+ new RequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(rm);
+ }});
+ }
+
+ /**
+ * Asynchronous service initialization
+ *
+ * @param requestMonitor
+ */
+ private void doInitialize(RequestMonitor rm) {
+
+ // Get the services references
+ fBreakpoints = getServicesTracker().getService(IBreakpoints.class);
+ fBreakpointManager = DebugPlugin.getDefault().getBreakpointManager();
+ fAttributeTranslator.initialize(this);
+
+ // Register to the useful events
+ fBreakpointManager.addBreakpointListener(this);
+ fBreakpointManager.addBreakpointManagerListener( this );
+
+ // Register this service
+ register(new String[] { BreakpointsMediator.class.getName() },
+ new Hashtable<String, String>());
+
+ rm.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor rm) {
+ // - Un-register the service
+ // - Stop listening to events
+ // - Remove the breakpoints installed by this service
+ //
+ // Since we are shutting down, there is no overwhelming need
+ // to keep the maps coherent...
+
+ // Stop accepting requests and events
+ unregister();
+ fBreakpointManager.removeBreakpointListener(this);
+ fBreakpointManager.removeBreakpointManagerListener( this );
+ fAttributeTranslator.dispose();
+
+ // Cleanup the breakpoints that are still installed by the service.
+ // Use a counting monitor which will call mom to complete the shutdown
+ // after the breakpoints are un-installed (successfully or not).
+ CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ BreakpointsMediator.super.shutdown(rm);
+ }
+ };
+
+ // We have to make a copy of the fPlatformBPs keys because uninstallBreakpoints()
+ // modifies the map as it walks through it.
+ List<IBreakpointsTargetDMContext> platformBPKeysCopy = new ArrayList<IBreakpointsTargetDMContext>(fPlatformBPs.size());
+ platformBPKeysCopy.addAll(0, fPlatformBPs.keySet());
+ for (IBreakpointsTargetDMContext dmc : platformBPKeysCopy) {
+ stopTrackingBreakpoints(dmc, countingRm);
+ }
+ countingRm.setDoneCount(platformBPKeysCopy.size());
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfPlugin.getBundleContext();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IBreakpointsManager
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Install and begin tracking breakpoints for given context. The service
+ * will keep installing new breakpoints that appear in the IDE for this
+ * context until {@link #uninstallBreakpoints(IDMContext)} is called for that
+ * context.
+ * @param dmc Context to start tracking breakpoints for.
+ * @param rm Completion callback.
+ */
+ public void startTrackingBreakpoints(IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
+ // - Augment the maps with the new execution context
+ // - Install the platform breakpoints on the selected target
+
+ // Validate the context
+ final IBreakpointsTargetDMContext breakpointsDmc = DMContexts.getAncestorOfType(dmc, IBreakpointsTargetDMContext.class);
+ if (breakpointsDmc == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Invalid context type", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Make sure a mapping for this execution context does not already exist
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs != null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Context already initialized", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Create entries in the breakpoint tables for the new context. These entries should only
+ // be removed when this service stops tracking breakpoints for the given context.
+ fPlatformBPs.put(breakpointsDmc, new HashMap<IBreakpoint, List<Map<String, Object>>>());
+ fBreakpointDMContexts.put(breakpointsDmc, new HashMap<IBreakpoint, List<IBreakpointDMContext>>());
+
+ // Install the platform breakpoints (stored in fPlatformBPs) on the target.
+ // We need to use a background thread for this operation because we are
+ // accessing the resources system to retrieve the breakpoint attributes.
+ // Accessing the resources system potentially requires using global locks.
+ // Also we will be calling IBreakpointAttributeTranslator which is prohibited
+ // from being called on the session executor thread.
+ new Job("MI Debugger: Install initial breakpoint list.") { //$NON-NLS-1$
+ { setSystem(true); }
+
+ // Get the stored breakpoints from the platform BreakpointManager
+ // and install them on the target
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ // Read initial breakpoints from platform. Copy the breakpoint attributes into a local map.
+ // Note that we cannot write data into fPlatformBPs table here directly because we are not
+ // executing on the dispatch thread.
+ final Map<IBreakpoint, List<Map<String, Object>>> initialPlatformBPs =
+ new HashMap<IBreakpoint, List<Map<String, Object>>>();
+ try {
+ // Get the stored breakpoint list from the platform BreakpointManager
+ IBreakpoint[] bps = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints();
+ // Single out the installable breakpoints...
+ for (IBreakpoint bp : bps) {
+ if (fAttributeTranslator.supportsBreakpoint(bp)) {
+ // Retrieve the breakpoint attributes
+ List<Map<String, Object>> attrsArray =
+ fAttributeTranslator.getBreakpointAttributes(bp, fBreakpointManager.isEnabled());
+ // Store it for now (will be installed on the dispatcher thread)
+ initialPlatformBPs.put(bp, attrsArray);
+ }
+ }
+ } catch (CoreException e) {
+ IStatus status = new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, REQUEST_FAILED, "Unable to read initial breakpoint attributes", e); //$NON-NLS-1$
+ rm.setStatus(status);
+ rm.done();
+ return status;
+ }
+
+ // Submit the runnable to plant the breakpoints on dispatch thread.
+ getExecutor().submit(new Runnable() {
+ public void run() {
+ installInitialBreakpoints(breakpointsDmc, initialPlatformBPs, rm);
+ }
+ });
+
+ return Status.OK_STATUS;
+ }
+ }.schedule();
+ }
+
+ /**
+ * Installs the breakpoints that existed prior to the activation of this
+ * breakpoints context.
+ */
+ private void installInitialBreakpoints(final IBreakpointsTargetDMContext dmc,
+ Map<IBreakpoint, List<Map<String, Object>>> initialPlatformBPs,
+ RequestMonitor rm)
+ {
+ // Retrieve the set of platform breakpoints for this context
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Install the individual breakpoints on the executor thread
+ // Requires a counting monitor to know when we're done
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm);
+ countingRm.setDoneCount(initialPlatformBPs.size());
+
+ for (final IBreakpoint bp : initialPlatformBPs.keySet()) {
+ final List<Map<String, Object>> attrs = initialPlatformBPs.get(bp);
+ // Upon determining the debuggerPath, the breakpoint is installed
+ installBreakpoint(dmc, bp, attrs, new RequestMonitor(getExecutor(), countingRm));
+ }
+ }
+
+
+ public void stopTrackingBreakpoints(final IBreakpointsTargetDMContext dmc, final RequestMonitor rm) {
+ // - Remove the target breakpoints for the given execution context
+ // - Update the maps
+
+ // Remove the breakpoints for given DMC from the internal maps.
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INTERNAL_ERROR, "Breakpoints not installed for given context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Uninstall the individual breakpoints on the executor thread
+ // Requires a counting monitor to know when we're done
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), rm);
+ countingRm.setDoneCount(platformBPs.size());
+
+ for (final IBreakpoint bp : platformBPs.keySet()) {
+ uninstallBreakpoint(dmc, bp,
+ new RequestMonitor(getExecutor(), countingRm) {
+ @Override
+ protected void handleCompleted() {
+ // After the breakpoint is removed from target. Call the attribute
+ // translator to refresh breakpoint status based on the new target
+ // breakpoint status.
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(bp);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+
+ countingRm.done();
+ }
+ });
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Back-end interface functions
+ ///////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Install a new platform breakpoint on the back-end. A platform breakpoint
+ * can resolve into multiple back-end breakpoints when threads are taken
+ * into account.
+ *
+ * @param dmc
+ * @param breakpoint
+ * @param attrsList
+ * @param rm
+ */
+ private void installBreakpoint(IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint,
+ final List<Map<String, Object>> attrsList, final RequestMonitor rm)
+ {
+ // Retrieve the set of breakpoints for this context
+ final Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ assert platformBPs != null;
+
+ final Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
+ assert breakpointIDs != null; // fBreakpointIds should be updated in parallel with fPlatformBPs
+
+ // Ensure the breakpoint is not already installed
+ if (platformBPs.containsKey(breakpoint)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_STATE, "Breakpoint already installed", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Update the breakpoint status when all back-end breakpoints have been installed
+ final CountingRequestMonitor installRM = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ // Store the platform breakpoint
+ platformBPs.put(breakpoint, attrsList);
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(breakpoint);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+ rm.done();
+ }
+ };
+
+ // A back-end breakpoint needs to be installed for each specified attributes map.
+ installRM.setDoneCount(attrsList.size());
+
+ // Install the back-end breakpoint(s)
+ for (Map<String, Object> attrs : attrsList) {
+ fBreakpoints.insertBreakpoint(
+ dmc, attrs,
+ new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), installRM) {
+ @Override
+ protected void handleCompleted() {
+ List<IBreakpointDMContext> list = breakpointIDs.get(breakpoint);
+ if (list == null) {
+ list = new LinkedList<IBreakpointDMContext>();
+ breakpointIDs.put(breakpoint, list);
+ }
+
+ if (isSuccess()) {
+ // Add the breakpoint back-end mapping
+ list.add(getData());
+ } else {
+ // TODO (bug 219841): need to add breakpoint error status tracking
+ // in addition to fBreakpointDMContexts.
+ }
+ installRM.done();
+ }
+ });
+ }
+ }
+
+ /**
+ * Un-install an individual breakpoint on the back-end. For one platform
+ * breakpoint, there could be multiple corresponding back-end breakpoints.
+ *
+ * @param dmc
+ * @param breakpoint
+ * @param rm
+ */
+ private void uninstallBreakpoint(final IBreakpointsTargetDMContext dmc, final IBreakpoint breakpoint,
+ final RequestMonitor rm)
+ {
+ // Remove completion monitor
+ CountingRequestMonitor removeRM = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ // Remove the attributes mapping
+ Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(dmc);
+ if (platformBPs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ platformBPs.remove(breakpoint);
+
+ // Remove the back-end mapping
+ Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
+ if (breakpointIDs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ breakpointIDs.get(breakpoint).clear();
+ breakpointIDs.remove(breakpoint);
+
+ // Update breakpoint status
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(breakpoint);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+
+ rm.done();
+ }
+ };
+
+ // Remove the back-end breakpoints
+ Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(dmc);
+ if (breakpointIDs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ List<IBreakpointDMContext> list = breakpointIDs.get(breakpoint);
+ int count = 0;
+ if (list != null) {
+ for (IBreakpointDMContext bp : list) {
+ fBreakpoints.removeBreakpoint(bp, removeRM);
+ }
+ count = list.size();
+ }
+ removeRM.setDoneCount(count);
+ }
+
+ /**
+ * Modify an individual breakpoint
+ *
+ * @param context
+ * @param breakpoint
+ * @param attributes
+ * @param rm
+ * @throws CoreException
+ */
+ private void modifyBreakpoint(final IBreakpointsTargetDMContext context, final IBreakpoint breakpoint,
+ final List<Map<String, Object>> newAttrsList0, final IMarkerDelta oldValues, final RequestMonitor rm)
+ {
+ // This method uses several lists to track the changed breakpoints:
+ // commonAttrsList - attributes which have not changed
+ // oldAttrsList - attributes for the breakpoint before the change
+ // newAttrsList - attributes for the breakpoint after the change
+ // oldBpContexts - target-side breakpoints from before the change
+ // newBpContexts - target-side breakpoints after the change
+ // attrDeltasList - changes in the attributes for each attribute map in
+ // oldAttrsList and newAttrsList
+
+ // Get the maps
+ final Map<IBreakpoint, List<Map<String, Object>>> platformBPs = fPlatformBPs.get(context);
+ final Map<IBreakpoint, List<IBreakpointDMContext>> breakpointIDs = fBreakpointDMContexts.get(context);
+ if (platformBPs == null || breakpointIDs == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Get the original breakpoint attributes
+ final List<Map<String, Object>> oldAttrsList0 = platformBPs.get(breakpoint);
+ if (oldAttrsList0 == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Get the list of corresponding back-end breakpoints
+ final List<IBreakpointDMContext> oldBpContexts = new ArrayList<IBreakpointDMContext>(breakpointIDs.get(breakpoint));
+ if (oldBpContexts == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid breakpoint", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ // Calculate the list of attributes maps that have not changed.
+ // Immediately add these to the list of new breakpoint contexts,
+ // and remove them from further breakpoint attribute comparisons.
+ final List<Map<String, Object>> commonAttrsList = getCommonAttributeMaps(newAttrsList0, oldAttrsList0);
+ final List<IBreakpointDMContext> newBpContexts = new ArrayList<IBreakpointDMContext>(commonAttrsList.size());
+
+ final List<Map<String, Object>> newAttrsList = new ArrayList<Map<String, Object>>(newAttrsList0);
+ newAttrsList.removeAll(commonAttrsList);
+
+ List<Map<String, Object>> oldAttrsList = new ArrayList<Map<String, Object>>(oldAttrsList0);
+ for (int i = 0; i < oldAttrsList.size(); i++) {
+ if (commonAttrsList.contains(oldAttrsList.get(i))) {
+ if (oldBpContexts.size() > i) {
+ newBpContexts.add(oldBpContexts.remove(i));
+ }
+ }
+ }
+ oldAttrsList.removeAll(commonAttrsList);
+
+ // Create a list of attribute changes. The lenghth of this list will
+ // always be max(oldAttrList.size(), newAttrsList.size()), padded with
+ // null's if oldAttrsList was longer.
+ final List<Map<String, Object>> attrDeltasList = getAttributesDeltas(oldAttrsList, newAttrsList);
+
+ // Create the request monitor that will be called when all
+ // modifying/inserting/removing is complete.
+ final CountingRequestMonitor countingRM = new CountingRequestMonitor(getExecutor(), rm) {
+ @Override
+ protected void handleCompleted() {
+ // Save the new list of breakpoint contexts and attributes
+ breakpointIDs.put(breakpoint, newBpContexts);
+ newAttrsList.addAll(commonAttrsList);
+ platformBPs.put(breakpoint, newAttrsList);
+
+ // Update breakpoint status. updateBreakpointStatus() cannot
+ // be called on the executor thread, so we need to
+ // use a Job.
+ new Job("Breakpoint status update") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ fAttributeTranslator.updateBreakpointStatus(breakpoint);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+
+ super.handleCompleted();
+ }
+ };
+
+ // Set the count, if could be zero if no breakpoints have actually changed.
+ countingRM.setDoneCount(attrDeltasList.size());
+
+ // Process the changed breakpoints.
+ for (int i = 0; i < attrDeltasList.size(); i++) {
+ if (attrDeltasList.get(i) == null) {
+ // The list of new attribute maps was shorter than the old.
+ // Remove the corresponding target-side bp.
+ fBreakpoints.removeBreakpoint(oldBpContexts.get(i), countingRM);
+ } else if ( i >= oldBpContexts.size()) {
+ // The list of new attribute maps was longer, just insert
+ // the new breakpoint
+ final Map<String, Object> attrs = newAttrsList.get(i);
+ fBreakpoints.insertBreakpoint(
+ context, attrs,
+ new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
+ @Override
+ protected void handleSuccess() {
+ newBpContexts.add(getData());
+ countingRM.done();
+ }
+ });
+ } else if ( !fAttributeTranslator.canUpdateAttributes(oldBpContexts.get(i), attrDeltasList.get(i)) ) {
+ // The attribute translator tells us that the debugger cannot modify the
+ // breakpoint to change the given attributes. Remove the breakpoint
+ // and insert a new one.
+ final Map<String, Object> attrs = newAttrsList.get(i);
+ fBreakpoints.removeBreakpoint(
+ oldBpContexts.get(i),
+ new RequestMonitor(getExecutor(), countingRM) {
+ @Override
+ protected void handleCompleted() {
+ fBreakpoints.insertBreakpoint(
+ context, attrs,
+ new DataRequestMonitor<IBreakpointDMContext>(getExecutor(), countingRM) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess()) {
+ newBpContexts.add(getData());
+ } else {
+ // TODO (bug 219841): need to add breakpoint error status tracking
+ // in addition to fBreakpointDMContexts.
+ }
+ countingRM.done();
+ }
+ });
+ }
+ });
+ } else {
+ // The back end can modify the breakpoint. Update the breakpoint with the
+ // new attributes.
+ final IBreakpointDMContext bpCtx = oldBpContexts.get(i);
+ fBreakpoints.updateBreakpoint(
+ oldBpContexts.get(i), newAttrsList.get(i),
+ new RequestMonitor(getExecutor(), countingRM) {
+ @Override
+ protected void handleSuccess() {
+ newBpContexts.add(bpCtx);
+ countingRM.done();
+ }
+ });
+ }
+ }
+ }
+
+ private List<Map<String, Object>> getCommonAttributeMaps(List<Map<String, Object>> array1, List<Map<String, Object>> array2)
+ {
+ List<Map<String, Object>> intersection = new LinkedList<Map<String, Object>>();
+ List<Map<String, Object>> list2 = new ArrayList<Map<String, Object>>(array2);
+ for (Map<String, Object> array1Map : array1) {
+ if (list2.remove(array1Map)) {
+ intersection.add(array1Map);
+ }
+ }
+ return intersection;
+ }
+
+ /**
+ * Determine the set of modified attributes
+ *
+ * @param oldAttributes
+ * @param newAttributes
+ * @return
+ */
+ private List<Map<String, Object>> getAttributesDeltas(List<Map<String, Object>> oldAttributesList, List<Map<String, Object>> newAttributesList) {
+ List<Map<String, Object>> deltas = new ArrayList<Map<String, Object>>(oldAttributesList.size());
+
+ // Go through the bp attributes common to the old and the new lists and calculate
+ // their deltas.
+ for (int i = 0; i < oldAttributesList.size() && i < newAttributesList.size(); i++) {
+ Map<String, Object> oldAttributes = oldAttributesList.get(i);
+ Map<String, Object> newAttributes = newAttributesList.get(i);
+
+ Map<String, Object> delta = new HashMap<String, Object>();
+
+ Set<String> oldKeySet = oldAttributes.keySet();
+ Set<String> newKeySet = newAttributes.keySet();
+
+ Set<String> commonKeys = new HashSet<String>(newKeySet); commonKeys.retainAll(oldKeySet);
+ Set<String> addedKeys = new HashSet<String>(newKeySet); addedKeys.removeAll(oldKeySet);
+ Set<String> removedKeys = new HashSet<String>(oldKeySet); removedKeys.removeAll(newKeySet);
+
+ // Add the modified attributes
+ for (String key : commonKeys) {
+ if (!(oldAttributes.get(key).equals(newAttributes.get(key))))
+ delta.put(key, newAttributes.get(key));
+ }
+
+ // Add the new attributes
+ for (String key : addedKeys) {
+ delta.put(key, newAttributes.get(key));
+ }
+
+ // Remove the deleted attributes
+ for (String key : removedKeys) {
+ delta.put(key, null);
+ }
+ deltas.add(delta);
+ }
+
+ // Add all the new attributes as deltas
+ for (int i = deltas.size(); i < newAttributesList.size(); i++) {
+ deltas.add(newAttributesList.get(i));
+ }
+
+ // For any old attribute Maps that were removed, insert a null value in the deltas list.
+ for (int i = deltas.size(); i < oldAttributesList.size(); i++) {
+ deltas.add(null);
+ }
+
+ return deltas;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IBreakpointManagerListener implementation
+ ///////////////////////////////////////////////////////////////////////////
+
+ public void breakpointManagerEnablementChanged(boolean enabled) {
+ for (IBreakpoint breakpoint : fBreakpointManager.getBreakpoints()) {
+ breakpointChanged(breakpoint, null);
+ }
+ }
+
+ @ThreadSafe
+ public void breakpointAdded(final IBreakpoint breakpoint) {
+ if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
+ try {
+ // Retrieve the breakpoint attributes
+ final List<Map<String, Object>> attrsArray =
+ fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled());
+
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ //TODO pp: need to track pending requests
+
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleError() {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ DsfPlugin.getDefault().getLog().log(getStatus());
+ }
+ }
+ };
+ countingRm.setDoneCount(fPlatformBPs.size());
+
+ // Install the breakpoint in all the execution contexts
+ for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
+ installBreakpoint(dmc, breakpoint, attrsArray, new RequestMonitor(getExecutor(), countingRm));
+ }
+ }
+ });
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ } catch (RejectedExecutionException e) {
+ }
+ }
+
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IBreakpointListener implementation
+ ///////////////////////////////////////////////////////////////////////////
+
+ public void breakpointChanged(final IBreakpoint breakpoint, final IMarkerDelta delta) {
+ if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
+ try {
+ // Retrieve the breakpoint attributes
+ final List<Map<String, Object>> attrsArray =
+ fAttributeTranslator.getBreakpointAttributes(breakpoint, fBreakpointManager.isEnabled());
+
+ // Modify the breakpoint in all the target contexts
+ getExecutor().execute( new DsfRunnable() {
+ public void run() {
+
+ // If the breakpoint is currently being updated, queue the request and exit
+ if (fPendingRequests.contains(breakpoint)) {
+ fPendingBreakpoints.add(breakpoint);
+ return;
+ }
+
+ // Keep track of the updates
+ final CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+
+ if (!isSuccess()) {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ DsfPlugin.getDefault().getLog().log(getStatus());
+ }
+ }
+
+ // Indicate that the pending request has completed
+ fPendingRequests.remove(breakpoint);
+
+ // Process the next pending update for this breakpoint
+ if (fPendingBreakpoints.contains(breakpoint)) {
+ fPendingBreakpoints.remove(breakpoint);
+ new Job("Deferred breakpoint changed job") { //$NON-NLS-1$
+ { setSystem(true); }
+ @Override
+ protected IStatus run(IProgressMonitor monitor) {
+ breakpointChanged(breakpoint, delta);
+ return Status.OK_STATUS;
+ };
+ }.schedule();
+ }
+ }
+ };
+ countingRm.setDoneCount(fPlatformBPs.size());
+
+ // Mark the breakpoint as being updated and go
+ fPendingRequests.add(breakpoint);
+
+ // Modify the breakpoint in all the execution contexts
+ for (final IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
+ modifyBreakpoint(dmc, breakpoint, attrsArray, delta, new RequestMonitor(getExecutor(), countingRm));
+ }
+ }
+ });
+ } catch (CoreException e) {
+ DsfPlugin.getDefault().getLog().log(e.getStatus());
+ } catch (RejectedExecutionException e) {
+ }
+ }
+
+ }
+
+ public void breakpointRemoved(final IBreakpoint breakpoint, IMarkerDelta delta) {
+
+ if (fAttributeTranslator.supportsBreakpoint(breakpoint)) {
+ try {
+ getExecutor().execute(new DsfRunnable() {
+ public void run() {
+ //TODO pp: need to track pending requests
+
+ CountingRequestMonitor countingRm = new CountingRequestMonitor(getExecutor(), null) {
+ @Override
+ protected void handleError() {
+ if (getStatus().getSeverity() == IStatus.ERROR) {
+ DsfPlugin.getDefault().getLog().log(getStatus());
+ }
+ }
+ };
+ countingRm.setDoneCount(fPlatformBPs.size());
+
+ // Remove the breakpoint in all the execution contexts
+ for (IBreakpointsTargetDMContext dmc : fPlatformBPs.keySet()) {
+ if (fPlatformBPs.get(dmc).remove(breakpoint) != null) {
+ uninstallBreakpoint(dmc, breakpoint, countingRm);
+ } else {
+ // Breakpoint not installed for given context, do nothing.
+ }
+ }
+ }
+ });
+ } catch (RejectedExecutionException e) {
+ }
+ }
+
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java
new file mode 100644
index 00000000000..fe158fb3073
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpointAttributeTranslator.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.List;
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.ThreadSafeAndProhibitedFromDsfExecutor;
+import org.eclipse.cdt.dsf.debug.service.IBreakpoints.IBreakpointDMContext;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.debug.core.model.IBreakpoint;
+
+
+@ThreadSafeAndProhibitedFromDsfExecutor("")
+public interface IBreakpointAttributeTranslator {
+
+ public void initialize(BreakpointsMediator mediator);
+
+ public void dispose();
+
+ public List<Map<String, Object>> getBreakpointAttributes(IBreakpoint breakpoint, boolean bpManagerEnabled) throws CoreException;
+
+ public boolean canUpdateAttributes(IBreakpointDMContext bp, Map<String, Object> delta);
+
+ public boolean supportsBreakpoint(IBreakpoint bp);
+
+ public void updateBreakpointStatus(IBreakpoint bp);
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java
new file mode 100644
index 00000000000..1fca358fa57
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IBreakpoints.java
@@ -0,0 +1,140 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson - Revisited the API
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.Immutable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Breakpoint service interface
+ */
+public interface IBreakpoints extends IDsfService {
+
+
+ /**
+ * Marker interface for a context for which breakpoints can be installed
+ */
+ public interface IBreakpointsTargetDMContext extends IDMContext {}
+
+ /**
+ * Specific breakpoint context
+ */
+ @Immutable
+ public interface IBreakpointDMContext extends IDMContext {}
+
+ /**
+ * Breakpoint events
+ */
+ public interface IBreakpointsChangedEvent extends IDMEvent<IBreakpointsTargetDMContext> {
+ public IBreakpointDMContext[] getBreakpoints();
+ }
+
+ public interface IBreakpointsAddedEvent extends IBreakpointsChangedEvent {}
+ public interface IBreakpointsUpdatedEvent extends IBreakpointsChangedEvent {}
+ public interface IBreakpointsRemovedEvent extends IBreakpointsChangedEvent {}
+
+ /**
+ * Effective breakpoint data as held by the back-end.
+ */
+ public interface IBreakpointDMData {
+
+ public String getBreakpointType();
+ public String getFileName();
+ public int getLineNumber();
+ public String getFunctionName();
+ public IAddress[] getAddresses();
+ public String getCondition();
+ public int getIgnoreCount();
+ public boolean isEnabled();
+ public String getExpression();
+ }
+
+ /**
+ * Retrieves the list of breakpoints installed in the context.
+ *
+ * Use getBreakpointDMData() to retrieve individual breakpoints.
+ *
+ * @param context the execution context of the breakpoint
+ * @param drm the list of breakpoints in the execution context
+ */
+ public void getBreakpoints(IBreakpointsTargetDMContext context,
+ DataRequestMonitor<IBreakpointDMContext[]> drm);
+
+ /**
+ * Retrieves a specific breakpoint from the service.
+ *
+ * @param dmc the breakpoint reference
+ * @param drm the DRM returning the breakpoint data
+ */
+ public void getBreakpointDMData(IBreakpointDMContext dmc,
+ DataRequestMonitor<IBreakpointDMData> drm);
+
+ /**
+ * Adds a breakpoint on the target.
+ *
+ * The breakpoint context is returned in the DRM. The actual breakpoint
+ * object can be later be retrieved using getBreakpoint(bp_context).
+ *
+ * E.g.:
+ * IBreakpointDMContext ref = insertBreakpoint(...);
+ * IBreakpointDMData bp = getBreakpointDMData(ref);
+ *
+ * If the breakpoint is a duplicate (already set previously), then it is up to
+ * the back-end to decide if it is an error or not.
+ *
+ * @param context the execution context of the breakpoint
+ * @param attributes the breakpoint attributes
+ * @param drm the DRM returning the breakpoint reference
+ */
+ public void insertBreakpoint(IBreakpointsTargetDMContext context,
+ Map<String,Object> attributes,
+ DataRequestMonitor<IBreakpointDMContext> drm);
+
+ /**
+ * Removes the breakpoint on the target.
+ *
+ * If the breakpoint doesn't exist, silently ignore it.
+ *
+ * @param dmc the context of the breakpoints to remove
+ * @param rm the asynchronous request monitor
+ */
+ public void removeBreakpoint(IBreakpointDMContext dmc,
+ RequestMonitor rm);
+
+ /**
+ * Updates the breakpoint properties on the target.
+ *
+ * To add/update/remove a property, simply create a map with
+ * the desired value(s) for the given key(s).
+ *
+ * Properties that affect the breakpoint nature or location
+ * should not be updated. Instead, the breakpoint should be
+ * removed then re-inserted.
+ *
+ * A null value is used for removal of a property e.g.:
+ * delta.set(some_key, null);
+ *
+ * @param delta the delta properties
+ * @param dmc the context of the breakpoints to modify
+ * @param rm the asynchronous request monitor
+ */
+ public void updateBreakpoint(IBreakpointDMContext dmc,
+ Map<String,Object> delta, RequestMonitor drm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java
new file mode 100644
index 00000000000..35d61287299
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ICachingService.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+/**
+ * Interface for services which use an internal cache for data.
+ * @since 1.1
+ */
+public interface ICachingService {
+
+ /**
+ * Clears the service cache entries which have the given context in their
+ * hierarchy.
+ * @param context Root context to flush. May be <code>null</code> to flush
+ * the entire cache.
+ */
+ public void flushCache(IDMContext context);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java
new file mode 100644
index 00000000000..0f751e32aac
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDisassembly.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.math.BigInteger;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Disassembly service interface
+ */
+public interface IDisassembly extends IDsfService {
+
+ public interface IDisassemblyDMContext extends IDMContext {}
+
+ /**
+ * Gets the disassembled code from an address range.
+ * If [startAddress] == null, disassemble from the instruction pointer.
+ *
+ * @param context Context of the disassembly code
+ * @param startAddress Beginning address
+ * @param endAddress End address
+ * @param drm Disassembled code
+ */
+ public void getInstructions(
+ IDisassemblyDMContext context,
+ BigInteger startAddress,
+ BigInteger endAddress,
+ DataRequestMonitor<IInstruction[]> drm);
+
+ /**
+ * Gets the disassembled code from a file location.
+ * If [lines] == -1, the whole function is disassembled.
+ *
+ * @param context Context of the disassembly code
+ * @param filename File to disassemble
+ * @param linenum Line number within the file
+ * @param lines Number of lines of disassembled code to produce
+ * @param drm Disassembled code
+ */
+ public void getInstructions(
+ IDisassemblyDMContext context,
+ String filename,
+ int linenum,
+ int lines,
+ DataRequestMonitor<IInstruction[]> drm);
+
+ /**
+ * Gets the mixed disassembled code from an address range.
+ * If [startAddress] == null, disassemble from the instruction pointer.
+ *
+ * @param context Context of the disassembly code
+ * @param startAddress Beginning address
+ * @param endAddress End address
+ * @param drm Disassembled code
+ */
+ public void getMixedInstructions(
+ IDisassemblyDMContext context,
+ BigInteger startAddress,
+ BigInteger endAddress,
+ DataRequestMonitor<IMixedInstruction[]> drm);
+
+ /**
+ * Gets the mixed disassembled code from a file location.
+ * If [lines] == -1, the whole function is disassembled.
+ *
+ * @param context Context of the disassembly code
+ * @param filename File to disassemble
+ * @param linenum Line number within the file
+ * @param lines Number of lines of disassembled code to produce
+ * @param drm Disassembled code
+ */
+ public void getMixedInstructions(
+ IDisassemblyDMContext context,
+ String filename,
+ int linenum,
+ int lines,
+ DataRequestMonitor<IMixedInstruction[]> drm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java
new file mode 100644
index 00000000000..e71d8091b2c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfBreakpointExtension.java
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.debug.core.model.ICBreakpointExtension;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.core.runtime.CoreException;
+
+/**
+ * An extension to {@link ICBreakpoint} with model-specific breakpoint
+ * attributes. Different debug models can use the standard C breakpoints that
+ * extend the basic <code>ICBreakpoint</code>. The can use this extension
+ * mechanism to edit and store model-specific data in the original breakpoint
+ * object.
+ *
+ * A breakpoint extension is defined by an extension of kind
+ * <code>"org.eclipse.cdt.debug.core.BreakpointExtension"</code></li>.
+ * The <code>ICBreakpoint</code> implementation instantiates breakpoint
+ * extensions registered for its specific marker type when a client requests
+ * extensions for a given debug model type. Thus the extension classes and
+ * plugins that declare them are not loaded unless requested by a client.
+ *
+ * @see ICBreakpoint#getExtension(String, Class)
+ */
+public interface IDsfBreakpointExtension extends ICBreakpointExtension {
+
+ public void setTargetFilter( IContainerDMContext target ) throws CoreException;
+ public void removeTargetFilter( IContainerDMContext target ) throws CoreException;
+ public IContainerDMContext[] getTargetFilters() throws CoreException;
+
+ public void setThreadFilters( IExecutionDMContext[] threads ) throws CoreException;
+ public void removeThreadFilters( IExecutionDMContext[] threads ) throws CoreException;
+ public IExecutionDMContext[] getThreadFilters( IContainerDMContext target ) throws CoreException;
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java
new file mode 100644
index 00000000000..5b3aab48852
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IDsfDebugServicesFactory.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * A factory to create DSF services. Using this interface allows
+ * to easily have different service implementation for different backends.
+ * @since 1.1
+ */
+public interface IDsfDebugServicesFactory {
+ <V> V createService(Class<V> clazz, DsfSession session, Object ... optionalArguments);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java
new file mode 100644
index 00000000000..adedef76125
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IExpressions.java
@@ -0,0 +1,231 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson - Update for GDB/MI
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.Map;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+
+/**
+ * Expressions service provides access to the debugger's expression evaluator. This service has
+ * dependencies on the Stack service, as it is be used to provide context for an
+ * expression to be evaluated.
+ */
+@SuppressWarnings("nls")
+public interface IExpressions extends IFormattedValues {
+
+ /**
+ * Expression context.
+ */
+ public interface IExpressionDMContext extends IFormattedDataDMContext {
+ /**
+ * Returns a fully qualified expression string represented by this context. This
+ * expression string is the same as the string that is sent to the debug engine to be
+ * evaluated in context of a stack frame, thread, or a symbol context.
+ */
+ String getExpression();
+ }
+
+ /**
+ * The address and size of an expression.
+ */
+ public interface IExpressionDMAddress {
+ IAddress getAddress();
+ int getSize();
+ }
+
+ /**
+ * This is the model data interface that corresponds to IExpressionDMContext.
+ */
+ public interface IExpressionDMData extends IDMData {
+ // These static fields define the possible return values of method getTypeId().
+
+ final static String TYPEID_UNKNOWN = "TYPEID_UNKNOWN";
+ final static String TYPEID_INTEGER = "TYPEID_INTEGER";
+ final static String TYPEID_CHAR = "TYPEID_CHAR";
+ final static String TYPEID_FLOAT = "TYPEID_FLOAT";
+ final static String TYPEID_DOUBLE = "TYPEID_DOUBLE";
+ final static String TYPEID_OPAQUE = "TYPEID_OPAQUE";
+
+ /**
+ * This enumerates the possible basic types that an expression can have.
+ *
+ * @see getBasicType().
+ */
+ enum BasicType {
+ unknown, // Unknown type.
+ basic, // Scalar type (e.g., int, short, float).
+ pointer, // Pointer to anything.
+ array, // Array of anything.
+ composite, // Struct, union, or class.
+ enumeration, // Enumeration.
+ function // Function.
+ }
+
+ /**
+ * If this expression is a sub-expression of another expression, this method returns
+ * the expression relative to the parent of this expression. Otherwise this method
+ * will return the same string as {@link #getExpression()}.
+ */
+ String getName();
+
+ /**
+ * @return A BasicType enumerator describing the basic type of an expression.
+ */
+ BasicType getBasicType();
+
+ /**
+ * @return The source code type of this expression. This is a string such as "struct Foo", "short",
+ * "int *", "mytypedef", "(int *)[]", "enum Bar". If the debugger backend cannot supply
+ * this information, this method returns "<UNKNOWN>" (the angle brackets are there just in
+ * case there is a type named "UNKNOWN" in the application).
+ */
+ String getTypeName();
+
+ /**
+ * This method needs to be defined. For now, this returns the empty string.
+ */
+ String getEncoding();
+
+ /**
+ * @return One of the TYPEID_* static field values defined by this interface.
+ */
+ String getTypeId();
+
+ /**
+ * @return A Map in which the keys are strings that are the names of enumerators in the enumeration
+ * that is the value of this expression and the values are the integer values of the
+ * enumerators. If the expression type is not an enumeration, this returns an empty Map.
+ */
+ Map<String, Integer> getEnumerations();
+
+ /**
+ * This method needs to be defined.
+ */
+ IRegisters.IRegisterDMContext getRegister();
+ }
+
+ /**
+ * Event indicating that a given expression is changed. If an expression is changed, it's implied that all
+ * the children of that expression are changed too.
+ */
+ public interface IExpressionChangedDMEvent extends IDMEvent<IExpressionDMContext> {}
+
+ /**
+ * Retrieves the expression DM data object for the given expression context(<tt>dmc</tt>).
+ *
+ * @param dmc
+ * The ExpressionDMC for the expression to be evaluated.
+ * @param rm
+ * The data request monitor that will contain the requested data
+ */
+ void getExpressionData(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMData> rm);
+
+ /**
+ * Retrieves the address and size of an expression given by the expression context(<tt>dmc</tt>).
+ * Non-lvalues do not have an addresses (e.g., "x + 5"). When the expression
+- * has no address, the data request monitor will contain null.
+ *
+ * @param dmc
+ * The ExpressionDMC for the expression
+ * @param rm
+ * The data request monitor that will contain the requested data
+ */
+ void getExpressionAddressData(IExpressionDMContext dmc, DataRequestMonitor<IExpressionDMAddress> rm);
+
+ /**
+ * Returns the data model context object for the specified expression in the context
+ * specified by <b>ctx</b>.
+ *
+ * @param ctx: Context in which to evaluate the expression. This context could include the
+ * PC location, stack frame, thread, or just a symbol context.
+ *
+ * @param expression: The expression to evaluate.
+ *
+ * @return An expression data model context object that must be passed to
+ * getModelData() to obtain the value of the expression.
+ */
+ IExpressionDMContext createExpression(IDMContext ctx, String expression);
+
+ /**
+ * Retrieves the sub-expressions of the given expression. Sub-expressions are fields of a struct, union,
+ * or class, the enumerators of an enumeration, and the element of an array.
+ *
+ * @param exprCtx: The data model context representing an expression.
+ *
+ * @param rm: Request completion monitor containing an array of all sub-expressions
+ */
+ void getSubExpressions(IExpressionDMContext exprCtx, DataRequestMonitor<IExpressionDMContext[]> rm);
+
+ /**
+ * Retrieves a particular range of sub-expressions of the given expression.
+ * Sub-expressions are fields of a struct, union, or class, the enumerators
+ * of an enumeration, and the element of an array.
+ *
+ * @param exprCtx: The data model context representing an expression.
+ * startIndex: Index of the first sub-expression to retrieve
+ * length: Total number of sub-expressions to retrieve
+ *
+ * @param rm: Request completion monitor containing an array of the requested
+ * range of sub-expressions
+ */
+ void getSubExpressions(IExpressionDMContext exprCtx, int startIndex, int length,
+ DataRequestMonitor<IExpressionDMContext[]> rm);
+
+ /**
+ * Retrieves the number of sub-expressions of the given expression. Sub-expressions are fields of a struct, union,
+ * or class, the enumerators of an enumeration, and the element of an array.
+ *
+ * @param exprCtx: The data model context representing an expression.
+ *
+ * @param rm: Request completion monitor containing the number of sub-expressions
+ * of the specified expression
+ */
+ void getSubExpressionCount(IExpressionDMContext exprCtx, DataRequestMonitor<Integer> rm);
+
+ /**
+ * For object oriented languages, this method returns the expressions representing base types of
+ * the given expression type.
+ *
+ * @param exprContext: The data model context representing an expression.
+ *
+ * @param rm: Request completion monitor.
+ */
+ void getBaseExpressions(IExpressionDMContext exprContext, DataRequestMonitor<IExpressionDMContext[]> rm);
+
+ /**
+ * This method indicates if an expression can be written to.
+ *
+ * @param expressionContext: The data model context representing an expression.
+ *
+ * @param rm: Data Request monitor containing True if this expression's value can be edited. False otherwise.
+ */
+ void canWriteExpression(IExpressionDMContext expressionContext, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * This method supports the writing/modifying the value of the expression.
+ *
+ * @param expressionContext: The data model context representing an expression.
+ *
+ * @param expressionValue: The new value of the expression as a String.
+ *
+ * @param formatId: The format ID specifying the format of parameter <b>expressionValue</b>.
+ *
+ * @param rm: Request completion monitor.
+ */
+ void writeExpression(IExpressionDMContext expressionContext, String expressionValue, String formatId, RequestMonitor rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java
new file mode 100644
index 00000000000..5cc665aebb3
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IFormattedValues.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.AbstractDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+public interface IFormattedValues extends IDMService {
+
+ /** Marker interface for a DMC that has a formatted value. */
+ public interface IFormattedDataDMContext extends IDMContext {}
+
+ /**
+ * These strings represent the standard known formats for any bit stream
+ * which needs to be formatted. These ID's as well as others which may be
+ * specifically available from the backend are what is returned from the
+ * getID() method.
+ */
+ public final static String HEX_FORMAT = "HEX.Format" ; //$NON-NLS-1$
+ public final static String OCTAL_FORMAT = "OCTAL.Format" ; //$NON-NLS-1$
+ public final static String NATURAL_FORMAT = "NATURAL.Format" ; //$NON-NLS-1$
+ public final static String BINARY_FORMAT = "BINARY.Format" ; //$NON-NLS-1$
+ public final static String DECIMAL_FORMAT = "DECIMAL.Format" ; //$NON-NLS-1$
+ public final static String STRING_FORMAT = "STRING.Format" ; //$NON-NLS-1$
+
+ /**
+ * Retrieves the formats that the given data is available in.
+ * This method is asynchronous because the service may need to retrieve
+ * information from the backend in order to determine what formats are
+ * available for the given data context.
+ *
+ * @param dmc Context for which to retrieve available formats.
+ * @param rm Completion monitor returns an array of support formatIds.
+ */
+ public void getAvailableFormats(IFormattedDataDMContext dmc, DataRequestMonitor<String[]> rm);
+
+ /**
+ * Creates a FormattedValueDMContext representing the given formatId.
+ *
+ * @param dmc Parent context for the context that is being created
+ * @param formatId Defines format to be used for the returned context.
+ */
+ public FormattedValueDMContext getFormattedValueContext(IFormattedDataDMContext dmc, String formatId);
+
+ /**
+ * Retrieves the DM data associated with given formatted value context.
+ * @param dmc Context to retrieve the value for.
+ * @param rm Completion monitor returns the formatted value.
+ */
+ public void getFormattedExpressionValue(FormattedValueDMContext dmc, DataRequestMonitor<FormattedValueDMData> rm);
+
+
+ /**
+ * DMC that represents a value with specific format. The format ID can be
+ * persisted and used for comparison.
+ */
+
+ public static class FormattedValueDMContext extends AbstractDMContext
+ {
+ private final String fFormatID;
+
+ public FormattedValueDMContext(IDMService service, IDMContext parent, String formatId) {
+ super(service, new IDMContext[] { parent });
+ fFormatID = formatId;
+ }
+
+ public FormattedValueDMContext(String sessionId, IDMContext parent, String formatId) {
+ super(sessionId, new IDMContext[] { parent });
+ fFormatID = formatId;
+ }
+
+ public String getFormatID() {
+ return fFormatID;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return baseEquals(obj) && ((FormattedValueDMContext)obj).getFormatID().equals(getFormatID());
+ }
+
+ @Override
+ public int hashCode() {
+ return baseHashCode() + getFormatID().hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return baseToString() + ".format(" + getFormatID() + ")"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+ }
+
+ public static class FormattedValueDMData implements IDMData {
+
+ private final String fValue;
+
+ public FormattedValueDMData(String value) {
+ fValue = value;
+ }
+
+ public String getFormattedValue() {
+ return fValue;
+ }
+
+
+ }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java
new file mode 100644
index 00000000000..dd547ff5746
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IInstruction.java
@@ -0,0 +1,51 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.math.BigInteger;
+
+/**
+ * Represents an assembly instruction
+ */
+public interface IInstruction {
+
+ /**
+ * @return the instruction address.
+ */
+ BigInteger getAdress();
+
+ /**
+ * @return the function name.
+ */
+ String getFuntionName();
+
+ /**
+ * @return the offset of this machine instruction
+ */
+ long getOffset();
+
+ /**
+ * @return the instruction.
+ */
+ String getInstruction();
+
+ /**
+ * @return the opcode
+ */
+ String getOpcode();
+
+ /**
+ * @return any arguments to the instruction
+ */
+ String getArgs();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java
new file mode 100644
index 00000000000..a8444301527
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMemory.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson AB - extended the API for IMemoryBlockExtension
+ * Ericsson AB - added support for 64 bit processors
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+import org.eclipse.debug.core.model.MemoryByte;
+
+/**
+ * Service for accessing memory. Memory contexts are not meant to be
+ * represented in tree or table views, so it doesn't need to implement
+ * IDMService interface.
+ */
+public interface IMemory extends IDsfService {
+
+ public interface IMemoryDMContext extends IDMContext {}
+
+ /**
+ * Event generated every time a range of bytes is modified.
+ *
+ * A client wishing to receive such events has to register as a service
+ * event listener and implement the corresponding eventDispatched method.
+ *
+ * E.g.:
+ *
+ * MyMemoryBlock(MIRunControl fRunControl)
+ * {
+ * ...
+ * fRunControl.getSession().addServiceEventListener(MyMemoryBlock.this, null);
+ * ...
+ * }
+ *
+ * @DsfServiceEventHandler
+ * public void eventDispatched(MemoryChangedEvent e) {
+ * IDMContext<?> context = e.getContext();
+ * IAddress[] addresses = e.getAddresses();
+ * // do whatever...
+ * }
+ */
+ public interface IMemoryChangedEvent extends IDMEvent<IMemoryDMContext> {
+ IAddress[] getAddresses();
+ }
+
+ /**
+ * Reads a memory block from the target.
+ *
+ * An asynchronous memory read request at [address] + [offset] for
+ * [count] memory items, each of size [word_size] bytes, will be
+ * issued to the target. The result will be stored in [drm] upon
+ * completion of the call.
+ *
+ * The [drm] result buffer will be of size [word_size] * [count]. The
+ * successfully read bytes will have their MemoryByte.READABLE flag
+ * set while the bytes in error (unreachable/bad memory) will have their
+ * flag byte set to 0. The bytes will respect the target "endianness".
+ *
+ * @param context the context of the target memory block
+ * @param address the memory block address (on the target)
+ * @param offset the offset from the start address
+ * @param word_size the size, in bytes, of an addressable item
+ * @param count the number of data elements to read
+ * @param drm the asynchronous data request monitor
+ */
+ public void getMemory(IMemoryDMContext context, IAddress address, long offset,
+ int word_size, int count, DataRequestMonitor<MemoryByte[]> drm);
+
+ /**
+ * Writes a memory block on the target.
+ *
+ * An asynchronous memory write request at [address] + [offset] for
+ * [count] * [word_size] bytes will be issued to the target.
+ *
+ * The [buffer] must hold at least [count] * [word_size] bytes.
+ *
+ * A MemoryChangedEvent will be generated for the range of addresses.
+ *
+ * @param context the context of the target memory block
+ * @param address the memory block address (on the target)
+ * @param offset the offset from the start address
+ * @param word_size the size, in bytes, of an addressable item
+ * @param count the number of data elements to write
+ * @param buffer the source buffer
+ * @param rm the asynchronous data request monitor
+ */
+ public void setMemory(IMemoryDMContext context, IAddress address, long offset,
+ int word_size, int count, byte[] buffer, RequestMonitor rm);
+
+ /**
+ * Writes [pattern] at memory [address] + [offset], [count] times.
+ *
+ * A MemoryChangedEvent will be generated for the range of addresses.
+ *
+ * @param context the context of the target memory block
+ * @param address the memory block address (on the target)
+ * @param offset the offset from the start address
+ * @param word_size the size, in bytes, of an addressable item
+ * @param count the number of times [pattern] will be written
+ * @param pattern the source buffer
+ * @param rm the asynchronous data request monitor
+ */
+ public void fillMemory(IMemoryDMContext context, IAddress address, long offset,
+ int word_size, int count, byte[] pattern, RequestMonitor rm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java
new file mode 100644
index 00000000000..511f81f1785
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IMixedInstruction.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Ericsson 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:
+ * Ericsson - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service;
+
+/**
+ * Represents the assembly instruction(s) corresponding to a source line
+ */
+public interface IMixedInstruction {
+
+ /**
+ * @return the file name
+ */
+ String getFileName();
+
+ /**
+ * @return the line Number.
+ */
+ int getLineNumber();
+
+ /**
+ * @return the array of instruction.
+ */
+ IInstruction[] getInstructions();
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java
new file mode 100644
index 00000000000..c01ea5db89a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IModules.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Debugger service representing module handling logic of a debugger.
+ */
+public interface IModules extends IDsfService {
+
+ /**
+ * Symbol context represents the space into which module symbols are loaded.
+ * Traditionally symbols are loaded in context of a process, but for other
+ * types of debugging, like kernel or no-OS debugging, it's useful to
+ * separate the concept of a symbol context from a process.
+ */
+ public interface ISymbolDMContext extends IDMContext {}
+
+ /**
+ * Module context represents a single module that is loaded.
+ */
+ public interface IModuleDMContext extends IDMContext {}
+
+ /**
+ * Event indicating a change in the symbol information for given context.
+ */
+ public interface ModulesChangedDMEvent extends IDMEvent<ISymbolDMContext> {}
+
+ /**
+ * Specific event identifying that a new module was loaded into a
+ * symbol context.
+ */
+ public interface ModuleLoadedDMEvent extends ModulesChangedDMEvent {
+ /** Returns context of the module that was loaded */
+ IModuleDMContext getLoadedModuleContext();
+ }
+
+ public interface ModuleUnloadedDMEvent extends ModulesChangedDMEvent {
+ /** Returns context of the module that was un-loaded */
+ IModuleDMContext getUnloadedModuleContext();
+ }
+
+ /** Module information. */
+ public interface IModuleDMData {
+ String getName();
+ String getFile();
+ long getTimeStamp();
+ String getBaseAddress();
+ String getToAddress();
+ boolean isSymbolsLoaded();
+ long getSize();
+ }
+
+ /** Line information about a particular address */
+ public interface LineInfo {
+ IAddress getAddress();
+ String getSourceFile();
+ int getStartLine();
+ int getStartColumn();
+ int getEndLine();
+ int getEndColumn();
+ }
+
+ /** Address information about a particular file/line */
+ public interface AddressRange {
+ IAddress getStartAddress();
+ IAddress getEndAddress();
+ }
+
+ void getModuleData(IModuleDMContext dmc, DataRequestMonitor<IModuleDMData> rm);
+
+ /**
+ * Retreives the list of modules loaded in given symbol context.
+ */
+ void getModules(ISymbolDMContext symCtx, DataRequestMonitor<IModuleDMContext[]> rm);
+
+ /**
+ * Calculates the line numbers corresponding to the given address.
+ */
+ void calcLineInfo(ISymbolDMContext symCtx, IAddress address, DataRequestMonitor<LineInfo[]> rm);
+
+ /**
+ * Calculates the addresses corresponding to the given source file location.
+ */
+ void calcAddressInfo(ISymbolDMContext symCtx, String file, int line, int col, DataRequestMonitor<AddressRange[]> rm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java
new file mode 100644
index 00000000000..db65c2c89ed
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IProcesses.java
@@ -0,0 +1,181 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson - Updated for latest DSF version
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.Map;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * This interface provides access to the OS's process
+ * information, manipulation methods, and debugging methods.
+ * This service provides a relatively simple interface for
+ * manipulating processes as compared with a full-blown
+ * remote target debugger.
+ * @since 1.1
+ */
+public interface IProcesses extends IDMService {
+
+ /**
+ * A thread as known by the OS.
+ * This context is kept different than {@link IRunControl.IExecutionDMContext}
+ * because the OS id of a thread may not be the same as the thread id used by
+ * the debugger when doing run control operations.
+ */
+ public interface IThreadDMContext extends IDMContext {}
+
+ /**
+ * A process as known by the OS.
+ * This context is kept different than {@link IRunControl.IContainerDMContext}
+ * because the OS id of a process may not be the same as the process id used by
+ * the debugger when doing run control operations.
+ */
+ public interface IProcessDMContext extends IThreadDMContext {}
+
+ /**
+ * Interface for thread and process object data. This data provides a link
+ * to the lower level debugger services, in form of execution contexts.
+ */
+ public interface IThreadDMData extends IDMData {
+ String getName();
+ String getId();
+ boolean isDebuggerAttached();
+ }
+
+ /**
+ * Event indicating that process data has changed.
+ */
+ public interface ProcessChangedDMEvent extends IDMEvent<IProcessDMContext> {}
+
+ /**
+ * Retrieves thread or process data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getExecutionData(IThreadDMContext dmc, DataRequestMonitor<IThreadDMData> rm);
+
+ /**
+ * Retrieves the debugging context that characterizes the specified thread
+ * or process context.
+ *
+ * @param dmc The thread or process dmc for which we want the debugging context
+ * @param rm The request monitor that will contain the debugging context.
+ * null if no such context exists
+ */
+ public void getDebuggingContext(IThreadDMContext dmc, DataRequestMonitor<IDMContext> rm);
+
+ /**
+ * Retrieves the current list of processes running on target.
+ * @param dmc The processor or core for which to list all processes
+ * @param rm Request completion monitor, to be filled in with array of process contexts.
+ */
+ void getRunningProcesses(IDMContext dmc, DataRequestMonitor<IProcessDMContext[]> rm);
+
+ /**
+ * Checks whether it is possible to attach the debugger to a new process.
+ * @param dmc The processor or core on which we want to attach to a process.
+ * @param rm Return if it is possible to attach.
+ */
+ void isDebuggerAttachSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Attaches debugger to the given process.
+ * When attaching to a process, a debugging context can now be used to characterize the process.
+ * This method can optionally choose to return this IDMContext inside the DataRequestMonitor.
+ * This can be useful for backends that do not have the ability to obtain the different
+ * debugging IDMContexts through {@link #getProcessesBeingDebugged(IDMContext, DataRequestMonitor)
+ */
+ void attachDebuggerToProcess(IProcessDMContext procCtx, DataRequestMonitor<IDMContext> rm);
+
+ /**
+ * Checks whether it is possible to detach the debugger from the specified process.
+ * @param dmc The debugging context from which we want to detach. This context
+ * should have IProcessDMContext as an ancestor.
+ * @param rm Return if it is possible to detach.
+ */
+ void canDetachDebuggerFromProcess(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Detaches debugger from the given process.
+ * @param dmc The debugging context from which we want to detach. This context
+ * should have IProcessDMContext as an ancestor.
+ */
+ void detachDebuggerFromProcess(IDMContext dmc, RequestMonitor requestMonitor);
+
+ /**
+ * Checks whether it is possible to run a new process.
+ * @param dmc The processor or core on which we want to run a new process.
+ * @param rm Return if it is possible to run a new process.
+ */
+ void isRunNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Starts a new process.
+ * @param dmc The processor or core on which we want to run a new process.
+ * @param file Process image to use for the new process.
+ * @param attributes Attributes that give information on the process to be debugged
+ * @param rm Request completion monitor, to be filled in with the process context.
+ */
+ void runNewProcess(IDMContext dmc,
+ String file,
+ Map<String, Object> attributes,
+ DataRequestMonitor<IProcessDMContext> rm);
+
+ /**
+ * Checks whether it is possible to start a new process with the debugger attached
+ * @param dmc The processor or core on which we want to start and debug the new process.
+ * @param rm Return if it is possible to start a new process with the debugger attached.
+ */
+ void isDebugNewProcessSupported(IDMContext dmc, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Starts a new process with the debugger attached.
+ * @param dmc The processor or core on which we want to start and debug the new process.
+ * @param file Process image to use for the new process.
+ * @param attributes Attributes that give information on the process to be debugged
+ * @param rm Request completion monitor, to be filled in with the
+ * debugging context that can now be used to characterize the process
+ */
+ void debugNewProcess(IDMContext dmc,
+ String file,
+ Map<String, Object> attributes,
+ DataRequestMonitor<IDMContext> rm);
+
+ /**
+ * Retrieves the list of processes which are currently under debugger control.
+ *
+ * @param dmc The processor or core for which to list processes being debugged
+ * @param rm Request completion monitor which contains all debugging contexts representing
+ * the processes being debugged. Note that each of these contexts should also have
+ * IProcessDMContext as a parent.
+ */
+ void getProcessesBeingDebugged(IDMContext dmc, DataRequestMonitor<IDMContext[]> rm);
+
+ /**
+ * Checks whether the given process or thread can be terminated.
+ * @param thread Thread or process to terminate.
+ * @param rm Return token.
+ */
+ void canTerminate(IThreadDMContext thread, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Terminates the selected process or thread.
+ * @param thread Thread or process to terminate.
+ * @param rm Request completion monitor, indicates success or failure.
+ */
+ void terminate(IThreadDMContext thread, RequestMonitor requestMonitor);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java
new file mode 100644
index 00000000000..7397ead772b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRegisters.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+
+/**
+ * Service for accessing register data.
+ */
+public interface IRegisters extends IFormattedValues {
+
+ /**
+ * Event indicating groups have changed. The type of context returned by this
+ * event is generic, because different implementations of the the register service
+ * could configure register groups using different contexts. Some implementations
+ * could configure different register groups for each execution context, other
+ * services may have a global list of groups.
+ */
+ public interface IGroupsChangedDMEvent extends IDMEvent<IDMContext> {}
+
+ /** Register group context */
+ public interface IRegisterGroupDMContext extends IFormattedDataDMContext {
+ }
+
+ /** Event indicating values for the group have changed. */
+ public interface IGroupChangedDMEvent extends IDMEvent<IRegisterGroupDMContext> {}
+
+ /** Event indicating registers in a group have changed. */
+ public interface IRegistersChangedDMEvent extends IDMEvent<IRegisterGroupDMContext> {}
+
+ /**
+ * Register groups only have a name and description. Sub groups and registers are
+ * retrieved through the service interface.
+ */
+ public interface IRegisterGroupDMData extends IDMData {
+ public String getName();
+ public String getDescription();
+ }
+
+ /** Register context */
+ public interface IRegisterDMContext extends IFormattedDataDMContext {
+ }
+
+ /** Event indicating register value changed. */
+ public interface IRegisterChangedDMEvent extends IDMEvent<IRegisterDMContext> {}
+
+ /** Register information */
+ public interface IRegisterDMData extends IDMData {
+ String getName();
+ String getDescription();
+ boolean isReadable();
+ boolean isReadOnce();
+ boolean isWriteable();
+ boolean isWriteOnce();
+ boolean hasSideEffects();
+ boolean isVolatile();
+ boolean isFloat();
+ }
+
+ /** Bit field context */
+ public interface IBitFieldDMContext extends IFormattedDataDMContext {
+ }
+
+ /** Event indicating register value changed. */
+ public interface IBitFieldChangedDMEvent extends IDMEvent<IBitFieldDMContext> {}
+
+ /**
+ * Bitfield data, big groups and mnemonics are retrieved at the same
+ * time as rest of bit field data
+ */
+ public interface IBitFieldDMData extends IDMData {
+ String getName();
+ String getDescription();
+ boolean isReadable();
+ boolean isReadOnce();
+ boolean isWriteable();
+ boolean isWriteOnce();
+ boolean hasSideEffects();
+ boolean isZeroBasedNumbering();
+ boolean isZeroBitLeftMost();
+ IBitGroup[] getBitGroup();
+ IMnemonic[] getMnemonics();
+ IMnemonic getCurrentMnemonicValue();
+ }
+
+ /** Bit group definition */
+ public interface IBitGroup {
+ int startBit();
+ int bitCount();
+ }
+
+ /** Bit field mnemonic */
+ public interface IMnemonic {
+ String getShortName();
+ String getLongName();
+ }
+
+ /**
+ * Retrieves the list of register groups.
+ * @param ctx Context for the returned data.
+ * @param rm Request completion monitor.
+ */
+ void getRegisterGroups(IDMContext ctx, DataRequestMonitor<IRegisterGroupDMContext[]> rm);
+
+ /**
+ * Retrieves the list of registers for the given context. The given context could include
+ * a register group and an execution context or just an execution context, in which case all
+ * registers for all groups should be returned.
+ * @param ctx Context for the returned data.
+ * @param rm Request completion monitor.
+ */
+ void getRegisters(IDMContext ctx, DataRequestMonitor<IRegisterDMContext[]> rm);
+
+ /**
+ * Retrieves bit fields for given register
+ * @param ctx Context for the returned data.
+ * @param rm Request completion monitor.
+ */
+ void getBitFields(IDMContext ctx, DataRequestMonitor<IBitFieldDMContext[]> rm);
+
+ /**
+ * Retrieves a Register Group context. The given context could include a register
+ * group and an execution context or just an execution context.
+ * @param ctx Context for the returned data.
+ * @param name Name of group being requested
+ * @param rm Request completion monitor.
+ */
+ void findRegisterGroup(IDMContext ctx, String name, DataRequestMonitor<IRegisterGroupDMContext> rm);
+
+ /**
+ * Retrieves a Register context. The given context could include a register group and an execution
+ * context or just an execution context.
+ * @param ctx Context for the returned data.
+ * @param name Name of register being requested
+ * @param rm Request completion monitor.
+ */
+ void findRegister(IDMContext ctx, String name, DataRequestMonitor<IRegisterDMContext> rm);
+
+ /**
+ * Retrieves bit field context. The given context could include a register and an execution
+ * context or just an execution context.
+ * @param ctx Context for the returned data.
+ * @param name Name of bit field being requested
+ * @param rm Request completion monitor.
+ */
+ void findBitField(IDMContext ctx, String name, DataRequestMonitor<IBitFieldDMContext> rm);
+
+ /**
+ * Retrieves register group data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ void getRegisterGroupData(IRegisterGroupDMContext dmc, DataRequestMonitor<IRegisterGroupDMData> rm);
+
+ /**
+ * Retrieves register data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ void getRegisterData(IRegisterDMContext dmc , DataRequestMonitor<IRegisterDMData> rm);
+
+ /**
+ * Retrieves bit field data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ void getBitFieldData(IBitFieldDMContext dmc , DataRequestMonitor<IBitFieldDMData> rm);
+
+
+
+ /**
+ * Writes a register value for a given register to the target
+ * @param regCtx Context containing the register.
+ * @param regValue Value of the register to be written.
+ * @param formatId Format of the value to be written.
+ * @param rm Request completion monitor.
+ */
+ void writeRegister(IRegisterDMContext regCtx, String regValue, String formatId, RequestMonitor rm);
+
+ /**
+ * Writes a bit field value for a given bit field to the target
+ * @param bitFieldCtx Context containing the bit field.
+ * @param bitFieldValue Value of the bit field to be written.
+ * @param formatId Format of the value to be written.
+ * @param rm Request completion monitor.
+ */
+ void writeBitField(IBitFieldDMContext bitFieldCtx, String bitFieldValue, String formatId, RequestMonitor rm);
+
+ /**
+ * Writes a bit field value for a given bit field to the target
+ * @param bitFieldCtx Context containing the bit field.
+ * @param mnemonic Mnemonic which represents the value to be written.
+ * @param rm Request completion monitor.
+ */
+ void writeBitField(IBitFieldDMContext bitFieldCtx, IMnemonic mnemonic, RequestMonitor rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java
new file mode 100644
index 00000000000..181d2f44418
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IRunControl.java
@@ -0,0 +1,127 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson - Modified for additional functionality
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * This interface provides access to controlling and monitoring the execution
+ * state of a process being debugged. This interface does not actually
+ * provide methods for creating or destroying execution contexts, it doesn't
+ * even have methods for getting labels. That's because it is expected that
+ * higher level services, ones that deal with processes, kernels, or target
+ * features will provide that functionality.
+ */
+public interface IRunControl extends IDMService
+{
+ /**
+ * Execution context is the object on which run control operations can be
+ * performed. A lot of higher-level services reference this context to build
+ * functionality on top of it, e.g. stack, expression evaluation, registers, etc.
+ */
+ public interface IExecutionDMContext extends IDMContext {}
+
+ /**
+ * Context representing a process, kernel, or some other logical container
+ * for execution contexts, which by itself can perform run-control
+ * operations.
+ */
+
+ public interface IContainerDMContext extends IExecutionDMContext {}
+
+ /** Flag indicating reason context state change. */
+ public enum StateChangeReason { UNKNOWN, USER_REQUEST, STEP, BREAKPOINT, EXCEPTION, CONTAINER, WATCHPOINT, SIGNAL, SHAREDLIB, ERROR, EVALUATION };
+
+ /**
+ * Indicates that the given thread has suspended.
+ */
+ public interface ISuspendedDMEvent extends IDMEvent<IExecutionDMContext> {
+ StateChangeReason getReason();
+ }
+
+ /**
+ * Indicates that the given thread has resumed.
+ */
+ public interface IResumedDMEvent extends IDMEvent<IExecutionDMContext> {
+ StateChangeReason getReason();
+ }
+
+ /**
+ * Indicates that the given container has suspended.
+ */
+ public interface IContainerSuspendedDMEvent extends ISuspendedDMEvent {
+ /**
+ * Returns the contexts which triggered the resume, which could be
+ * an empty array if not known.
+ */
+ IExecutionDMContext[] getTriggeringContexts();
+ }
+
+ /**
+ * Indicates that the given container has resumed.
+ */
+ public interface IContainerResumedDMEvent extends IResumedDMEvent {
+ /**
+ * Returns the contexts which triggered the resume, which could be an
+ * empty array if not known.
+ */
+ IExecutionDMContext[] getTriggeringContexts();
+ }
+
+ /**
+ * Indicates that a new execution context was started.
+ */
+ public interface IStartedDMEvent extends IDMEvent<IExecutionDMContext> {}
+
+ /**
+ * Indicates that an execution context has exited.
+ */
+ public interface IExitedDMEvent extends IDMEvent<IExecutionDMContext> {}
+
+ /**
+ * Display information for an execution context.
+ */
+ public interface IExecutionDMData extends IDMData {
+ StateChangeReason getStateChangeReason();
+ }
+
+ /**
+ * Retrieves execution data for given context.
+ * @param dmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm);
+
+ /**
+ * Returns execution contexts belonging to the given container context.
+ */
+ public void getExecutionContexts(IContainerDMContext c, DataRequestMonitor<IExecutionDMContext[]> rm);
+
+ /*
+ * Run control commands. They all require the IExecutionContext object on
+ * which they perform the operations.
+ */
+ void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm);
+ void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm);
+ boolean isSuspended(IExecutionDMContext context);
+ void resume(IExecutionDMContext context, RequestMonitor requestMonitor);
+ void suspend(IExecutionDMContext context, RequestMonitor requestMonitor);
+ public enum StepType { STEP_OVER, STEP_INTO, STEP_RETURN, INSTRUCTION_STEP_OVER, INSTRUCTION_STEP_INTO, INSTRUCTION_STEP_RETUTRN };
+ boolean isStepping(IExecutionDMContext context);
+ void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm);
+ void step(IExecutionDMContext context, StepType stepType, RequestMonitor requestMonitor);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java
new file mode 100644
index 00000000000..3fba2d7da39
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISignals.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ *
+ */
+public interface ISignals extends IDsfService {
+ /**
+ * Marker interface for a context for which signals can be set.
+ */
+ public interface ISignalsDMContext extends IDMContext {};
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java
new file mode 100644
index 00000000000..b92dd3c83b1
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISourceLookup.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Service for mapping debugger paths to host paths. This service is needed
+ * primarily by other services that need to access source-path mappings, such
+ * as the breakpoints service. For UI components, the platform source lookup
+ * interfaces could be sufficient.
+ */
+public interface ISourceLookup extends IDsfService {
+
+ public interface ISourceLookupDMContext extends IDMContext {}
+
+ public interface ISourceLookupChangedDMEvent extends IDMEvent<ISourceLookupDMContext> {}
+
+ /**
+ * Retrieves the host source object for given debugger path string.
+ */
+ void getSource(ISourceLookupDMContext ctx, String debuggerPath, DataRequestMonitor<Object> rm);
+
+ /**
+ * Retrieves the debugger path string for given host source object.
+ */
+ void getDebuggerPath(ISourceLookupDMContext ctx, Object source, DataRequestMonitor<String> rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java
new file mode 100644
index 00000000000..d6003483f94
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 2006,, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.core.IAddress;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * Stack service provides access to stack information for a
+ * given execution context.
+ */
+public interface IStack extends IDMService {
+
+ /**
+ * Context for a specific stack frame. Besides allowing access to stack
+ * frame data, this context is used by other services that require a stack
+ * frame for evaluation.
+ */
+ public interface IFrameDMContext extends IDMContext {
+ int getLevel();
+ }
+
+ /**
+ * Stack frame information.
+ */
+ public interface IFrameDMData extends IDMData {
+ IAddress getAddress();
+ String getFile();
+ String getFunction();
+ int getLine();
+ int getColumn();
+ }
+
+ /**
+ * Variable context. This context only provides access to limited
+ * expression information. For displaying complete information,
+ * Expressions service should be used.
+ */
+ public interface IVariableDMContext extends IDMContext {}
+
+ /**
+ * Stack frame variable information.
+ */
+ public interface IVariableDMData extends IDMData {
+ String getName();
+ String getValue();
+ }
+
+ /**
+ * Retrieves stack frame data for given context.
+ * @param frameDmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getFrameData(final IFrameDMContext frameDmc, DataRequestMonitor<IFrameDMData> rm);
+
+ /**
+ * Retrieves stack frame variable data for given context.
+ * @param variableDmc Context to retrieve data for.
+ * @param rm Request completion monitor.
+ */
+ public void getVariableData(IVariableDMContext variableDmc, DataRequestMonitor<IVariableDMData> rm);
+
+ /**
+ * Retrieves list of stack frames for the given execution context. Request
+ * will fail if the stack frame data is not available.
+ */
+ void getFrames(IDMContext execContext, DataRequestMonitor<IFrameDMContext[]> rm);
+
+ /**
+ * Retrieves the top stack frame for the given execution context.
+ * Retrieving just the top frame DMC and corresponding data can be much
+ * more efficient than just retrieving the whole stack, before the data
+ * is often included in the stopped event. Also for some UI functionality,
+ * such as setpping, only top stack frame is often needed.
+ * @param execContext
+ * @param rm
+ */
+ void getTopFrame(IDMContext execContext, DataRequestMonitor<IFrameDMContext> rm);
+
+ /**
+ * Retrieves variables which were arguments to the stack frame's function.
+ */
+ void getArguments(IFrameDMContext frameCtx, DataRequestMonitor<IVariableDMContext[]> rm);
+
+ /**
+ * Retrieves variables local to the stack frame, including arguments.
+ */
+ void getLocals(IFrameDMContext frameCtx, DataRequestMonitor<IVariableDMContext[]> rm);
+
+ /**
+ * Retrieves the number of stack frames available for the given context..
+ * @param dmc Context to retrieve data for.
+ * @param The maximum depth of stack to calculate. Should be 0 to calculate
+ * depth with no limit.
+ * @param rm Callback
+ */
+ void getStackDepth(IDMContext dmc, int maxDepth, DataRequestMonitor<Integer> rm);
+
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java
new file mode 100644
index 00000000000..ae2f507839f
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStack2.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+/**
+ * Stack service extension.
+ * <p>
+ * Adds the capability to retrieve a limited number of stack frames.
+ * </p>
+ *
+ * @since DSF 1.1
+ */
+public interface IStack2 extends IStack {
+
+ /**
+ * Convenience constant for use with {@link #getFrames(IDMContext, int, int, DataRequestMonitor)}
+ * to retrieve all stack frames.
+ */
+ public final static int ALL_FRAMES = -1;
+
+ /**
+ * Retrieves list of stack frames for the given execution context. Request
+ * will fail if the stack frame data is not available.
+ * <p>The range of stack frames can be limited by the <code>startIndex</code> and <code>endIndex</code> arguments.
+ * It is no error to specify an <code>endIndex</code> exceeding the number of available stack frames.
+ * A negative value for <code>endIndex</code> means to retrieve all stack frames. <code>startIndex</code> must be a non-negative value.
+ * </p>
+ *
+ * @param execContext the execution context to retrieve stack frames for
+ * @param startIndex the index of the first frame to retrieve
+ * @param endIndex the index of the last frame to retrieve (inclusive) or {@link #ALL_FRAMES}
+ * @param rm the request monitor
+ *
+ * @see #getFrames(IDMContext, DataRequestMonitor)
+ */
+ public abstract void getFrames(IDMContext execContext, int startIndex, int endIndex, DataRequestMonitor<IFrameDMContext[]> rm);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java
new file mode 100644
index 00000000000..16167692125
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/IStepQueueManager.java
@@ -0,0 +1,42 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems, Inc. 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.service.DsfSession;
+
+/**
+ * @since 1.1
+ */
+@ConfinedToDsfExecutor("getSession().getExecutor()")
+public interface IStepQueueManager {
+
+ /**
+ * Returns the session for which this step queue manager is used.
+ */
+ public DsfSession getSession();
+
+ /**
+ * Checks whether a step command can be queued up for given context.
+ */
+ public abstract void canEnqueueStep(IExecutionDMContext execCtx, StepType stepType, DataRequestMonitor<Boolean> rm);
+
+ /**
+ * Adds a step command to the execution queue for given context.
+ * @param execCtx Execution context that should perform the step.
+ * @param stepType Type of step to execute.
+ */
+ public abstract void enqueueStep(final IExecutionDMContext execCtx, final StepType stepType);
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java
new file mode 100644
index 00000000000..bf92dd13caa
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/ISymbols.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMData;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.datamodel.IDMService;
+
+/**
+ * Service for accessing debugger symbols. This service builds on the Modules
+ * service, but not all debuggers provide access for parsing symbols so this
+ * service is separated.
+ * @see IModules
+ */
+public interface ISymbols extends IDMService {
+ public interface ISymbolObjectDMContext extends IDMContext {}
+
+ /**
+ * Data about a debug symbol.
+ */
+ public interface ISymbolObjectDMData extends IDMData {
+ String getName();
+ String getTypeName();
+ String getFilepath();
+ }
+
+ /**
+ * Indicates that the list of symbol objects is changed. Parsing debug
+ * symbols can be a long running operation (order of 10's of seconds or
+ * minues), so it is useful for the service to provide access to the data
+ * even while it's still parsing. This event may be issued periodically
+ * by the service to indicate that a section of debug symbols has been
+ * parsed.
+ */
+ public interface ISymbolDataChangedDMEvent extends IDMEvent<IModules.ISymbolDMContext> {}
+
+ /**
+ * Retrieves the list of symbols.
+ * @param symCtx Symbols context to retrieve symbols for.
+ * @param rm Request completion monitor. The return value is an iterator (rather than
+ * array) since there could be a very large number of symbols returned.
+ */
+ public void getSymbols(IModules.ISymbolDMContext symCtx, DataRequestMonitor<Iterable<ISymbolObjectDMContext>> rm);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java
new file mode 100644
index 00000000000..3054e2af136
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/StepQueueManager.java
@@ -0,0 +1,248 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service;
+
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.IResumedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.cdt.dsf.debug.service.IRunControl.StepType;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.AbstractDsfService;
+import org.eclipse.cdt.dsf.service.DsfServiceEventHandler;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.osgi.framework.BundleContext;
+
+/**
+ * This service builds on top of standard run control service to provide
+ * step queuing functionality. Step queuing essentially allows user to press
+ * and hold the step key and achieve maximum stepping speed. If this service
+ * is used, other service implementations, such as stack and expressions, can
+ * use it to avoid requesting data from debugger back end if another step is
+ * about to be executed.
+ *
+ * @deprecated The functionality has been integrated in the UI layer.
+ */
+@Deprecated
+public class StepQueueManager extends AbstractDsfService implements IStepQueueManager
+{
+ /**
+ * Amount of time in milliseconds, that it takes the ISteppingTimedOutEvent
+ * event to be issued after a step is started.
+ * @see ISteppingTimedOutEvent
+ */
+ public final static int STEPPING_TIMEOUT = 500;
+
+ /**
+ * The depth of the step queue. In other words, the maximum number of steps
+ * that are queued before the step queue manager throwing them away.
+ */
+ public final static int STEP_QUEUE_DEPTH = 3;
+
+ /**
+ * Indicates that the given context has been stepping for some time,
+ * and the UI (views and actions) may need to be updated accordingly.
+ */
+ public interface ISteppingTimedOutEvent extends IDMEvent<IExecutionDMContext> {}
+
+
+ private static class StepRequest {
+ StepType fStepType;
+ StepRequest(StepType type) {
+ fStepType = type;
+ }
+ }
+
+ private IRunControl fRunControl;
+ private int fQueueDepth = STEP_QUEUE_DEPTH;
+ private Map<IExecutionDMContext,List<StepRequest>> fStepQueues = new HashMap<IExecutionDMContext,List<StepRequest>>();
+ private Map<IExecutionDMContext,Boolean> fTimedOutFlags = new HashMap<IExecutionDMContext,Boolean>();
+ private Map<IExecutionDMContext,ScheduledFuture<?>> fTimedOutFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
+
+ public StepQueueManager(DsfSession session) {
+ super(session);
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // IDsfService
+ @Override
+ public void initialize(final RequestMonitor requestMonitor) {
+ super.initialize(
+ new RequestMonitor(getExecutor(), requestMonitor) {
+ @Override
+ protected void handleSuccess() {
+ doInitialize(requestMonitor);
+ }});
+ }
+
+ private void doInitialize(final RequestMonitor requestMonitor) {
+ fRunControl = getServicesTracker().getService(IRunControl.class);
+
+ getSession().addServiceEventListener(this, null);
+ register(new String[]{ StepQueueManager.class.getName()}, new Hashtable<String,String>());
+ requestMonitor.done();
+ }
+
+ @Override
+ public void shutdown(final RequestMonitor requestMonitor) {
+ unregister();
+ getSession().removeServiceEventListener(this);
+ super.shutdown(requestMonitor);
+ }
+
+ @Override
+ protected BundleContext getBundleContext() {
+ return DsfPlugin.getBundleContext();
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.service.IStepQueueManager#canEnqueueStep(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.dsf.debug.service.IRunControl.StepType, org.eclipse.cdt.dsf.concurrent.DataRequestMonitor)
+ */
+ public void canEnqueueStep(IExecutionDMContext execCtx, StepType stepType, DataRequestMonitor<Boolean> rm) {
+ if (doCanEnqueueStep(execCtx, stepType)) {
+ rm.setData(true);
+ rm.done();
+ } else {
+ fRunControl.canStep(execCtx, stepType, rm);
+ }
+ }
+
+ private boolean doCanEnqueueStep(IExecutionDMContext execCtx, StepType stepType) {
+ return fRunControl.isStepping(execCtx) && !isSteppingTimedOut(execCtx);
+ }
+
+ /**
+ * Returns the number of step commands that are queued for given execution
+ * context.
+ */
+ public int getPendingStepCount(IExecutionDMContext execCtx) {
+ List<StepRequest> stepQueue = fStepQueues.get(execCtx);
+ if (stepQueue == null) return 0;
+ return stepQueue.size();
+ }
+
+ /*
+ * @see org.eclipse.cdt.dsf.debug.service.IStepQueueManager#enqueueStep(org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.cdt.dsf.debug.service.IRunControl.StepType)
+ */
+ public void enqueueStep(final IExecutionDMContext execCtx, final StepType stepType) {
+ fRunControl.canStep(
+ execCtx, stepType, new DataRequestMonitor<Boolean>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess() && getData()) {
+ fRunControl.step(execCtx, stepType, new RequestMonitor(getExecutor(), null));
+ } else if (doCanEnqueueStep(execCtx, stepType)) {
+ List<StepRequest> stepQueue = fStepQueues.get(execCtx);
+ if (stepQueue == null) {
+ stepQueue = new LinkedList<StepRequest>();
+ fStepQueues.put(execCtx, stepQueue);
+ }
+ if (stepQueue.size() < fQueueDepth) {
+ stepQueue.add(new StepRequest(stepType));
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Returns whether the step instruction for the given context has timed out.
+ */
+ public boolean isSteppingTimedOut(IExecutionDMContext execCtx) {
+ for (IExecutionDMContext timedOutCtx : fTimedOutFlags.keySet()) {
+ if (execCtx.equals(timedOutCtx) || DMContexts.isAncestorOf(execCtx, timedOutCtx)) {
+ return fTimedOutFlags.get(timedOutCtx);
+ }
+ }
+ return false;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final ISuspendedDMEvent e) {
+ // Take care of the stepping time out
+ fTimedOutFlags.remove(e.getDMContext());
+ ScheduledFuture<?> future = fTimedOutFutures.remove(e.getDMContext());
+ if (future != null) future.cancel(false);
+
+ // Check if there's a step pending, if so execute it
+ if (fStepQueues.containsKey(e.getDMContext())) {
+ List<StepRequest> queue = fStepQueues.get(e.getDMContext());
+ final StepRequest request = queue.remove(queue.size() - 1);
+ if (queue.isEmpty()) fStepQueues.remove(e.getDMContext());
+ fRunControl.canStep(
+ e.getDMContext(), request.fStepType,
+ new DataRequestMonitor<Boolean>(getExecutor(), null) {
+ @Override
+ protected void handleCompleted() {
+ if (isSuccess() && getData()) {
+ fRunControl.step(
+ e.getDMContext(), request.fStepType, new RequestMonitor(getExecutor(), null));
+ } else {
+ // For whatever reason we can't step anymore, so clear out
+ // the step queue.
+ fStepQueues.remove(e.getDMContext());
+ }
+ }
+ });
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(final IResumedDMEvent e) {
+ if (e.getReason().equals(StateChangeReason.STEP)) {
+ fTimedOutFlags.put(e.getDMContext(), Boolean.FALSE);
+ // We shouldn't have a stepping timeout running unless we get two
+ // stepping events in a row without a suspended, which would be a
+ // protocol error.
+ assert !fTimedOutFutures.containsKey(e.getDMContext());
+ fTimedOutFutures.put(
+ e.getDMContext(),
+ getExecutor().schedule(
+ new DsfRunnable() { public void run() {
+ fTimedOutFutures.remove(e.getDMContext());
+
+ if (getSession().isActive()) {
+ // Issue the stepping time-out event.
+ getSession().dispatchEvent(
+ new ISteppingTimedOutEvent() {
+ public IExecutionDMContext getDMContext() { return e.getDMContext(); }
+ },
+ getProperties());
+ }
+ }},
+ STEPPING_TIMEOUT, TimeUnit.MILLISECONDS)
+ );
+
+ }
+ }
+
+ @DsfServiceEventHandler
+ public void eventDispatched(ISteppingTimedOutEvent e) {
+ fTimedOutFlags.put(e.getDMContext(), Boolean.TRUE);
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java
new file mode 100644
index 00000000000..0c0f1360da2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/CommandCache.java
@@ -0,0 +1,549 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson - Modified for caching commands corresponding to multiple execution contexts
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.datamodel.DMContexts;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * This is a utility class for caching results of MI Commands. Return MIInfo
+ * data is retrieved from the cache if command was previously executed, and
+ * it is executed with MICommand service if it was not previously seen.
+ *
+ * Resetting the cache has to be performed by the object owning the cache when
+ * when an event indicates that the data is obsolete (which is specific to the
+ * types of commands being cached).
+ */
+
+public class CommandCache implements ICommandListener
+{
+ static enum CommandStyle { COALESCED, NONCOALESCED }
+
+ /**
+ * Holds cache information for a given command.
+ * @param <V> Type matches the result type associated with the command.
+ */
+ class CommandInfo {
+
+ /*
+ * Control variables.
+ */
+
+ /** List of the request monitors associated with this command */
+ private final List<DataRequestMonitor<ICommandResult>> fCurrentRequestMonitors ;
+
+ /** Original command. Need for reference from Queue completion notification */
+ private final ICommand<ICommandResult> fCommand;
+
+ /** Style of this command ( internal coalesced or not) */
+ private final CommandStyle fCmdStyle;
+
+ /** Command being processed for this command */
+ private CommandInfo fCoalescedCmd;
+
+ private ICommandToken fToken;
+
+ public CommandInfo(CommandStyle cmdstyle, ICommand<ICommandResult> cmd, DataRequestMonitor<ICommandResult> rm ) {
+ fCmdStyle = cmdstyle;
+ fCommand = cmd;
+ fCurrentRequestMonitors = new LinkedList<DataRequestMonitor<ICommandResult>>();
+ fCurrentRequestMonitors.add(rm);
+ fCoalescedCmd = null;
+ }
+
+ public CommandStyle getCommandstyle() { return fCmdStyle; }
+ public List<DataRequestMonitor<ICommandResult>> getRequestMonitorList() { return fCurrentRequestMonitors; }
+ public ICommand<ICommandResult> getCommand() { return fCommand; }
+ public CommandInfo getCoalescedCmd() { return fCoalescedCmd; }
+ public void setCoalescedCmd( CommandInfo cmd ) { fCoalescedCmd = cmd; }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CommandInfo)) return false;
+ CommandInfo otherCmd = (CommandInfo)other;
+
+ return otherCmd.fCommand.equals(fCommand);
+ }
+
+ @Override
+ public int hashCode() {
+ return fCommand.hashCode();
+ }
+ }
+
+ class CommandResultInfo {
+ private final ICommandResult fData;
+ private final IStatus fStatus;
+
+ public CommandResultInfo(ICommandResult data, IStatus status) {
+ fData = data;
+ fStatus = status;
+ }
+
+ public ICommandResult getData() { return fData; }
+ public IStatus getStatus() { return fStatus; }
+ }
+
+ private DsfSession fSession;
+
+ private ICommandControl fCommandControl;
+
+ /*
+ * This class contains 5 significant lists.
+ *
+ * Cached Results :
+ *
+ * Contains a mapping of commands and their completed results. Until the cached
+ * results are cleared by the owner of the cache.
+ *
+ * Pending Commands Not Queued :
+ *
+ * The Control object has not yet indicated that it has recognized the command
+ * yet. The user is not allowed to interrogate these objects until the Control
+ * object indicates they have been queued ( commandQueued notification ).
+ *
+ * Pending Commands Unsent :
+ *
+ * This is the list of commands which have been issued to the Control object but
+ * have not been actually issued to the backend. These commands represent coalesce
+ * options. They may be compared against the Queued list being maintained by the
+ * Control object until told otherwise - commandSent notification ).
+ *
+ * Pending Commands Sent :
+ *
+ * This is a list of commands which have been issued to the Control object and
+ * have also been sent to the backend. It is not possible use these objects for
+ * coalescents.
+ *
+ * Coalesced Pending Q :
+ *
+ * These represent original commands for which a new coalesced command has been
+ * created. When the coalesced commands completes the results will be decomposed
+ * when back into individual results from this command.
+ */
+ private Set<IDMContext> fAvailableContexts = new HashSet<IDMContext>();
+
+ private Map<IDMContext, HashMap<CommandInfo, CommandResultInfo>> fCachedContexts = new HashMap<IDMContext, HashMap<CommandInfo, CommandResultInfo>>();
+
+ private ArrayList<CommandInfo> fPendingQCommandsSent = new ArrayList<CommandInfo>();
+
+ private ArrayList<CommandInfo> fPendingQCommandsNotYetSent = new ArrayList<CommandInfo>();
+
+ private ArrayList<CommandInfo> fPendingQWaitingForCoalescedCompletion = new ArrayList<CommandInfo>();
+
+ public CommandCache(DsfSession session, ICommandControl control) {
+ fSession = session;
+ fCommandControl = control;
+
+ /*
+ * We listen for the notifications that the commands have been sent to the
+ * backend from the GDB/MI Communications engine.
+ */
+ fCommandControl.addCommandListener(this);
+ }
+
+ /*
+ * Constructs a coalesced command if possible.
+ */
+ private CommandInfo getCoalescedCommand(CommandInfo cmd) {
+
+ for ( CommandInfo currentUnsentEntry : new ArrayList<CommandInfo>(fPendingQCommandsNotYetSent) ) {
+ /*
+ * Get the current unsent entry to determine if we can coalesced with it.
+ */
+ ICommand<?> unsentCommand = currentUnsentEntry.getCommand();
+
+ /*
+ * Check if we can so construct a new COALESCED command from scratch.
+ */
+
+ // For sanity's sake, cast the generic ?'s to concrete types in the cache implementation.
+ @SuppressWarnings("unchecked")
+ ICommand<ICommandResult> coalescedCmd =
+ (ICommand<ICommandResult>)unsentCommand.coalesceWith( cmd.getCommand() );
+
+ if ( coalescedCmd != null ) {
+ CommandInfo coalescedCmdInfo = new CommandInfo( CommandStyle.COALESCED, coalescedCmd, null) ;
+
+ if ( currentUnsentEntry.getCommandstyle() == CommandStyle.COALESCED ) {
+ /*
+ * We matched a command which is itself already a COALESCED command. So
+ * we need to run through the reference list and point all the current
+ * command which are referencing the command we just subsumed and change
+ * them to point to the new super command.
+ */
+
+ for ( CommandInfo waitingEntry : new ArrayList<CommandInfo>(fPendingQWaitingForCoalescedCompletion) ) {
+
+ if ( waitingEntry.getCoalescedCmd() == currentUnsentEntry ) {
+ /*
+ * This referenced the old command change it to point to the new one.
+ */
+ waitingEntry.setCoalescedCmd(coalescedCmdInfo);
+ }
+ }
+ } else {
+ /*
+ * This currently unsent entry needs to go into the coalescing list. To
+ * be completed when the coalesced command comes back with a result.
+ */
+ fPendingQWaitingForCoalescedCompletion.add(currentUnsentEntry);
+ currentUnsentEntry.setCoalescedCmd(coalescedCmdInfo);
+ }
+
+ /*
+ * Either way we want to take the command back from the Control object so it
+ * does not continue to process it.
+ */
+ fPendingQCommandsNotYetSent.remove(currentUnsentEntry);
+ fCommandControl.removeCommand(currentUnsentEntry.fToken);
+
+ return( coalescedCmdInfo );
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Executes given ICommand, or retrieves the cached result if known.
+ * @param command Command to execute.
+ * @param rm Return token, contains the retrieved MIInfo object as
+ * well as its cache status.
+ */
+ public <V extends ICommandResult> void execute(ICommand<V> command, DataRequestMonitor<V> rm) {
+ assert fSession.getExecutor().isInExecutorThread();
+
+ // Cast the generic ?'s to concrete types in the cache implementation.
+ @SuppressWarnings("unchecked")
+ final ICommand<ICommandResult> genericCommand = (ICommand<ICommandResult>)command;
+ @SuppressWarnings("unchecked")
+ final DataRequestMonitor<ICommandResult> genericDone = (DataRequestMonitor<ICommandResult>) rm;
+
+ CommandInfo cachedCmd = new CommandInfo( CommandStyle.NONCOALESCED, genericCommand, genericDone) ;
+
+ final IDMContext context = genericCommand.getContext();
+
+ /*
+ * If command is already cached, just return the cached data.
+ */
+ if(fCachedContexts.get(context) != null && fCachedContexts.get(context).containsKey(cachedCmd)){
+ CommandResultInfo result = fCachedContexts.get(context).get(cachedCmd);
+ if (result.getStatus().getSeverity() <= IStatus.INFO) {
+ @SuppressWarnings("unchecked")
+ V v = (V)result.getData();
+ rm.setData(v);
+ } else {
+ rm.setStatus(result.getStatus());
+ }
+ rm.done();
+ return;
+ }
+
+ /*
+ * Return an error if the target is available anymore.
+ */
+ if (!isTargetAvailable(command.getContext())) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_STATE, "Target not available.", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ /*
+ * If we are already waiting for this command to complete,
+ * add this request monitor to list of waiting monitors.
+ */
+ for ( CommandInfo sentCommand : fPendingQCommandsSent ) {
+ if ( sentCommand.equals( cachedCmd )) {
+ sentCommand.getRequestMonitorList().add(genericDone);
+ return;
+ }
+ }
+ for ( CommandInfo notYetSentCommand : fPendingQCommandsNotYetSent ) {
+ if ( notYetSentCommand.equals( cachedCmd )) {
+ notYetSentCommand.getRequestMonitorList().add(genericDone);
+ return;
+ }
+ }
+
+
+ /*
+ * We see if this command can be combined into a coalesced one. The
+ * coalesce routine will take care of the already enqueued one which
+ * this command is being coalesced with.
+ */
+
+ CommandInfo coalescedCmd = getCoalescedCommand(cachedCmd);
+
+ if ( coalescedCmd != null ) {
+ /*
+ * The original command we were handed needs to go into the waiting QUEUE.
+ * We also need to point it it to the coalesced command.
+ */
+ fPendingQWaitingForCoalescedCompletion.add(cachedCmd);
+ cachedCmd.setCoalescedCmd(coalescedCmd);
+ cachedCmd = coalescedCmd;
+ }
+
+ /*
+ * Now we have a command to send ( coalesced or not ). Put it in the cannot touch
+ * it list and give it to the Control object. Our state handlers will move it into
+ * the proper list as the Control object deals with it.
+ */
+ final CommandInfo finalCachedCmd = cachedCmd;
+ fPendingQCommandsNotYetSent.add(finalCachedCmd);
+
+ finalCachedCmd.fToken = fCommandControl.queueCommand(
+ finalCachedCmd.getCommand(),
+ new DataRequestMonitor<ICommandResult>(fSession.getExecutor(), null) {
+ @Override
+ public void handleCompleted() {
+
+ /*
+ * Match this up with a command set we know about.
+ */
+ if ( ! fPendingQCommandsSent.remove(finalCachedCmd) ) {
+ /*
+ * It should not be the case that this is possible. It would mean we
+ * have mismanaged the queues or completions are lost at the lower
+ * levels. When the removal and cancellation is completed this code
+ * will probably not be here. But for now just return.
+ */
+ return ;
+ }
+
+ ICommandResult result = getData();
+ IStatus status = getStatus();
+
+ if ( finalCachedCmd.getCommandstyle() == CommandStyle.COALESCED ) {
+ /*
+ * We matched a command which is itself already a COALESCED command. So
+ * we need to go through the list of unsent commands which were not sent
+ * because the coalesced command represented it. For each match we find
+ * we create a new result from the coalesced command for it.
+ */
+
+ for ( CommandInfo waitingEntry : new ArrayList<CommandInfo>(fPendingQWaitingForCoalescedCompletion) ) {
+
+ if ( waitingEntry.getCoalescedCmd() == finalCachedCmd ) {
+
+ /*
+ * Remove this entry from the list since we can complete it.
+ */
+ fPendingQWaitingForCoalescedCompletion.remove(waitingEntry);
+
+ // Cast the calculated result back to the requested type.
+ @SuppressWarnings("unchecked")
+ V subResult = (V)result.getSubsetResult(waitingEntry.getCommand());
+ CommandResultInfo subResultInfo = new CommandResultInfo(subResult, status);
+
+ if(fCachedContexts.get(context) != null){
+ fCachedContexts.get(context).put(waitingEntry, subResultInfo);
+ } else {
+ HashMap<CommandInfo, CommandResultInfo> map = new HashMap<CommandInfo, CommandResultInfo>();
+ map.put(waitingEntry, subResultInfo);
+ fCachedContexts.put(context, map);
+ }
+
+ if (!isSuccess()) {
+
+ /*
+ * We had some form of error with the original command. So notify the
+ * original requesters of the issues.
+ */
+ for (DataRequestMonitor<?> pendingRM : waitingEntry.getRequestMonitorList()) {
+ pendingRM.setStatus(status);
+ pendingRM.done();
+ }
+ } else {
+ assert subResult != null;
+
+ /*
+ * Notify the original requesters of the positive results.
+ */
+ for (DataRequestMonitor<? extends ICommandResult> pendingRM : waitingEntry.getRequestMonitorList()) {
+ // Cast the pending return token to match the requested type.
+ @SuppressWarnings("unchecked")
+ DataRequestMonitor<V> vPendingRM = (DataRequestMonitor<V>) pendingRM;
+
+ vPendingRM.setData(subResult);
+ vPendingRM.done();
+ }
+ }
+ }
+ }
+ } else {
+ /*
+ * This is an original request which completed. Indicate success or
+ * failure to the original requesters.
+ */
+ CommandResultInfo resultInfo = new CommandResultInfo(result, status);
+
+ if (fCachedContexts.get(context) != null){
+ fCachedContexts.get(context).put(finalCachedCmd, resultInfo);
+ } else {
+ HashMap<CommandInfo, CommandResultInfo> map = new HashMap<CommandInfo, CommandResultInfo>();
+ map.put(finalCachedCmd, resultInfo);
+ fCachedContexts.put(context, map);
+ }
+
+ if (!isSuccess()) {
+ /*
+ * We had some form of error with the original command. So notify the
+ * original requesters of the issues.
+ */
+ for (DataRequestMonitor<?> pendingRM : finalCachedCmd.getRequestMonitorList()) {
+ pendingRM.setStatus(status);
+ pendingRM.done();
+ }
+ } else {
+ // Cast the calculated result back to the requested type.
+ @SuppressWarnings("unchecked")
+ V vResult = (V)result;
+
+ for (DataRequestMonitor<? extends ICommandResult> pendingRM : finalCachedCmd.getRequestMonitorList()) {
+ // Cast the pending return token to match the requested type.
+ @SuppressWarnings("unchecked")
+ DataRequestMonitor<V> vPendingRM = (DataRequestMonitor<V>) pendingRM;
+
+ vPendingRM.setData(vResult);
+ vPendingRM.done();
+ }
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * TODO
+ */
+ public void setContextAvailable(IDMContext context, boolean isAvailable) {
+ if (isAvailable) {
+ fAvailableContexts.add(context);
+ } else {
+ fAvailableContexts.remove(context);
+ for (Iterator<IDMContext> itr = fAvailableContexts.iterator(); itr.hasNext();) {
+ if (DMContexts.isAncestorOf(context, itr.next())) {
+ itr.remove();
+ }
+ }
+ }
+ }
+
+ /**
+ * TODO
+ * @see #setContextAvailable(IDMContext, boolean)
+ */
+ public boolean isTargetAvailable(IDMContext context) {
+ for (IDMContext availableContext : fAvailableContexts) {
+ if (context.equals(availableContext) || DMContexts.isAncestorOf(context, availableContext)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+
+ /**
+ * Clears the cache data.
+ */
+ public void reset() {
+ fCachedContexts.clear();
+ }
+
+ public void commandRemoved(ICommandToken token) {
+ /*
+ * Do nothing.
+ */
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandQueued(org.eclipse.cdt.dsf.mi.core.command.ICommand)
+ */
+ public void commandQueued(ICommandToken token) {
+ /*
+ * Do nothing.
+ */
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandDone(org.eclipse.cdt.dsf.mi.core.command.ICommand, org.eclipse.cdt.dsf.mi.core.command.ICommandResult)
+ */
+ public void commandDone(ICommandToken token, ICommandResult result) {
+ /*
+ * We handle the done with a runnable where we initiated the command
+ * so there is nothing to do here.
+ */
+ }
+
+ /*
+ * Move the command into our internal sent list. This means we can no longer look at
+ * this command for possible coalescence since it has been given to the debug engine
+ * and is currently being processed.
+ *
+ * (non-Javadoc)
+ * @see org.eclipse.cdt.dsf.mi.service.control.IDebuggerControl.ICommandListener#commandSent(org.eclipse.cdt.dsf.mi.core.command.ICommand)
+ */
+ public void commandSent(ICommandToken token) {
+
+ // Cast the generic ?'s to concrete types in the cache implementation.
+ @SuppressWarnings("unchecked")
+ ICommand<ICommandResult> genericCommand = (ICommand<ICommandResult>)token.getCommand();
+
+ CommandInfo cachedCmd = new CommandInfo( CommandStyle.NONCOALESCED, genericCommand, null) ;
+
+ for ( CommandInfo unqueuedCommand : new ArrayList<CommandInfo>(fPendingQCommandsNotYetSent) ) {
+ if ( unqueuedCommand.equals( cachedCmd )) {
+ fPendingQCommandsNotYetSent.remove(unqueuedCommand);
+ fPendingQCommandsSent.add(unqueuedCommand);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Clears the cache entries for given context. Clears the whole cache if
+ * context parameter is null.
+ */
+ public void reset(IDMContext dmc) {
+ if (dmc == null) {
+ fCachedContexts.clear();
+ return;
+ }
+ for (Iterator<IDMContext> itr = fCachedContexts.keySet().iterator(); itr.hasNext();) {
+ IDMContext keyDmc = itr.next();
+ if (keyDmc != null && (dmc.equals(keyDmc) || DMContexts.isAncestorOf(keyDmc, dmc))) {
+ itr.remove();
+ }
+ }
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java
new file mode 100644
index 00000000000..6c63ae8fb35
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommand.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ * Ericsson - Modified for additional features in DSF Reference implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+
+
+/**
+ * Command interface for creating and manipulating GDB/MI commands
+ * for the DSF GDB reference implemenation. The command represents
+ * the GDB/MI request which will be put on the wire to the GDB
+ * backend.
+ */
+
+public interface ICommand<V extends ICommandResult> {
+ /**
+ * Takes the supplied command and coalesces it with this one.
+ * The result is a new third command which represent the two
+ * original commands.
+ * <br>Note: the result type associated with the resurned command may be
+ * different than the result type associated with either of the commands
+ * being coalesced.
+ *
+ * @return newly created command, or null if command cannot be coalesced
+ */
+ public ICommand<? extends ICommandResult> coalesceWith( ICommand<? extends ICommandResult> command );
+
+ /**
+ * Returns the context that this command is to be evaluated in. May be null
+ * if the command does not need to be evaluated in a specific context.
+ */
+ public IDMContext getContext();
+}
+
+
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java
new file mode 100644
index 00000000000..dd174d3bd4a
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControl.java
@@ -0,0 +1,72 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+
+/**
+ * API for sending commands to the debugger and for receiving command results
+ * and asynchronous events. The command control may be implemented by a service
+ * or a non-service object.
+ *
+ * @see ICommandControlService
+ */
+public interface ICommandControl {
+
+ /**
+ * Adds the specified command to the queue of commands to be processed.
+ *
+ * @param command Specific command to be processed
+ * @param rm Request completion monitor
+ * @return None
+ */
+ <V extends ICommandResult> ICommandToken queueCommand(ICommand<V> command, DataRequestMonitor<V> rm);
+
+ /**
+ * Removes the specified command from the processor queue.
+ *
+ * @param command Specific command to be removed
+ * @return None
+ */
+ void removeCommand(ICommandToken token);
+
+ /**
+ * Adds a notification handler for the Command processor.
+ *
+ * @param command listener to be added
+ * @return None
+ */
+ void addCommandListener(ICommandListener listener);
+
+ /**
+ * Removes a notification handler for the Command processor.
+ *
+ * @param command listener to be removed
+ * @return None
+ */
+ void removeCommandListener(ICommandListener listener);
+
+ /**
+ * Adds a notification handler for the Event processor.
+ *
+ * @param event listener to be added
+ * @return None
+ */
+ void addEventListener(IEventListener listener);
+
+ /**
+ * Removes a notification handler for the Event processor.
+ *
+ * @param event listener to be removed
+ * @return None
+ */
+ void removeEventListener(IEventListener listener);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java
new file mode 100644
index 00000000000..0672d5ec986
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandControlService.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.datamodel.IDMEvent;
+import org.eclipse.cdt.dsf.service.IDsfService;
+
+/**
+ * Service which acts as a command control.
+ *
+ * @since 1.1
+ */
+public interface ICommandControlService extends ICommandControl, IDsfService {
+
+ /**
+ * Context representing a command control service. All contexts which
+ * originate from a given command control service, should have that
+ * control's context in their hierarchy.
+ *
+ * @see ICommandControlService#getContext()
+ */
+ public interface ICommandControlDMContext extends IDMContext {
+ /**
+ * Returns the ID of the command control that this context
+ * represents.
+ */
+ public String getCommandControlId();
+ }
+
+ /**
+ * Event indicating that the back end process has started.
+ */
+ public interface ICommandControlInitializedDMEvent extends IDMEvent<ICommandControlDMContext> {};
+
+ /**
+ * Event indicating that the back end process has terminated.
+ */
+ public interface ICommandControlShutdownDMEvent extends IDMEvent<ICommandControlDMContext> {};
+
+ /**
+ * Returns the identifier of this command control service. It can be used
+ * to distinguish between multiple instances of command control services.
+ */
+ public String getId();
+
+ /**
+ * returns the context representing this command control.
+ */
+ public ICommandControlDMContext getContext();
+
+ /**
+ * Returns whether this command control is currently active. A command
+ * control service is active if it has been initialized and has not yet
+ * shut down.
+ * @return
+ */
+ public boolean isActive();
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java
new file mode 100644
index 00000000000..f7a0f80ae79
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandListener.java
@@ -0,0 +1,64 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+
+/**
+ * Synchronous listener to commands being sent and received.
+ * All the registered listeners will be called in the same
+ * dispatch cycle as when the result of the command is submitted.
+ */
+
+@ConfinedToDsfExecutor("")
+public interface ICommandListener {
+ /**
+ * Notifies that the specified command has been added to the Command Queue.
+ * It has not yet been sent. In this state the command can be examined and
+ * possibly withdrawn because it has been coalesced with another command.
+ *
+ * @return None
+ * @param command Command which has been added to the Queue
+ */
+ public void commandQueued(ICommandToken token);
+
+ /**
+ * Notification that the given command was sent to the debugger. At this
+ * point the command is no longer in the Command Queue and should not be
+ * examined. The only thing which can be done is to try and cancel the
+ * command.
+ *
+ * @return None
+ * @param command
+ */
+ public void commandSent(ICommandToken token);
+
+ /**
+ * Notifies that the specified command has been removed from the
+ * Command Queue. This notification means that the command has
+ * been removed from the queue and not sent to the backend. The
+ * user has specifically removed it, perhaps because it has been
+ * combined with another. Or some state change has occured and
+ * there is no longer a need to get this particular set of data.
+ *
+ * @return None
+ * @param Command which has been sent to the backend
+ */
+ public void commandRemoved(ICommandToken token);
+
+ /**
+ * Notifies that the specified command has been completed.
+ *
+ * @return None
+ * @param Command which has been sent to the backend
+ */
+ public void commandDone(ICommandToken token, ICommandResult result);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java
new file mode 100644
index 00000000000..09e53154c43
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandResult.java
@@ -0,0 +1,27 @@
+/*******************************************************************************
+ * Copyright (c) 2007 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.debug.service.command;
+
+public interface ICommandResult {
+ /**
+ * Returns an ICommandResult which is a subset command result. The command
+ * result which is being passed in is from a coalesced command. The result
+ * which is desired is contained within those results. In this instance we
+ * are processing the command result from the coalesced command to get our
+ * command result.
+ * <i>Note:</i> The type of returned command result must match the type
+ * associated with the subset command that is passed in the argument.
+ *
+ * @return result for this particular command.
+ */
+ public <V extends ICommandResult> V getSubsetResult( ICommand<V> command );
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java
new file mode 100644
index 00000000000..ccd80d234d2
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/ICommandToken.java
@@ -0,0 +1,23 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.service.command;
+
+/**
+ * Token returned by ICommandControl.queueCommand(). This token can be used
+ * to uniquely identify a command when calling ICommandControl.removeCommand()
+ * or when implementing the ICommandListener listener methods.
+ */
+public interface ICommandToken {
+ /**
+ * Returns the command that this was created for.
+ */
+ public ICommand<? extends ICommandResult> getCommand();
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java
new file mode 100644
index 00000000000..49fa20f3eee
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/service/command/IEventListener.java
@@ -0,0 +1,19 @@
+package org.eclipse.cdt.dsf.debug.service.command;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+
+/**
+ * Synchronous listener for events issued from the debugger. All
+ * registered listeners will be called in the same dispatch cycle.
+ */
+
+@ConfinedToDsfExecutor("")
+public interface IEventListener {
+ /**
+ * Notifies that the given asynchronous output was received from the
+ * debugger.
+ * @param output output that was received from the debugger. Format
+ * of the output data is debugger specific.
+ */
+ public void eventReceived(Object output);
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java
new file mode 100644
index 00000000000..2e881b18c6c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupDirector.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * Copyright (c) 2004, 2008 QNX Software Systems 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:
+ * QNX Software Systems - Initial API and implementation
+ * Nokia - Added support for AbsoluteSourceContainer( 159833 )
+ * Wind River Systems - Adapted for use with DSF
+*******************************************************************************/
+package org.eclipse.cdt.dsf.debug.sourcelookup;
+
+import org.eclipse.cdt.debug.internal.core.sourcelookup.CSourceLookupDirector;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+
+/**
+ * DSF source lookup director.
+ */
+public class DsfSourceLookupDirector extends CSourceLookupDirector {
+
+ private final DsfSession fSession;
+
+ public DsfSourceLookupDirector(DsfSession session) {
+ fSession = session;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupDirector#initializeParticipants()
+ */
+ @Override
+ public void initializeParticipants() {
+ super.initializeParticipants();
+ addParticipants( new ISourceLookupParticipant[]{ new DsfSourceLookupParticipant(fSession) } );
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java
new file mode 100644
index 00000000000..11a105e6f2e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/debug/sourcelookup/DsfSourceLookupParticipant.java
@@ -0,0 +1,229 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.debug.sourcelookup;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DataRequestMonitor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.Query;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.datamodel.IDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMContext;
+import org.eclipse.cdt.dsf.debug.service.IStack.IFrameDMData;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.cdt.dsf.service.DsfServicesTracker;
+import org.eclipse.cdt.dsf.service.DsfSession;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.MultiStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.sourcelookup.ISourceContainer;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
+import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
+
+/**
+ * Source lookup participant that should be used with DSF-based debuggers.
+ */
+@ThreadSafe
+public class DsfSourceLookupParticipant implements ISourceLookupParticipant {
+ protected static final Object[] EMPTY = new Object[0];
+
+ private DsfExecutor fExecutor;
+ private String fSessionId;
+ private DsfServicesTracker fServicesTracker;
+ private ISourceLookupDirector fDirector;
+ private Map<String, List<Object>> fLookupCache = Collections.synchronizedMap(new HashMap<String, List<Object>>());
+
+ public DsfSourceLookupParticipant(DsfSession session) {
+ fSessionId = session.getId();
+ fExecutor = session.getExecutor();
+ fServicesTracker = new DsfServicesTracker(DsfPlugin.getBundleContext(), fSessionId);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#init(org.eclipse.debug.core.sourcelookup.ISourceLookupDirector)
+ */
+ public void init(ISourceLookupDirector director) {
+ fDirector = director;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#dispose()
+ */
+ public void dispose() {
+ fServicesTracker.dispose();
+ fDirector = null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#findSourceElements(java.lang.Object)
+ */
+ public Object[] findSourceElements(Object object) throws CoreException {
+ CoreException single = null;
+ MultiStatus multiStatus = null;
+ List<Object> results = null;
+
+ String name = getSourceName(object);
+ if (name != null) {
+ results = fLookupCache.get(name);
+ if (results != null) {
+ return results.toArray();
+ } else {
+ results = new ArrayList<Object>();
+ }
+ ISourceContainer[] containers = getSourceContainers();
+ for (int i = 0; i < containers.length; i++) {
+ try {
+ ISourceContainer container = containers[i];
+ if (container != null) {
+ Object[] objects = container.findSourceElements(name);
+ if (objects.length > 0) {
+ if (isFindDuplicates()) {
+ results.addAll(Arrays.asList(objects));
+ } else {
+ results.add(objects[0]);
+ break;
+ }
+ }
+ }
+ } catch (CoreException e) {
+ if (single == null) {
+ single = e;
+ } else if (multiStatus == null) {
+ multiStatus = new MultiStatus(DebugPlugin.getUniqueIdentifier(), DebugPlugin.INTERNAL_ERROR, new IStatus[]{single.getStatus()}, "Source Lookup error", null); //$NON-NLS-1$
+ multiStatus.add(e.getStatus());
+ } else {
+ multiStatus.add(e.getStatus());
+ }
+ }
+ }
+
+ if (!results.isEmpty()) {
+ synchronized(fLookupCache) {
+ if (!fLookupCache.containsKey(name)) {
+ fLookupCache.put(name, results);
+ }
+ }
+ }
+ }
+ if (results == null || results.isEmpty()) {
+ if (multiStatus != null) {
+ throw new CoreException(multiStatus);
+ } else if (single != null) {
+ throw single;
+ }
+ return EMPTY;
+ }
+ return results.toArray();
+ }
+
+ /**
+ * Returns whether this participant's source lookup director is configured
+ * to search for duplicate source elements.
+ *
+ * @return whether this participant's source lookup director is configured
+ * to search for duplicate source elements
+ */
+ protected boolean isFindDuplicates() {
+ ISourceLookupDirector director = fDirector;
+ if (director != null) {
+ return director.isFindDuplicates();
+ }
+ return false;
+ }
+
+ /**
+ * Returns the source containers currently registered with this participant's
+ * source lookup director.
+ *
+ * @return the source containers currently registered with this participant's
+ * source lookup director
+ */
+ protected ISourceContainer[] getSourceContainers() {
+ ISourceLookupDirector director = fDirector;
+ if (director != null) {
+ return director.getSourceContainers();
+ }
+ return new ISourceContainer[0];
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant#sourceContainersChanged(org.eclipse.debug.core.sourcelookup.ISourceLookupDirector)
+ */
+ public void sourceContainersChanged(ISourceLookupDirector director) {
+ fLookupCache.clear();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.debug.internal.core.sourcelookup.ISourceLookupParticipant#getSourceName(java.lang.Object)
+ */
+ public String getSourceName(Object object) throws CoreException {
+ if ( !(object instanceof IDMContext) ||
+ !((IDMContext)object).getSessionId().equals(fSessionId) )
+ {
+ throw new CoreException(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Invalid object", null)); //$NON-NLS-1$
+ }
+
+ final IDMContext dmc = (IDMContext)object;
+ Query<String> query = new Query<String>() {
+ @Override
+ protected void execute(final DataRequestMonitor<String> rm) {
+ getSourceNameOnDispatchThread(dmc, rm);
+ }};
+ fExecutor.execute(query);
+ try {
+ return query.get();
+ } catch (InterruptedException e) { assert false : "Interrupted exception in DSF executor"; //$NON-NLS-1$
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof CoreException) {
+ throw (CoreException)e.getCause();
+ }
+ assert false : "Unexptected exception"; //$NON-NLS-1$
+ }
+ return null; // Should never get here.
+ }
+
+ @ConfinedToDsfExecutor("fExecutor")
+ private void getSourceNameOnDispatchThread(IDMContext dmc, final DataRequestMonitor<String> rm) {
+ if (!(dmc instanceof IStack.IFrameDMContext)) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "No source for this object", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+ IFrameDMContext frameDmc = (IFrameDMContext)dmc;
+
+ IStack stackService = fServicesTracker.getService(IStack.class);
+ if (stackService == null) {
+ rm.setStatus(new Status(IStatus.ERROR, DsfPlugin.PLUGIN_ID, IDsfStatusConstants.INVALID_HANDLE, "Stack data not available", null)); //$NON-NLS-1$
+ rm.done();
+ return;
+ }
+
+ stackService.getFrameData(
+ frameDmc,
+ new DataRequestMonitor<IFrameDMData>(fExecutor, rm) { @Override
+ public void handleSuccess() {
+ rm.setData(getData().getFile());
+ rm.done();
+ }});
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java
new file mode 100644
index 00000000000..11ccf06857b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/internal/DsfPlugin.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.internal;
+
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Plugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ */
+public class DsfPlugin extends Plugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.cdt.dsf"; //$NON-NLS-1$
+
+ // The shared instance
+ private static DsfPlugin fgPlugin;
+
+ // BundleContext of this plugin
+ private static BundleContext fgBundleContext;
+
+ // Debugging flag
+ public static boolean DEBUG = false;
+
+ /**
+ * The constructor
+ */
+ public DsfPlugin() {
+ fgPlugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void start(BundleContext context) throws Exception {
+ fgBundleContext = context;
+ super.start(context);
+ DEBUG = "true".equals(Platform.getDebugOption("org.eclipse.cdt.dsf/debug")); //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
+ */
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ fgBundleContext = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static DsfPlugin getDefault() {
+ return fgPlugin;
+ }
+
+ public static BundleContext getBundleContext() {
+ return fgBundleContext;
+ }
+
+ public static void debug(String message) {
+ if (DEBUG) {
+ System.out.println(message);
+ }
+ }
+
+ public static String getDebugTime() {
+ StringBuilder traceBuilder = new StringBuilder();
+
+ // Record the time
+ long time = System.currentTimeMillis();
+ long seconds = (time / 1000) % 1000;
+ if (seconds < 100) traceBuilder.append('0');
+ if (seconds < 10) traceBuilder.append('0');
+ traceBuilder.append(seconds);
+ traceBuilder.append(',');
+ long millis = time % 1000;
+ if (millis < 100) traceBuilder.append('0');
+ if (millis < 10) traceBuilder.append('0');
+ traceBuilder.append(millis);
+ return traceBuilder.toString();
+ }
+
+
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java
new file mode 100644
index 00000000000..8d085eb6c27
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/AbstractDsfService.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.service;
+
+import java.util.Arrays;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.IDsfStatusConstants;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+
+
+/**
+ * Standard base implementation of the DSF service. This is a convenience
+ * class that provides the basic functionality that all DSF services have
+ * to implement.
+ */
+abstract public class AbstractDsfService
+ implements IDsfService, IDsfStatusConstants
+{
+ /** Reference to the session that this service belongs to. */
+ private DsfSession fSession;
+
+ /** Startup order number of this service. */
+ private int fStartupNumber;
+
+ /** Registration object for this service. */
+ private ServiceRegistration fRegistration;
+
+ /** Tracker for services that this service depends on. */
+ private DsfServicesTracker fTracker;
+
+ /** Properties that this service was registered with */
+ @SuppressWarnings("unchecked")
+ private Dictionary fProperties;
+
+ /** Properties that this service was registered with */
+ private String fFilter;
+
+ /**
+ * Only constructor, requires a reference to the session that this
+ * service belongs to.
+ * @param session
+ */
+ public AbstractDsfService(DsfSession session) {
+ fSession = session;
+ }
+
+ public DsfExecutor getExecutor() { return fSession.getExecutor(); }
+
+ @SuppressWarnings("unchecked")
+ public Dictionary getProperties() { return fProperties; }
+
+ public String getServiceFilter() { return fFilter; }
+
+ public int getStartupNumber() { return fStartupNumber; }
+
+ public void initialize(RequestMonitor rm) {
+ fTracker = new DsfServicesTracker(getBundleContext(), fSession.getId());
+ fStartupNumber = fSession.getAndIncrementServiceStartupCounter();
+ rm.done();
+ }
+
+ public void shutdown(RequestMonitor rm) {
+ fTracker.dispose();
+ fTracker = null;
+ rm.done();
+ }
+
+ /** Returns the session object for this service */
+ public DsfSession getSession() { return fSession; }
+
+ /**
+ * Sub-classes should return the bundle context of the plugin, which the
+ * service belongs to.
+ */
+ abstract protected BundleContext getBundleContext();
+
+ /** Returns the tracker for the services that this service depends on. */
+ protected DsfServicesTracker getServicesTracker() { return fTracker; }
+
+ /**
+ * Registers this service.
+ */
+ @SuppressWarnings("unchecked")
+ protected void register(String[] classes, Dictionary properties) {
+
+ /*
+ * If this service has already been registered, make sure we
+ * keep the names it has been registered with. However, we
+ * must trigger a new registration or else OSGI will keep the two
+ * registration separate.
+ */
+ if (fRegistration != null) {
+ String[] previousClasses = (String[])fRegistration.getReference().getProperty(Constants.OBJECTCLASS);
+
+ // Use a HashSet to avoid duplicates
+ Set<String> newClasses = new HashSet<String>();
+ newClasses.addAll(Arrays.asList(previousClasses));
+ newClasses.addAll(Arrays.asList(classes));
+ classes = newClasses.toArray(new String[0]);
+
+ /*
+ * Also keep all previous properties.
+ */
+ if (fProperties != null) {
+ for (Enumeration e = fProperties.keys() ; e.hasMoreElements();) {
+ Object key = e.nextElement();
+ Object value = fProperties.get(key);
+ properties.put(key, value);
+ }
+ }
+
+ // Now, cancel the previous registration
+ unregister();
+ }
+ /*
+ * Ensure that the list of classes contains the base DSF service
+ * interface, as well as the actual class type of this object.
+ */
+ if (!Arrays.asList(classes).contains(IDsfService.class.getName())) {
+ String[] newClasses = new String[classes.length + 1];
+ System.arraycopy(classes, 0, newClasses, 1, classes.length);
+ newClasses[0] = IDsfService.class.getName();
+ classes = newClasses;
+ }
+ if (!Arrays.asList(classes).contains(getClass().getName())) {
+ String[] newClasses = new String[classes.length + 1];
+ System.arraycopy(classes, 0, newClasses, 1, classes.length);
+ newClasses[0] = getClass().getName();
+ classes = newClasses;
+ }
+ /*
+ * Make sure that the session ID is set in the service properties.
+ * The session ID distinguishes this service instance from instances
+ * of the same service in other sessions.
+ */
+ properties.put(PROP_SESSION_ID, getSession().getId());
+ fProperties = properties;
+ fRegistration = getBundleContext().registerService(classes, this, properties);
+
+ /*
+ * Retrieve the OBJECTCLASS property directly from the service
+ * registration info. This is the best bet for getting an accurate
+ * value.
+ */
+ fRegistration.getReference().getProperty(Constants.OBJECTCLASS);
+ fProperties.put(Constants.OBJECTCLASS, fRegistration.getReference().getProperty(Constants.OBJECTCLASS));
+
+ /*
+ * Create the filter for this service based on all the properties. If
+ * there is a single service instance per session, or if the properties
+ * parameter uniquely identifies this service instance among other
+ * instances in this session. Then this filter will fetch this service
+ * and only this service from OSGi.
+ */
+ fFilter = generateFilter(fProperties);
+ }
+
+ /**
+ * Generates an LDAP filter to uniquely identify this service.
+ */
+ @SuppressWarnings("unchecked")
+ private String generateFilter(Dictionary properties) {
+ StringBuffer filter = new StringBuffer();
+ filter.append("(&"); //$NON-NLS-1$
+
+ for (Enumeration keys = properties.keys(); keys.hasMoreElements();) {
+ Object key = keys.nextElement();
+ Object value = properties.get(key);
+ if (value instanceof Object[]) {
+ /*
+ * For arrays, add a test to check that every element in array
+ * is present. This is here mainly to handle OBJECTCLASS property.
+ */
+ for (Object arrayValue : (Object[])value) {
+ filter.append('(');
+ filter.append(key.toString());
+ filter.append("=*"); //$NON-NLS-1$
+ filter.append(arrayValue.toString());
+ filter.append(')');
+ }
+ } else {
+ filter.append('(');
+ filter.append(key.toString());
+ filter.append('=');
+ filter.append(value.toString());
+ filter.append(')');
+ }
+ }
+ filter.append(')');
+ return filter.toString();
+ }
+
+ /**
+ * De-registers this service.
+ *
+ */
+ protected void unregister() {
+ if (fRegistration != null) {
+ fRegistration.unregister();
+ }
+ fRegistration = null;
+ }
+
+ /** Returns the registration object that was obtained when this service was registered */
+ protected ServiceRegistration getServiceRegistration() { return fRegistration; }
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java
new file mode 100644
index 00000000000..9f2e5525dcb
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServiceEventHandler.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2006 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.service;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for service event handler methods. The name of the event
+ * handler method is irrelevant, only the annotation is checked.
+ * <p>
+ * Each service event handler method should have one or two parameters:
+ * <li>
+ * <br> First argument is required and it should be the event object, with
+ * type with the event class desired.
+ * <br> Second argument is optional, and it has to be of type Dictionary<String,String>.
+ * If this parameter is declared, the handler will be passed the properties
+ * dictionary of the service that submitted the event.
+ * </li>
+ * <p>
+ * It is expected that service event classes are hierarchical. So that if a
+ * handler is registered for a super-class of another event, this handler
+ * will be called every time one of the sub-class events is invoked.
+ * If a listener declares a handler for an event AND a superclass of that event,
+ * both handlers will be invoked when the event is dispatched.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+@Documented
+public @interface DsfServiceEventHandler {
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java
new file mode 100644
index 00000000000..02b83b94b1d
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServices.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.dsf.service;
+
+/**
+ * Utility class containing status methods to use with DSF services.
+ */
+public class DsfServices {
+
+ /**
+ * Creates a properly formatted OSGi service filter for a DSF service based
+ * on service class and session ID.
+ * @param serviceClass Class of the service to create the filter for.
+ * @param sessionId Session ID of the session that the service belongs to.
+ * @return Filter string to identify the given service.
+ */
+ public static String createServiceFilter(Class<?> serviceClass, String sessionId) {
+ String serviceId =
+ "(&" + //$NON-NLS-1$
+ "(OBJECTCLASS=" + //$NON-NLS-1$
+ serviceClass.getName() +
+ ")" + //$NON-NLS-1$
+ "(" + //$NON-NLS-1$
+ IDsfService.PROP_SESSION_ID +
+ "=" + //$NON-NLS-1$
+ sessionId +
+ ")" + //$NON-NLS-1$
+ ")" ; //$NON-NLS-1$
+
+ return serviceId;
+ }
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java
new file mode 100644
index 00000000000..9a98805798c
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfServicesTracker.java
@@ -0,0 +1,169 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.service;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * Convenience class to help track DSF services that a given
+ * client needs to use. This class is similar to the standard OSGI
+ * org.osgi.util.tracker.ServiceTracker class, with a few differences:
+ * <br>1. This class is assumed to be accessed by a single thread hence it
+ * has no synchronization built in, while OSGI ServiceTracker synchronized
+ * access to its data.
+ * <br>2. This class is primarily designed to track multiple services of
+ * different type (class), while OSGI ServiceTracker is designed to work with
+ * single class type, with optional filtering options.
+ * <br>3. This class uses knowledge of DSF sessions to help narrow down
+ * service references.
+ * <br>4. OSGI Service tracker explicitly listens to OSGI service
+ * startup/shutdown events and it will clear a reference to a service as
+ * soon as it's shut down. This class leaves it up to the client to make
+ * sure that it doesn't access a service once that service has been shut down.
+ * <p>
+ * That said, it might be more convenient for certain types of clients to use
+ * OSGI Service tracker for the additional features it provides.
+ *
+ * @see org.osgi.util.tracker.ServiceTracker
+ */
+public class DsfServicesTracker {
+
+ private static String getServiceFilter(String sessionId) {
+ return ("(" + IDsfService.PROP_SESSION_ID + "=" + sessionId + ")").intern(); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
+ }
+
+ private static class ServiceKey
+ {
+ String fClassName;
+ String fFilter;
+ public ServiceKey(Class<?> clazz, String filter) {
+ fClassName = clazz != null ? clazz.getName() : null;
+ fFilter = filter;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ // I guess this doesn't have to assume fFilter can be null, but oh well.
+ return other instanceof ServiceKey &&
+ ((fClassName == null && ((ServiceKey)other).fClassName == null) ||
+ (fClassName != null && fClassName.equals(((ServiceKey)other).fClassName))) &&
+ ((fFilter == null && ((ServiceKey)other).fFilter == null) ||
+ (fFilter != null && fFilter.equals(((ServiceKey)other).fFilter)));
+ }
+
+ @Override
+ public int hashCode() {
+ return (fClassName == null ? 0 : fClassName.hashCode()) + (fFilter == null ? 0 : fFilter.hashCode());
+ }
+ }
+
+ private BundleContext fBundleContext;
+ private Map<ServiceKey,ServiceReference> fServiceReferences = new HashMap<ServiceKey,ServiceReference>();
+ private Map<ServiceReference,Object> fServices = new HashMap<ServiceReference,Object>();
+ private String fServiceFilter;
+
+ /**
+ * Only constructor.
+ * @param bundleContext Context of the plugin that the client lives in.
+ * @param sessionId The DSF session that this tracker will be used for.
+ */
+ public DsfServicesTracker(BundleContext bundleContext, String sessionId) {
+ fBundleContext = bundleContext;
+ fServiceFilter = getServiceFilter(sessionId);
+ }
+
+ /**
+ * Retrieves a service reference for given service class and optional filter.
+ * Filter should be used if there are multiple instances of the desired service
+ * running within the same session.
+ * @param serviceClass class of the desired service
+ * @param custom filter to use when searching for the service, this filter will
+ * be used instead of the standard filter so it should also specify the desired
+ * session-ID
+ * @return OSGI service reference object to the desired service, null if not found
+ */
+ @SuppressWarnings("unchecked")
+ public ServiceReference getServiceReference(Class serviceClass, String filter) {
+ ServiceKey key = new ServiceKey(serviceClass, filter != null ? filter : fServiceFilter);
+ if (fServiceReferences.containsKey(key)) {
+ return fServiceReferences.get(key);
+ }
+
+ try {
+ ServiceReference[] references = fBundleContext.getServiceReferences(key.fClassName, key.fFilter);
+ assert references == null || references.length <= 1;
+ if (references == null || references.length == 0) {
+ return null;
+ } else {
+ fServiceReferences.put(key, references[0]);
+ return references[0];
+ }
+ } catch(InvalidSyntaxException e) {
+ assert false : "Invalid session ID syntax"; //$NON-NLS-1$
+ } catch(IllegalStateException e) {
+ // Can occur when plugin is shutting down.
+ }
+ return null;
+ }
+
+ /**
+ * Convenience class to retrieve a service based on class name only.
+ * @param serviceClass class of the desired service
+ * @return instance of the desired service, null if not found
+ */
+ public <V> V getService(Class<V> serviceClass) {
+ return getService(serviceClass, null);
+ }
+
+ /**
+ * Retrieves the service given service class and optional filter.
+ * Filter should be used if there are multiple instances of the desired service
+ * running within the same session.
+ * @param serviceClass class of the desired service
+ * @param custom filter to use when searching for the service, this filter will
+ * be used instead of the standard filter so it should also specify the desired
+ * session-ID
+ * @return instance of the desired service, null if not found
+ */
+ @SuppressWarnings("unchecked")
+ public <V> V getService(Class<V> serviceClass, String filter) {
+ ServiceReference serviceRef = getServiceReference(serviceClass, filter);
+ if (serviceRef == null) {
+ return null;
+ } else {
+ if (fServices.containsKey(serviceRef)) {
+ return (V)fServices.get(serviceRef);
+ } else {
+ V service = (V)fBundleContext.getService(serviceRef);
+ fServices.put(serviceRef, service);
+ return service;
+ }
+ }
+ }
+
+ /**
+ * Un-gets all the serferences held by this tracker. Must be called
+ * to avoid leaking OSGI service references.
+ */
+ public void dispose() {
+ for (Iterator<ServiceReference> itr = fServices.keySet().iterator(); itr.hasNext();) {
+ fBundleContext.ungetService(itr.next());
+ itr.remove();
+ }
+ }
+
+}
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java
new file mode 100644
index 00000000000..349ae16447e
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/DsfSession.java
@@ -0,0 +1,431 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.service;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfRunnable;
+import org.eclipse.cdt.dsf.concurrent.ThreadSafe;
+import org.eclipse.cdt.dsf.internal.DsfPlugin;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.osgi.framework.Filter;
+
+/**
+ * Class to manage DSF sessions. A DSF session is a way to
+ * associate a set of DSF services that are running simultaneously and
+ * are interacting with each other to provide a complete set of functionality.
+ * <p>
+ * Properties of a session are following:
+ * <br>1. Each session is associated with a single DSF executor, although there
+ * could be multiple sessions using the same executor.
+ * <br>2. Each session has a unique String identifier, which has to be used by
+ * the services belonging to this session when registering with OSGI services.
+ * <br>3. Each session has its set of service event listeners.
+ * <br>4. Start and end of each session is announced by events, which are always
+ * sent on that session's executor dispatch thread.
+ *
+ * @see org.eclipse.cdt.dsf.concurrent.DsfExecutor
+ */
+@ConfinedToDsfExecutor("getExecutor")
+public class DsfSession
+{
+ /**
+ * Listener for session started events. This listener is always going to be
+ * called in the dispatch thread of the session's executor.
+ */
+ public static interface SessionStartedListener {
+ /**
+ * Called when a new session is started. It is always called in the
+ * dispatch thread of the new session.
+ */
+ public void sessionStarted(DsfSession session);
+ }
+
+ /**
+ * Listener for session ended events. This listener is always going to be
+ * called in the dispatch thread of the session's executor.
+ */
+ public static interface SessionEndedListener {
+ /**
+ * Called when a session is ended. It is always called in the
+ * dispatch thread of the session.
+ */
+ public void sessionEnded(DsfSession session);
+ }
+
+ private static int fgSessionIdCounter = 0;
+ private static Set<DsfSession> fgActiveSessions = Collections.synchronizedSet(new HashSet<DsfSession>());
+ private static List<SessionStartedListener> fSessionStartedListeners = Collections.synchronizedList(new ArrayList<SessionStartedListener>());
+ private static List<SessionEndedListener> fSessionEndedListeners = Collections.synchronizedList(new ArrayList<SessionEndedListener>());
+
+ /** Returns true if given session is currently active */
+ public static boolean isSessionActive(String sessionId) {
+ return getSession(sessionId) != null;
+ }
+
+ /** Returns a session instance for given session identifier */
+ @ThreadSafe
+ public static DsfSession getSession(String sessionId) {
+ synchronized(fgActiveSessions) {
+ for (DsfSession session : fgActiveSessions) {
+ if (session.getId().equals(sessionId)) {
+ return session;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Registers a listener for session started events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void addSessionStartedListener(SessionStartedListener listener) {
+ assert !fSessionStartedListeners.contains(listener);
+ fSessionStartedListeners.add(listener);
+ }
+
+ /**
+ * Un-registers a listener for session started events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void removeSessionStartedListener(SessionStartedListener listener) {
+ assert fSessionStartedListeners.contains(listener);
+ fSessionStartedListeners.remove(listener);
+ }
+
+ /**
+ * Registers a listener for session ended events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void addSessionEndedListener(SessionEndedListener listener) {
+ assert !fSessionEndedListeners.contains(listener);
+ fSessionEndedListeners.add(listener);
+ }
+
+ /**
+ * Un-registers a listener for session ended events.
+ * Can be called on any thread.
+ */
+ @ThreadSafe
+ public static void removeSessionEndedListener(SessionEndedListener listener) {
+ assert fSessionEndedListeners.contains(listener);
+ fSessionEndedListeners.remove(listener);
+ }
+
+ /**
+ * Starts and returns a new session instance. This method can be called on any
+ * thread, but the session-started listeners will be called using the session's
+ * executor.
+ * @param executor The DSF executor to use for this session.
+ * @param ownerId ID (plugin ID preferably) of the owner of this session
+ * @return instance object of the new session
+ */
+ @ThreadSafe
+ public static DsfSession startSession(DsfExecutor executor, String ownerId) {
+ synchronized(fgActiveSessions) {
+ final DsfSession newSession = new DsfSession(executor, ownerId, Integer.toString(fgSessionIdCounter++));
+ fgActiveSessions.add(newSession);
+ executor.submit( new DsfRunnable() { public void run() {
+ SessionStartedListener[] listeners = fSessionStartedListeners.toArray(
+ new SessionStartedListener[fSessionStartedListeners.size()]);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].sessionStarted(newSession);
+ }
+ }});
+ return newSession;
+ }
+ }
+
+ /**
+ * Terminates the given session. This method can be also called on any
+ * thread, but the session-ended listeners will be called using the session's
+ * executor.
+ * @param session session to terminate
+ */
+ @ThreadSafe
+ public static void endSession(final DsfSession session) {
+ synchronized(fgActiveSessions) {
+ if (!fgActiveSessions.contains(session)) {
+ throw new IllegalArgumentException();
+ }
+ fgActiveSessions.remove(session);
+ session.getExecutor().submit( new DsfRunnable() { public void run() {
+ SessionEndedListener[] listeners = fSessionEndedListeners.toArray(
+ new SessionEndedListener[fSessionEndedListeners.size()]);
+ for (int i = 0; i < listeners.length; i++) {
+ listeners[i].sessionEnded(session);
+ }
+ }});
+ }
+ }
+
+ private static class ListenerEntry {
+ Object fListener;
+ Filter fFilter;
+
+ ListenerEntry(Object listener, Filter filter) {
+ fListener = listener;
+ fFilter = filter;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof ListenerEntry && fListener.equals(((ListenerEntry)other).fListener);
+ }
+
+ @Override
+ public int hashCode() { return fListener.hashCode(); }
+ }
+
+ /** ID (plugin ID preferably) of the owner of this session */
+ private String fOwnerId;
+
+ /** Session ID of this session. */
+ private String fId;
+
+ /** Dispatch-thread executor for this session */
+ private DsfExecutor fExecutor;
+
+ /** Service start-up counter for this session */
+ private int fServiceInstanceCounter;
+
+ /** Map of registered event listeners. */
+ private Map<ListenerEntry,Method[]> fListeners = new HashMap<ListenerEntry,Method[]>();
+
+ /**
+ * Map of registered adapters, for implementing the
+ * IModelContext.getAdapter() method.
+ * @see org.eclipse.cdt.dsf.datamodel.AbstractDMContext#getAdapter
+ */
+ @SuppressWarnings("unchecked")
+ private Map<Class,Object> fAdapters = Collections.synchronizedMap(new HashMap<Class,Object>());
+
+ /** Returns the owner ID of this session */
+ public String getOwnerId() { return fOwnerId; }
+
+ public boolean isActive() { return DsfSession.isSessionActive(fId); }
+
+ /** Returns the ID of this session */
+ public String getId() { return fId; }
+
+ /** Returns the DSF executor of this session */
+ public DsfExecutor getExecutor() { return fExecutor; }
+
+ /**
+ * Adds a new listener for service events in this session.
+ * @param listener the listener that will receive service events
+ * @param filter optional filter to restrict the services that the
+ * listener will receive events from
+ */
+ public void addServiceEventListener(Object listener, Filter filter) {
+ ListenerEntry entry = new ListenerEntry(listener, filter);
+ assert !fListeners.containsKey(entry);
+ fListeners.put(entry, getEventHandlerMethods(listener));
+ }
+
+ /**
+ * Removes the given listener.
+ * @param listener listener to remove
+ */
+ public void removeServiceEventListener(Object listener) {
+ ListenerEntry entry = new ListenerEntry(listener, null);
+ assert fListeners.containsKey(entry);
+ fListeners.remove(entry);
+ }
+
+ /**
+ * Retrieves and increments the startup counter for services in this session.
+ * DSF services should retrieve this counter when they are initialized,
+ * and should return it through IService.getStartupNumber(). This number is then
+ * used to prioritize service events.
+ * @return current startup counter value
+ */
+ public int getAndIncrementServiceStartupCounter() { return fServiceInstanceCounter++; }
+
+ /**
+ * Dispatches the given event to service event listeners. The event is submitted to
+ * the executor to be dispatched.
+ * @param event to be sent out
+ * @param serviceProperties properties of the service requesting the event to be dispatched
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public void dispatchEvent(final Object event, final Dictionary serviceProperties) {
+ getExecutor().submit(new DsfRunnable() {
+ public void run() { doDispatchEvent(event, serviceProperties);}
+ @Override
+ public String toString() { return "Event: " + event + ", from service " + serviceProperties; } //$NON-NLS-1$ //$NON-NLS-2$
+ });
+ }
+
+ /**
+ * Registers a IModelContext adapter of given type.
+ * @param adapterType class type to register the adapter for
+ * @param adapter adapter instance to register
+ * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public void registerModelAdapter(Class adapterType, Object adapter) {
+ fAdapters.put(adapterType, adapter);
+ }
+
+ /**
+ * Un-registers a IModelContext adapter of given type.
+ * @param adapterType adapter type to unregister
+ * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public void unregisterModelAdapter(Class adapterType) {
+ fAdapters.remove(adapterType);
+ }
+
+ /**
+ * Retrieves an adapter for given type for IModelContext.
+ * @param adapterType adapter type to look fors
+ * @return adapter object for given type, null if none is registered with the session
+ * @see org.eclipse.dsdp.model.AbstractDMContext#getAdapter
+ */
+ @ThreadSafe
+ @SuppressWarnings("unchecked")
+ public Object getModelAdapter(Class adapterType) {
+ return fAdapters.get(adapterType);
+ }
+
+ @Override
+ @ThreadSafe
+ public boolean equals(Object other) {
+ return other instanceof DsfSession && fId.equals(((DsfSession)other).fId);
+ }
+
+ @Override
+ @ThreadSafe
+ public int hashCode() { return fId.hashCode(); }
+
+ @SuppressWarnings("unchecked")
+ private void doDispatchEvent(Object event, Dictionary serviceProperties) {
+ // Build a list of listeners;
+ SortedMap<ListenerEntry,List<Method>> listeners = new TreeMap<ListenerEntry,List<Method>>(new Comparator<ListenerEntry>() {
+ public int compare(ListenerEntry o1, ListenerEntry o2) {
+ if (o1.fListener == o2.fListener) {
+ return 0;
+ } if (o1.fListener instanceof IDsfService && !(o2.fListener instanceof IDsfService)) {
+ return Integer.MIN_VALUE;
+ } else if (o2.fListener instanceof IDsfService && !(o1.fListener instanceof IDsfService)) {
+ return Integer.MAX_VALUE;
+ } else if ( (o1.fListener instanceof IDsfService) && (o2.fListener instanceof IDsfService) ) {
+ return ((IDsfService)o1.fListener).getStartupNumber() - ((IDsfService)o2.fListener).getStartupNumber();
+ }
+ return 1;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this;
+ }
+ });
+
+ // Build a list of listeners and methods that are registered for this event class.
+ Class<?> eventClass = event.getClass();
+ for (Map.Entry<ListenerEntry,Method[]> entry : fListeners.entrySet()) {
+ if (entry.getKey().fFilter != null && !entry.getKey().fFilter.match(serviceProperties)) {
+ // Dispatching service doesn't match the listener's filter, skip it.
+ continue;
+ }
+ Method[] allMethods = entry.getValue();
+ List<Method> matchingMethods = new ArrayList<Method>();
+ for (Method method : allMethods) {
+ assert method.getParameterTypes().length > 0 : eventClass.getName() + "." + method.getName() //$NON-NLS-1$
+ + " signature contains zero parameters"; //$NON-NLS-1$
+ if ( method.getParameterTypes()[0].isAssignableFrom(eventClass) ) {
+ matchingMethods.add(method);
+ }
+ }
+ if (!matchingMethods.isEmpty()) {
+ listeners.put(entry.getKey(), matchingMethods);
+ }
+ }
+
+ // Call the listeners
+ for (Map.Entry<ListenerEntry,List<Method>> entry : listeners.entrySet()) {
+ for (Method method : entry.getValue()) {
+ try {
+ method.invoke(entry.getKey().fListener, new Object[] { event } );
+ }
+ catch (IllegalAccessException e) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Security exception when calling a service event handler method", e)); //$NON-NLS-1$
+ assert false : "IServiceEventListener.ServiceHandlerMethod method not accessible, is listener declared public?"; //$NON-NLS-1$
+ }
+ catch (InvocationTargetException e) {
+ DsfPlugin.getDefault().getLog().log(new Status(
+ IStatus.ERROR, DsfPlugin.PLUGIN_ID, -1, "Invocation exception when calling a service event handler method", e)); //$NON-NLS-1$
+ assert false : "Exception thrown by a IServiceEventListener.ServiceHandlerMethod method"; //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ private Method[] getEventHandlerMethods(Object listener)
+ {
+ List<Method> retVal = new ArrayList<Method>();
+ try {
+ Method[] methods = listener.getClass().getMethods();
+ for (Method method : methods) {
+ if (method.isAnnotationPresent(DsfServiceEventHandler.class)) {
+ Class<?>[] paramTypes = method.getParameterTypes();
+ if (paramTypes.length > 2) {
+ throw new IllegalArgumentException("ServiceEventHandler method has incorrect number of parameters"); //$NON-NLS-1$
+ }
+ retVal.add(method);
+ }
+ }
+ } catch(SecurityException e) {
+ throw new IllegalArgumentException("No permission to access ServiceEventHandler method"); //$NON-NLS-1$
+ }
+
+ if (retVal.isEmpty()) {
+ throw new IllegalArgumentException("No methods marked with @ServiceEventHandler in listener, is listener declared public?"); //$NON-NLS-1$
+ }
+ return retVal.toArray(new Method[retVal.size()]);
+ }
+
+ /**
+ * Class to be instanciated only using startSession()
+ */
+ @ThreadSafe
+ private DsfSession(DsfExecutor executor, String ownerId, String id) {
+ fId = id;
+ fOwnerId = ownerId;
+ fExecutor = executor;
+ }
+
+} \ No newline at end of file
diff --git a/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java
new file mode 100644
index 00000000000..f0181ea115b
--- /dev/null
+++ b/dsf/org.eclipse.cdt.dsf/src/org/eclipse/cdt/dsf/service/IDsfService.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 2008 Wind River Systems 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:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.dsf.service;
+
+import java.util.Dictionary;
+
+import org.eclipse.cdt.dsf.concurrent.ConfinedToDsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.DsfExecutor;
+import org.eclipse.cdt.dsf.concurrent.RequestMonitor;
+
+/**
+ * The inteface that all DSF services must implement. It only privides a
+ * few features to help manage and identify the servies using the OSGI services
+ * framework.
+ * <p>
+ * Each service should register itself with OSGI services framework using
+ * the BundleContext.registerService() method. And each service should use the
+ * session ID that it is registering with as one of the service properties. If there
+ * is more than one instance of the service to be instanciated for a given session,
+ * additional properties should be used when registering the service to allow clients
+ * to uniquely identify the services.
+ * <p>
+ * By convention, all methods of DSF services can be called only on the dispatch
+ * thread of the DSF executor that is associated with the service. If a
+ * service exposes a method that is to be called on non-dispatch thread, it should
+ * be documented so.
+ *
+ * @see org.osgi.framework.BundleContext#registerService(String[], Object, Dictionary)
+ */
+@ConfinedToDsfExecutor("getExecutor")
+public interface IDsfService {
+
+ /**
+ * Property name for the session-id of this service. This property should be set by
+ * all DSF services when they are registered with OSGI service framework.
+ */
+ final static String PROP_SESSION_ID = "org.eclipse.cdt.dsf.service.IService.session_id"; //$NON-NLS-1$
+
+ /**
+ * Returns the DSF Session that this service belongs to.
+ */
+ DsfSession getSession();
+
+ /**
+ * Returns the executor that should be used to call methods of this service.
+ * This method is equivalent to calling getSession().getExecutor()
+ */
+ DsfExecutor getExecutor();
+
+ /**
+ * Returns the map of properties that this service was registered with.
+ */
+ @SuppressWarnings("unchecked")
+ Dictionary getProperties();
+
+ /**
+ * Returns a filter string that can be used to uniquely identify this
+ * service. This filter string should be based on the properties and class
+ * name, which were used to register this service.
+ * @see org.osgi.framework.BundleContext#getServiceReferences
+ */
+ String getServiceFilter();
+
+ /**
+ * Performs initialization and registration of the given service. Implementation
+ * should initialize the service, so that all methods and events belonging to this
+ * service can be used following the initialization.
+ * <br>Note: Since service initializaiton should be performed by an external
+ * logic, if this service depends on other services, the implementaion should
+ * assume that these services are already present, and if they are not, the
+ * initializaiton should fail.
+ * @param requestMonitor callback to be submitted when the initialization is complete
+ */
+ void initialize(RequestMonitor requestMonitor);
+
+ /**
+ * Performs shutdown and de-registration of the given service.
+ * @param requestMonitor callback to be submitted when shutdown is complete
+ */
+ void shutdown(RequestMonitor requestMonitor);
+
+ /**
+ * Returns the startup order number of this service among services in the same session.
+ * Implementations should get this number during initialization by calling
+ * Session.getAndIncrementServiceStartupCounter(). This counter is used to Session
+ * objects to prioritize the listeners of service events.
+ * @return startup order number of this service
+ * @see org.eclipse.cdt.dsf.service.DsfSession#getAndIncrementServiceStartupCounter()
+ */
+ int getStartupNumber();
+}

Back to the top