diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java
index 1ba4920289c..99ec56d2a9c 100644
--- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java
+++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractContainerVMNode.java
@@ -12,19 +12,21 @@ package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch;
 
 import java.util.concurrent.RejectedExecutionException;
 
+import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
 import org.eclipse.dd.dsf.concurrent.DsfRunnable;
 import org.eclipse.dd.dsf.concurrent.RequestMonitor;
 import org.eclipse.dd.dsf.datamodel.DMContexts;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
 import org.eclipse.dd.dsf.datamodel.IDMEvent;
 import org.eclipse.dd.dsf.debug.service.IRunControl;
 import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
 import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerResumedDMEvent;
 import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerSuspendedDMEvent;
-import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
 import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent;
 import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent;
 import org.eclipse.dd.dsf.debug.service.StepQueueManager.ISteppingTimedOutEvent;
 import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.viewmodel.IVMContext;
 import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
 import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
 import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
@@ -40,14 +42,16 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
 public abstract class AbstractContainerVMNode extends AbstractDMVMNode implements IElementLabelProvider {
 
 	public AbstractContainerVMNode(AbstractDMVMProvider provider, DsfSession session) {
-		super(provider, session, IRunControl.IExecutionDMContext.class);
+		super(provider, session, IRunControl.IContainerDMContext.class);
 	}
 
 	public void update(final ILabelUpdate[] updates) {
 	    try {
 	        getSession().getExecutor().execute(new DsfRunnable() {
 	            public void run() {
-	                updateLabelInSessionThread(updates);
+	                for (final ILabelUpdate update : updates) {
+	                    updateLabelInSessionThread(update);
+	                }
 	            }});
 	    } catch (RejectedExecutionException e) {
 	        for (ILabelUpdate update : updates) {
@@ -62,26 +66,36 @@ public abstract class AbstractContainerVMNode extends AbstractDMVMNode implement
      * @param updates  the pending label updates
      * @see {@link #update(ILabelUpdate[])
      */
-	protected abstract void updateLabelInSessionThread(ILabelUpdate[] updates);
+	protected abstract void updateLabelInSessionThread(ILabelUpdate update);
 
+    @Override
+    public void getContextsForEvent(VMDelta parentDelta, Object e, final DataRequestMonitor<IVMContext[]> rm) {
+        super.getContextsForEvent(parentDelta, e, rm);
+    }
+            
 	public int getDeltaFlags(Object e) {
-        if (e instanceof IContainerResumedDMEvent && 
-            ((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) 
-        {
-            return IModelDelta.CONTENT;            
+        IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+
+	    if (e instanceof IContainerResumedDMEvent) {
+            if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) 
+            {
+                return IModelDelta.CONTENT;
+            }
         } else if (e instanceof IContainerSuspendedDMEvent) {
-        	// no change, update happens on FullStackRefreshEvent
             return IModelDelta.NO_CHANGE;
         } else if (e instanceof FullStackRefreshEvent) {
-        	return IModelDelta.CONTENT;
-	    } else if (e instanceof ISteppingTimedOutEvent &&
-                   ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext)
-	    {
-           return IModelDelta.CONTENT;            
+            if (dmc instanceof IContainerDMContext) {
+                return IModelDelta.CONTENT;
+            }
+	    } else if (e instanceof ISteppingTimedOutEvent) {
+	        if (dmc instanceof IContainerDMContext) 
+	        {
+	            return IModelDelta.CONTENT;
+	        }
 	    } else if (e instanceof IExitedDMEvent) {
 	        return IModelDelta.CONTENT;
 	    } else if (e instanceof IStartedDMEvent) {
-	    	if (((IStartedDMEvent) e).getDMContext() instanceof IContainerDMContext) {
+	    	if (dmc instanceof IContainerDMContext) {
 	    		return IModelDelta.EXPAND | IModelDelta.SELECT;
 	    	} else {
 		        return IModelDelta.CONTENT;
@@ -91,37 +105,63 @@ public abstract class AbstractContainerVMNode extends AbstractDMVMNode implement
 	}
 
 	public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor requestMonitor) {
-		if(e instanceof IContainerResumedDMEvent &&
-           ((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) 
-		{
-	        parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
+	    IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+	    
+		if(e instanceof IContainerResumedDMEvent) {
+            // Container resumed: 
+		    // - If not stepping, update the container and the execution 
+		    // contexts under it.  
+		    // - If stepping, do nothing to avoid too many updates.  If a 
+		    // time-out is reached before the step completes, the 
+		    // ISteppingTimedOutEvent will trigger a full refresh.
+		    if (((IContainerResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) 
+		    {
+    	        parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
+		    } 
 		} else if (e instanceof IContainerSuspendedDMEvent) {
-        	// do nothing
+            // Container suspended.  Do nothing here to give the stack the 
+		    // priority in updating. The container and threads will update as 
+		    // a result of FullStackRefreshEvent. 
 		} else if (e instanceof FullStackRefreshEvent) {
-			parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
-		} else if (e instanceof ISteppingTimedOutEvent &&
-                   ((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext)
-		{
-            parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
-            // Workaround for bug 233730: we need to add a separate delta node for the state flag in 
-            // order to trigger an update of the run control actions.
-            parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE);
+		    // Full-stack refresh event is generated following a suspended event 
+		    // and a fixed delay.  If the suspended event was generated for the 
+		    // container refresh the whole container.
+		    if (dmc instanceof IContainerDMContext) {
+		        parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+		    }
+		} else if (e instanceof ISteppingTimedOutEvent) {
+		    // Stepping time-out indicates that a step operation is taking 
+		    // a long time, and the view needs to be refreshed to show 
+		    // the user that the program is running.
+		    // If the step was issued for the whole container refresh
+		    // the whole container.
+		    if (dmc instanceof IContainerDMContext) {
+	            parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+		    }
 		} else if (e instanceof IExitedDMEvent) {
-	    	IExecutionDMContext exeContext= ((IExitedDMEvent) e).getDMContext();
-			if (exeContext instanceof IContainerDMContext) {
+		    // An exited event could either be for a thread within a container
+		    // or for the container itself.  
+		    // If a container exited, refresh the parent element so that the 
+		    // container may be removed.
+		    // If a thread exited within a container, refresh that container.
+			if (dmc instanceof IContainerDMContext) {
 	    		parentDelta.setFlags(parentDelta.getFlags() |  IModelDelta.CONTENT);
 	    	} else {
-		        IContainerDMContext containerCtx = DMContexts.getAncestorOfType(exeContext, IContainerDMContext.class);
+		        IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class);
 		        if (containerCtx != null) {
 		            parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT);
 		        }
 	    	}
 	    } else if (e instanceof IStartedDMEvent) {
-	    	IExecutionDMContext exeContext= ((IStartedDMEvent) e).getDMContext();
-			if (exeContext instanceof IContainerDMContext) {
-		        parentDelta.addNode(createVMContext(exeContext), IModelDelta.EXPAND | IModelDelta.SELECT);
+            // A started event could either be for a thread within a container
+            // or for the container itself.  
+            // If a container started, issue an expand and select event to 
+	        // show the threads in the new container. 
+	        // Note: the EXPAND flag implies refreshing the parent element.
+			if (dmc instanceof IContainerDMContext) {
+		        parentDelta.addNode(createVMContext(dmc), IModelDelta.EXPAND | IModelDelta.SELECT);
 			} else {
-				IContainerDMContext containerCtx = DMContexts.getAncestorOfType(exeContext, IContainerDMContext.class);
+				IContainerDMContext containerCtx = DMContexts.getAncestorOfType(dmc, IContainerDMContext.class);
 				if (containerCtx != null) {
 					parentDelta.addNode(createVMContext(containerCtx), IModelDelta.CONTENT);
 				}
diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractLaunchVMProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractLaunchVMProvider.java
new file mode 100644
index 00000000000..da4bdbe3d13
--- /dev/null
+++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractLaunchVMProvider.java
@@ -0,0 +1,206 @@
+/*******************************************************************************
+ * 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 new functionality	
+ *******************************************************************************/
+package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.dd.dsf.concurrent.DsfRunnable;
+import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.concurrent.ThreadSafe;
+import org.eclipse.dd.dsf.datamodel.DMContexts;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.datamodel.IDMEvent;
+import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent;
+import org.eclipse.dd.dsf.debug.service.IRunControl;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
+import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
+import org.eclipse.dd.dsf.ui.viewmodel.IVMModelProxy;
+import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchesListener2;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
+
+
+/**
+ * 
+ */
+@SuppressWarnings("restriction")
+public class AbstractLaunchVMProvider extends AbstractDMVMProvider 
+    implements IDebugEventSetListener, ILaunchesListener2
+{
+    /**
+	 * Delay (in milliseconds) before a full stack trace will be requested.
+	 */
+	private static final int FRAME_UPDATE_DELAY= 200;
+	
+    private final Map<IExecutionDMContext,ScheduledFuture<?>> fRefreshStackFramesFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
+
+	@ThreadSafe
+    public AbstractLaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session)
+    {
+        super(adapter, presentationContext, session);
+    }
+    
+    @Override
+	protected IVMUpdatePolicy[] createUpdateModes() {
+		return new IVMUpdatePolicy[] { new DelayedStackRefreshUpdatePolicy() };
+    }
+    
+    public void handleDebugEvents(final DebugEvent[] events) {
+        if (isDisposed()) return;
+        
+        // We're in session's executor thread.  Re-dispach to VM Adapter 
+        // executor thread and then call root layout node.
+        try {
+            getExecutor().execute(new Runnable() {
+                public void run() {
+                    if (isDisposed()) return;
+    
+                    for (final DebugEvent event : events) {
+                        handleEvent(event);
+                    }
+                }});
+        } catch (RejectedExecutionException e) {
+            // Ignore.  This exception could be thrown if the provider is being 
+            // shut down.  
+        }
+    }
+
+    @Override
+    protected void handleEvent(IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) {
+    	super.handleEvent(proxyStrategy, event, rm);
+    	
+		if (event instanceof IRunControl.ISuspendedDMEvent) {
+    		final IExecutionDMContext exeContext= ((IRunControl.ISuspendedDMEvent) event).getDMContext();
+    		ScheduledFuture<?> refreshStackFramesFuture = getRefreshFuture(exeContext);
+    		// trigger delayed full stack frame update
+    		if (refreshStackFramesFuture != null) {
+    			// cancel previously scheduled frame update
+    			refreshStackFramesFuture.cancel(false);
+    		}
+
+    		refreshStackFramesFuture = getSession().getExecutor().schedule(
+	            new DsfRunnable() { 
+	                public void run() {
+	                    if (getSession().isActive()) {
+	                        getExecutor().execute(new Runnable() {
+	                            public void run() {
+	                                // trigger full stack frame update
+	                                ScheduledFuture<?> future= fRefreshStackFramesFutures.get(exeContext);
+	                                if (future != null && !isDisposed()) {
+	                                    fRefreshStackFramesFutures.remove(exeContext);
+	                                    handleEvent(new FullStackRefreshEvent(exeContext));
+	                                }
+	                            }});
+	                    }
+	                }
+	            },
+			    FRAME_UPDATE_DELAY, TimeUnit.MILLISECONDS);
+			fRefreshStackFramesFutures.put(exeContext, refreshStackFramesFuture);
+    	} else if (event instanceof IRunControl.IResumedDMEvent) {
+    		IExecutionDMContext exeContext= ((IRunControl.IResumedDMEvent) event).getDMContext();
+    		ScheduledFuture<?> refreshStackFramesFuture= fRefreshStackFramesFutures.get(exeContext);
+    		if (refreshStackFramesFuture != null) {
+    			// cancel previously scheduled frame update
+    			refreshStackFramesFuture.cancel(false);
+    			fRefreshStackFramesFutures.remove(exeContext);
+    		}
+    	}
+    }
+
+    /**
+     * Returns the future for the given execution context or for any child of the 
+     * given execution context.
+     */
+    private ScheduledFuture<?> getRefreshFuture(IExecutionDMContext execCtx) {
+        for (IExecutionDMContext refreshCtx : fRefreshStackFramesFutures.keySet()) {
+            if (refreshCtx.equals(execCtx) || DMContexts.isAncestorOf(refreshCtx, execCtx)) {
+                return fRefreshStackFramesFutures.remove(refreshCtx);
+            }
+        }
+        return null;
+    }
+    
+    @Override
+    public void dispose() {
+        DebugPlugin.getDefault().removeDebugEventListener(this);
+        DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
+        super.dispose();
+    }
+    
+    public void launchesAdded(ILaunch[] launches) {
+        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); 
+    }
+    
+    public void launchesRemoved(ILaunch[] launches) {
+        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); 
+    }
+    
+    public void launchesChanged(ILaunch[] launches) {
+        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); 
+    }
+    
+    public void launchesTerminated(ILaunch[] launches) {
+        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); 
+    }
+    
+    private void handleLaunchesEvent(final LaunchesEvent event) {
+        if (isDisposed()) return;
+        
+        // We're in session's executor thread.  Re-dispach to VM Adapter 
+        // executor thread and then call root layout node.
+        try {
+            getExecutor().execute(new Runnable() {
+                public void run() {
+                    if (isDisposed()) return;
+    
+                    IRootVMNode rootLayoutNode = getRootVMNode();
+                    if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
+                        handleEvent(event);
+                    }
+                }});
+        } catch (RejectedExecutionException e) {
+            // Ignore.  This exception could be thrown if the provider is being 
+            // shut down.  
+        }
+    }
+    
+    @Override
+    protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
+        // To optimize view performance when stepping rapidly, skip events that came 
+        // before the last suspended events.  However, the debug view can get suspended
+        // events for different threads, so make sure to skip only the events if they
+        // were in the same hierarchy as the last suspended event.
+        if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent<?>) {
+            IDMContext newEventDmc = ((IDMEvent<?>)newEvent).getDMContext();
+            IDMContext eventToSkipDmc = ((IDMEvent<?>)eventToSkip).getDMContext();
+            
+            if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+}
diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java
index b111973f084..f373511226b 100644
--- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java
+++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/launch/AbstractThreadVMNode.java
@@ -21,6 +21,7 @@ import org.eclipse.dd.dsf.concurrent.DsfRunnable;
 import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
 import org.eclipse.dd.dsf.concurrent.RequestMonitor;
 import org.eclipse.dd.dsf.datamodel.DMContexts;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
 import org.eclipse.dd.dsf.datamodel.IDMEvent;
 import org.eclipse.dd.dsf.debug.service.IRunControl;
 import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
@@ -219,24 +220,19 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode
     
     
     public int getDeltaFlags(Object e) {
-        if (e instanceof IContainerResumedDMEvent || e instanceof IContainerSuspendedDMEvent) {
-            // No need to react to container events, because the container 
-            // nodes will deal with them. We need this if statement however, 
-            // because the these events extend IResumedDMEvent and 
-            // ISuspendedDMEvent and would trigger the if statement below.
+        IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+
+        if (dmc instanceof IContainerDMContext) {
             return IModelDelta.NO_CHANGE;
         } else if (e instanceof IResumedDMEvent && 
                    ((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) 
         {
             return IModelDelta.CONTENT;            
         } else if (e instanceof ISuspendedDMEvent) {
-        	// no change, update happens on FullStackRefreshEvent
             return IModelDelta.NO_CHANGE;
         } else if (e instanceof FullStackRefreshEvent) {
             return IModelDelta.CONTENT;
-        } else if (e instanceof ISteppingTimedOutEvent && 
-                 !(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) ) 
-        {
+        } else if (e instanceof ISteppingTimedOutEvent) {
             return IModelDelta.CONTENT;            
         } else if (e instanceof ModelProxyInstalledEvent) {
             return IModelDelta.SELECT | IModelDelta.EXPAND;
@@ -245,32 +241,51 @@ public abstract class AbstractThreadVMNode extends AbstractDMVMNode
     }
 
     public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
-        if(e instanceof IContainerResumedDMEvent || e instanceof IContainerSuspendedDMEvent) {
-            // No need to react to container events, because the container 
-            // nodes will deal with them. We need this if statement however, 
-            // because the these events extend IResumedDMEvent and 
-            // ISuspendedDMEvent and would trigger the if statement below.
-            rm.done();
-        } else if(e instanceof IResumedDMEvent && 
-                  ((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) 
-        {
-            parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
+        IDMContext dmc = e instanceof IDMEvent<?> ? ((IDMEvent<?>)e).getDMContext() : null;
+
+        if(dmc instanceof IContainerDMContext) {
+            // The IContainerDMContext sub-classes IExecutionDMContext.
+            // Also IContainerResumedDMEvent sub-classes IResumedDMEvent and
+            // IContainerSuspendedDMEvnet sub-classes ISuspendedEvent.
+            // Because of this relationship, the thread VM node can be called
+            // with data-model evnets for the containers.  This statement
+            // filters out those event.
             rm.done();
+        } else if(e instanceof IResumedDMEvent) {
+            // Resumed: 
+            // - If not stepping, update the thread and its content (its stack).
+            // - If stepping, do nothing to avoid too many updates.  If a 
+            // time-out is reached before the step completes, the 
+            // ISteppingTimedOutEvent will trigger a refresh.
+            if (((IResumedDMEvent)e).getReason() != IRunControl.StateChangeReason.STEP) {
+                parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
+                rm.done();
+            }
         } else if (e instanceof ISuspendedDMEvent) {
-        	// no change
+            // Container suspended.  Do nothing here to give the stack the 
+            // priority in updating. The thread will update as a result of 
+            // FullStackRefreshEvent. 
         	rm.done();
         } else if (e instanceof FullStackRefreshEvent) {
-            parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
+            // Full-stack refresh event is generated following a suspended event 
+            // and a fixed delay.  Refresh the whole thread upon this event.
+            parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
             rm.done();
-        } else if (e instanceof ISteppingTimedOutEvent && 
-            !(((ISteppingTimedOutEvent)e).getDMContext() instanceof IContainerDMContext) ) 
-        {
-            parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.CONTENT);
-            // Workaround for bug 233730: we need to add a separate delta node for the state flag in 
-            // order to trigger an update of the run control actions.
-            parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE);
+        } else if (e instanceof ISteppingTimedOutEvent) {
+            // Stepping time-out indicates that a step operation is taking 
+            // a long time, and the view needs to be refreshed to show 
+            // the user that the program is running.  
+            parentDelta.addNode(createVMContext(dmc), IModelDelta.CONTENT);
             rm.done();            
         } else if (e instanceof ModelProxyInstalledEvent) {
+            // Model Proxy install event is generated when the model is first 
+            // populated into the view.  This happens when a new debug session
+            // is started or when the view is first opened.  
+            // In both cases, if there are already threads in the debug model, 
+            // the desired user behavior is to show the threads and to select
+            // the first thread.  
+            // If the thread is suspended, do not select the thread, instead, 
+            // its top stack frame will be selected.
             getThreadVMCForModelProxyInstallEvent(
                 parentDelta,
                 new DataRequestMonitor<VMContextInfo>(getExecutor(), rm) {
diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java
index cbfb60c4f75..85abf87d21f 100644
--- a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/actions/PDATerminateCommand.java
@@ -22,7 +22,7 @@ import org.eclipse.dd.dsf.service.DsfServicesTracker;
 import org.eclipse.dd.dsf.service.DsfSession;
 import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext;
 import org.eclipse.dd.examples.pda.service.PDACommandControl;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 import org.eclipse.dd.examples.pda.ui.PDAUIPlugin;
 import org.eclipse.debug.core.commands.IDebugCommandRequest;
 import org.eclipse.debug.core.commands.IEnabledStateRequest;
@@ -64,7 +64,7 @@ public class PDATerminateCommand implements ITerminateHandler {
         // Find the PDA program context in the selected element.  If one is not found, 
         // the action should be disabled.
         IDMVMContext vmc = (IDMVMContext)request.getElements()[0];
-        final PDAProgramDMContext pdaProgramCtx = DMContexts.getAncestorOfType(vmc.getDMContext(), PDAProgramDMContext.class);
+        final PDAVirtualMachineDMContext pdaProgramCtx = DMContexts.getAncestorOfType(vmc.getDMContext(), PDAVirtualMachineDMContext.class);
         if (pdaProgramCtx == null) {
             request.setEnabled(false);
             request.done();
diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java
index 7a691225bc5..5d269524432 100644
--- a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java
+++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDALaunchVMProvider.java
@@ -11,39 +11,35 @@
  *******************************************************************************/
 package org.eclipse.dd.examples.pda.ui.viewmodel.launch;
 
-import java.util.concurrent.RejectedExecutionException;
-
 import org.eclipse.dd.dsf.concurrent.ThreadSafe;
+import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractLaunchVMProvider;
 import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode;
 import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode;
 import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode;
-import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent;
 import org.eclipse.dd.dsf.service.DsfSession;
 import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
 import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
 import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
-import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
-import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.IDebugEventSetListener;
-import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchesListener2;
 import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
 
 
 /**
- * View Model provider for the Launch (AKA Debug) view.  The PDA debugger is 
- * single-threaded, so there is no need for a debug target element to be visible
- * in the debug view.  Therefore the launch VM provider is configured with three nodes:
+ * View Model provider for the Launch (AKA Debug) view. The launch VM 
+ * provider is configured with three nodes:
  * <ul>
  * <li> LaunchRootVMNode - This is the root of the PDA view model.</li>  
- * <li> ThreadVMNode - Supplies the PDA program element.</li>  
+ * <li> PDAVirtualMachineVMNode - Supplies the element representing PDA VM</li>
+ * <li> PDAThreadsVMNode - Supplies the PDA thread elements</li>
  * <li> StackFramesVMNode - Supplies the stack frame elements.</li>  
- * <li> StandardProcessVMNode - Supplies elements representing the PDA debugger process.</li>
+ * <li> StandardProcessVMNode - Supplies elements representing the PDA 
+ * debugger process.</li>
  * </ul> 
  */
 @SuppressWarnings("restriction")
-public class PDALaunchVMProvider extends AbstractDMVMProvider 
+public class PDALaunchVMProvider extends AbstractLaunchVMProvider 
     implements IDebugEventSetListener, ILaunchesListener2
 {
     @ThreadSafe
@@ -55,82 +51,21 @@ public class PDALaunchVMProvider extends AbstractDMVMProvider
         setRootNode(launchNode);
 
         // Launch node is a parent to the processes and program nodes.
-        IVMNode pdaProgramNode = new PDAProgramVMNode(this, getSession());
+        IVMNode pdaVirtualMachineNode = new PDAVirtualMachineVMNode(this, getSession());
         IVMNode processesNode = new StandardProcessVMNode(this);
-        addChildNodes(launchNode, new IVMNode[] { pdaProgramNode, processesNode});
+        addChildNodes(launchNode, new IVMNode[] { pdaVirtualMachineNode, processesNode});
         
-        // Stack frames node is under the PDA program node.
+        // Virtual machine node is under the PDA threads node.
+        IVMNode threadsNode = new PDAThreadsVMNode(this, getSession());
+        addChildNodes(pdaVirtualMachineNode, new IVMNode[] { threadsNode });
+        
+        // Stack frames node is under the PDA threads node.
         IVMNode stackFramesNode = new StackFramesVMNode(this, getSession());
-        addChildNodes(pdaProgramNode, new IVMNode[] { stackFramesNode });
+        addChildNodes(threadsNode, new IVMNode[] { stackFramesNode });
 
         // Register the LaunchVM provider as a listener to debug and launch 
         // events.  These events are used by the launch and processes nodes.
         DebugPlugin.getDefault().addDebugEventListener(this);
         DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
     }
-    
-    
-    public void handleDebugEvents(final DebugEvent[] events) {
-        if (isDisposed()) return;
-        
-        // This method may be called on any thread.  Switch to the 
-        // view model executor thread before processing.
-        try {
-            getExecutor().execute(new Runnable() {
-                public void run() {
-                    if (isDisposed()) return;
-    
-                    for (final DebugEvent event : events) {
-                        handleEvent(event);
-                    }
-                }});
-        } catch (RejectedExecutionException e) {
-            // Ignore.  This exception could be thrown if the view model is being 
-            // shut down.  
-        }
-    }
-
-    @Override
-    public void dispose() {
-        DebugPlugin.getDefault().removeDebugEventListener(this);
-        DebugPlugin.getDefault().getLaunchManager().removeLaunchListener(this);
-        super.dispose();
-    }
-    
-    public void launchesAdded(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); 
-    }
-    
-    public void launchesRemoved(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); 
-    }
-    
-    public void launchesChanged(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); 
-    }
-    
-    public void launchesTerminated(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); 
-    }
-    
-    private void handleLaunchesEvent(final LaunchesEvent event) {
-        if (isDisposed()) return;
-        
-        // This method also may be called on any thread.  Switch to the 
-        // view model executor thread before processing.
-        try {
-            getExecutor().execute(new Runnable() {
-                public void run() {
-                    if (isDisposed()) return;
-    
-                    IRootVMNode rootLayoutNode = getRootVMNode();
-                    if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
-                        handleEvent(event);
-                    }
-                }});
-        } catch (RejectedExecutionException e) {
-            // Ignore.  This exception could be thrown if the view model is being 
-            // shut down.  
-        }
-    }
 }
diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAProgramVMNode.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAProgramVMNode.java
deleted file mode 100644
index e8fe38e0334..00000000000
--- a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAProgramVMNode.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*******************************************************************************
- * 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 multi threaded functionality	
- *******************************************************************************/
-package org.eclipse.dd.examples.pda.ui.viewmodel.launch;
-
-import java.util.concurrent.RejectedExecutionException;
-
-import org.eclipse.core.runtime.CoreException;
-import org.eclipse.dd.dsf.concurrent.ConfinedToDsfExecutor;
-import org.eclipse.dd.dsf.concurrent.DsfRunnable;
-import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
-import org.eclipse.dd.dsf.concurrent.RequestMonitor;
-import org.eclipse.dd.dsf.datamodel.IDMContext;
-import org.eclipse.dd.dsf.datamodel.IDMEvent;
-import org.eclipse.dd.dsf.debug.service.IRunControl;
-import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
-import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData;
-import org.eclipse.dd.dsf.debug.service.IRunControl.IResumedDMEvent;
-import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
-import org.eclipse.dd.dsf.service.DsfSession;
-import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
-import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMContext;
-import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
-import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
-import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMNode;
-import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
-import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext;
-import org.eclipse.dd.examples.pda.PDAPlugin;
-import org.eclipse.dd.examples.pda.launch.PDALaunch;
-import org.eclipse.dd.examples.pda.service.PDACommandControl;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
-import org.eclipse.dd.examples.pda.service.PDAStartedEvent;
-import org.eclipse.debug.core.ILaunch;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IHasChildrenUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
-import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdate;
-import org.eclipse.debug.ui.DebugUITools;
-import org.eclipse.debug.ui.IDebugUIConstants;
-import org.eclipse.jface.viewers.TreePath;
-import org.eclipse.ui.IMemento;
-
-/**
- * View Model node representing a PDA program. 
- */
-@SuppressWarnings("restriction")
-public class PDAProgramVMNode extends AbstractDMVMNode 
-    implements IElementLabelProvider, IElementMementoProvider
-{
-    // View model context representing a terminated PDA program.
-    // It's purpose is to show a terminated program in the debug view
-    // even after the DSF session is terminated.
-    // 
-    // Note: this context does not implement the IDMVMContext
-    // interfaces, as it does not use an IDMContext as its root.
-    // 
-    // To implement comparison methods, this contexts uses the
-    // VM node object, such that two terminated program contexts
-    // from the same instance of VM node will be equal. 
-    private static class TerminatedProgramVMContext extends AbstractVMContext {
-        TerminatedProgramVMContext(IVMNode node) {
-            super(node);
-        }
-        
-        @Override
-        public boolean equals(Object obj) {
-            if (obj instanceof TerminatedProgramVMContext) {
-                TerminatedProgramVMContext context = (TerminatedProgramVMContext)obj;
-                return getVMNode().equals(context.getVMNode());
-            }
-            return false;
-        }
-        
-        @Override
-        public int hashCode() {
-            return getVMNode().hashCode();
-        }
-    }
-    
-    public PDAProgramVMNode(AbstractDMVMProvider provider, DsfSession session) {
-        super(provider, session, IExecutionDMContext.class);
-    }
-
-    @Override
-    public void update(IHasChildrenUpdate[] updates) {
-        for (IHasChildrenUpdate update : updates) {
-            // Check if the launch is initialized.  PDA program element should 
-            // be shown only if the launch has completed initializing.
-            PDALaunch launch = findLaunchInPath(update.getElementPath());
-            update.setHasChilren(launch != null && launch.isInitialized());
-            update.done();
-        }        
-    }
-
-    @Override
-    public void update(IChildrenCountUpdate[] updates) {
-        for (IChildrenCountUpdate update : updates) {
-            // Check if the launch is initialized.  PDA program element should 
-            // be shown only if the launch has completed initializing.
-            PDALaunch launch = findLaunchInPath(update.getElementPath());
-            if (launch != null && launch.isInitialized()) {
-                update.setChildCount(1);
-            } else {
-                update.setChildCount(0);
-            }
-            update.done();
-        }        
-    }
-
-    @Override
-    public void update(IChildrenUpdate[] updates) {
-        for (IChildrenUpdate update : updates) {
-            PDALaunch launch = findLaunchInPath(update.getElementPath());
-            if (launch != null && launch.isInitialized() && launch.isShutDown()) {
-                // If the debug session has been shut down, add a dummy 
-                // VM context representing the PDA thread.
-                update.setChild(new TerminatedProgramVMContext(this), 0);
-                update.done();
-            } else {
-                super.update(new IChildrenUpdate[] { update });
-            }
-        }
-    }
-    
-    @Override
-    protected void updateElementsInSessionThread(final IChildrenUpdate update) {
-    	// Get the instance of the service.  Note that there is no race condition
-    	// in getting the service since this method is called only in the 
-    	// service executor thread.
-        final PDACommandControl commandControl = getServicesTracker().getService(PDACommandControl.class);
-
-        // Check if the service is available.  If it is not, no elements are 
-        // updated.
-        if (commandControl == null) {
-            handleFailedUpdate(update);
-            return;
-        }
-        
-        update.setChild(createVMContext(commandControl.getProgramDMContext()), 0);
-        update.done();
-    }
-
-    public void update(final ILabelUpdate[] updates) {
-        for (final ILabelUpdate update : updates) {
-            if (update.getElement() instanceof TerminatedProgramVMContext) {
-                // If the element is a terminated program, update the label 
-                // in the View Model thread.
-                updateTerminatedThreadLabel(update);
-            } else {
-                // If the element is the PDA Program context, try to switch
-                // to the DSF session thread before updating the label.
-                try {
-                    getSession().getExecutor().execute(new DsfRunnable() {
-                        public void run() {
-                            updateProgramLabelInSessionThread(update);
-                        }});
-                } catch (RejectedExecutionException e) {
-                    // Acceptable race condition: DSF session terminated.
-                    handleFailedUpdate(update);
-                }
-            }
-        }
-    }
-    
-    @ConfinedToDsfExecutor("getSession().getExecutor()")
-    private void updateProgramLabelInSessionThread(final ILabelUpdate update) {
-        // Get a reference to the run control service.
-        final IRunControl runControl = getServicesTracker().getService(IRunControl.class);
-        if (runControl == null) {
-            handleFailedUpdate(update);
-            return;
-        }
-        
-        // Find the PDA program context.
-        final PDAProgramDMContext programCtx = 
-            findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAProgramDMContext.class);
-
-        // Call service to get current program state
-        final boolean isSuspended = runControl.isSuspended(programCtx);
-
-        // Set the program icon based on the running state of the program.
-        String imageKey = null;
-        if (isSuspended) {
-            imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
-        } else {
-            imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
-        }
-        update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
-
-        // Retrieve the last state change reason 
-        runControl.getExecutionData(
-            programCtx, 
-            new ViewerDataRequestMonitor<IExecutionDMData>(ImmediateExecutor.getInstance(), update) 
-            { 
-                @Override
-                public void handleCompleted(){
-                    // If the request failed, fail the udpate. 
-                    if (!isSuccess()) {
-                        handleFailedUpdate(update);
-                        return;
-                    }
-    
-                    // Compose the thread name string.
-                    final StringBuilder builder = new StringBuilder(); 
-    
-                    builder.append("PDA [");
-                    builder.append(programCtx.getProgram());
-                    builder.append("]");
-                    
-                    if(isSuspended) {
-                        builder.append(" (Suspended"); 
-                    } else {
-                        builder.append(" (Running"); 
-                    }
-                    // Reason will be null before ContainerSuspendEvent is fired
-                    if(getData().getStateChangeReason() != null) {
-                        builder.append(" : "); 
-                        builder.append(getData().getStateChangeReason());
-                    }
-                    builder.append(")"); 
-                    update.setLabel(builder.toString(), 0);
-                    update.done();
-                }
-            });        
-    }
-    
-    private void updateTerminatedThreadLabel(ILabelUpdate update) {
-        update.setLabel("<terminated> PDA [" + getProgramName(update) + "]", 0);
-        update.setImageDescriptor(DebugUITools.getImageDescriptor(IDebugUIConstants.IMG_OBJS_DEBUG_TARGET_TERMINATED), 0);
-        update.done();
-    }
-
-    private String getProgramName(IViewerUpdate update) {
-        // Retrieve the program name from the launch object in the update path.
-        String program = "unknown program";
-        ILaunch launch = findLaunchInPath(update.getElementPath());
-        if (launch != null) {
-            try {
-                program = launch.getLaunchConfiguration().getAttribute(PDAPlugin.ATTR_PDA_PROGRAM, program);
-            } catch (CoreException e) {
-                // Ignore, label will revert to default.
-            }
-        } 
-        return program;
-    }
-    
-    private PDALaunch findLaunchInPath(TreePath path) {
-        for (int i = 0; i < path.getSegmentCount(); i++) {
-            if (path.getSegment(i) instanceof PDALaunch) {
-                return (PDALaunch)path.getSegment(i);
-            }
-        }
-        return null;
-    }
-
-    public int getDeltaFlags(Object e) {
-        if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) {
-            return IModelDelta.STATE;
-        } 
-        if (e instanceof PDAStartedEvent) {
-            return IModelDelta.EXPAND | IModelDelta.SELECT;
-        }
-        return IModelDelta.NO_CHANGE;
-    }
-
-    public void buildDelta(Object e, VMDelta parentDelta, int nodeOffset, RequestMonitor rm) {
-        if(e instanceof IResumedDMEvent || e instanceof ISuspendedDMEvent) {
-            // If a suspended/resumed event is received, just update the 
-            // state of the program.  StackFramesVMNode will take care of 
-            // refreshing the stack frames.
-            parentDelta.addNode(createVMContext(((IDMEvent<?>)e).getDMContext()), IModelDelta.STATE);
-        } 
-        if (e instanceof PDAStartedEvent) {
-            // When debug session is started expand and select the program.
-            // If the program hits a breakpoint, the top stack frame will then
-            // be selected.
-            parentDelta.addNode(createVMContext(((PDAStartedEvent)e).getDMContext()), IModelDelta.EXPAND | IModelDelta.SELECT);            
-        }
-        rm.done();
-  	 }
-    
-    /*
-     * (non-Javadoc)
-     * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
-     */
-    private String produceProgramElementName( String viewName , PDAProgramDMContext execCtx ) {
-    	return "PDA." + execCtx.getProgram(); //$NON-NLS-1$
-    }
-    
-    private final String MEMENTO_NAME = "PDAPROGRAM_MEMENTO_NAME"; //$NON-NLS-1$
-    
-    public void compareElements(IElementCompareRequest[] requests) {
-        
-        for ( IElementCompareRequest request : requests ) {
-        	
-            Object element = request.getElement();
-            IMemento memento = request.getMemento();
-            String mementoName = memento.getString(MEMENTO_NAME);
-            
-            if (mementoName != null) {
-                if (element instanceof IDMVMContext) {
-                	
-                    IDMContext dmc = ((IDMVMContext)element).getDMContext();
-                    
-                    if ( dmc instanceof PDAProgramDMContext) {
-                    	
-                    	String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAProgramDMContext) dmc );
-                    	request.setEqual( elementName.equals( mementoName ) );
-                    } 
-                }
-            }
-            request.done();
-        }
-    }
-    
-    /*
-     * (non-Javadoc)
-     * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
-     */
-    public void encodeElements(IElementMementoRequest[] requests) {
-    	
-    	for ( IElementMementoRequest request : requests ) {
-    		
-            Object element = request.getElement();
-            IMemento memento = request.getMemento();
-            
-            if (element instanceof IDMVMContext) {
-
-            	IDMContext dmc = ((IDMVMContext)element).getDMContext();
-
-            	if ( dmc instanceof PDAProgramDMContext) {
-
-            		String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAProgramDMContext) dmc );
-            		memento.putString(MEMENTO_NAME, elementName);
-            	} 
-            }
-            request.done();
-        }
-    }
-}
diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAThreadsVMNode.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAThreadsVMNode.java
new file mode 100644
index 00000000000..d1d1750c858
--- /dev/null
+++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAThreadsVMNode.java
@@ -0,0 +1,156 @@
+/*******************************************************************************
+ * 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 multi threaded functionality	
+ *******************************************************************************/
+package org.eclipse.dd.examples.pda.ui.viewmodel.launch;
+
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractThreadVMNode;
+import org.eclipse.dd.dsf.debug.service.IRunControl;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData;
+import org.eclipse.dd.dsf.debug.service.IRunControl.StateChangeReason;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.dd.examples.pda.service.PDARunControl;
+import org.eclipse.dd.examples.pda.service.PDAThreadDMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementLabelProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.ui.IMemento;
+
+
+/**
+ * View model node supplying the PDA thread elements.  It extends 
+ * the base threads node and adds label and memento generation.
+ */
+@SuppressWarnings("restriction")
+public class PDAThreadsVMNode extends AbstractThreadVMNode 
+    implements IElementLabelProvider, IElementMementoProvider
+{
+    public PDAThreadsVMNode(AbstractDMVMProvider provider, DsfSession session) {
+        super(provider, session);
+    }
+
+    
+    @Override
+    protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
+        for (final ILabelUpdate update : updates) {
+        	final PDARunControl runControl = getServicesTracker().getService(PDARunControl.class);
+            if ( runControl == null ) {
+                    handleFailedUpdate(update);
+                    continue;
+            }
+            
+            final PDAThreadDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAThreadDMContext.class);
+
+            String imageKey = null;
+            if (getServicesTracker().getService(IRunControl.class).isSuspended(dmc)) {
+                imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
+            } else {
+                imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
+            }
+            update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+
+            // Find the Reason for the State
+            runControl.getExecutionData(dmc,
+            		new ViewerDataRequestMonitor<IExecutionDMData>(getSession().getExecutor(), update) {
+            	@Override
+				public void handleCompleted(){
+                    if (!isSuccess()) {
+                        handleFailedUpdate(update);
+                        return;
+                    }
+
+                    // We're in a new dispatch cycle, and we have to check whether the
+                    // service reference is still valid.
+                    final PDARunControl runControl = getServicesTracker().getService(PDARunControl.class);
+                    if ( runControl == null ) {
+                        handleFailedUpdate(update);
+                        return;
+                    }
+
+                    final StateChangeReason reason = getData().getStateChangeReason();
+
+                    // Create Labels of type Thread[GDBthreadId]RealThreadID/Name (State: Reason)
+                    // Thread[1] 3457 (Suspended:BREAKPOINT)
+                    final StringBuilder builder = new StringBuilder();
+                    builder.append("Thread ");
+                    builder.append(dmc.getID());
+                    if(getServicesTracker().getService(IRunControl.class).isSuspended(dmc))
+                        builder.append(" (Suspended"); 
+                    else
+                        builder.append(" (Running"); 
+                    // Reason will be null before ContainerSuspendEvent is fired
+                    if(reason != null) {
+                        builder.append(" : "); 
+                        builder.append(reason);
+                    }
+                    builder.append(")"); 
+                    update.setLabel(builder.toString(), 0);
+                    update.done();
+            	}
+            });
+            
+        }
+    }
+
+	private String produceThreadElementName(String viewName, PDAThreadDMContext execCtx) {
+		return "Thread." + execCtx.getID(); 
+    }
+
+    private static final String MEMENTO_NAME = "THREAD_MEMENTO_NAME"; 
+    
+    /*
+     * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#compareElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest[])
+     */
+    public void compareElements(IElementCompareRequest[] requests) {
+        for ( IElementCompareRequest request : requests ) {
+            Object element = request.getElement();
+            IMemento memento = request.getMemento();
+            String mementoName = memento.getString(MEMENTO_NAME);
+            if (mementoName != null) {
+                if (element instanceof IDMVMContext) {
+                    IDMContext dmc = ((IDMVMContext)element).getDMContext();
+                    if ( dmc instanceof PDAThreadDMContext) {
+                    	String elementName = produceThreadElementName( 
+                    	    request.getPresentationContext().getId(), (PDAThreadDMContext) dmc );
+                    	request.setEqual( elementName.equals( mementoName ) );
+                    }
+                }
+            }
+            request.done();
+        }
+    }
+    
+    /*
+     * @see org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider#encodeElements(org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest[])
+     */
+    public void encodeElements(IElementMementoRequest[] requests) {
+    	for ( IElementMementoRequest request : requests ) {
+            Object element = request.getElement();
+            IMemento memento = request.getMemento();
+            if (element instanceof IDMVMContext) {
+            	IDMContext dmc = ((IDMVMContext)element).getDMContext();
+            	if ( dmc instanceof PDAThreadDMContext) {
+            		String elementName = produceThreadElementName( request.getPresentationContext().getId(), (PDAThreadDMContext) dmc );
+                	memento.putString(MEMENTO_NAME, elementName);
+                }
+            }
+            request.done();
+        }
+    }
+
+}
diff --git a/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java
new file mode 100644
index 00000000000..4a31e8e2acc
--- /dev/null
+++ b/plugins/org.eclipse.dd.examples.pda.ui/src/org/eclipse/dd/examples/pda/ui/viewmodel/launch/PDAVirtualMachineVMNode.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2006, 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
+ *     Wind River Systems - Factored out AbstractContainerVMNode
+ *******************************************************************************/
+
+package org.eclipse.dd.examples.pda.ui.viewmodel.launch;
+
+
+import org.eclipse.dd.dsf.concurrent.ImmediateExecutor;
+import org.eclipse.dd.dsf.concurrent.RequestMonitor;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractContainerVMNode;
+import org.eclipse.dd.dsf.debug.service.IRunControl;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMData;
+import org.eclipse.dd.dsf.service.DsfSession;
+import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor;
+import org.eclipse.dd.dsf.ui.viewmodel.VMDelta;
+import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
+import org.eclipse.dd.dsf.ui.viewmodel.datamodel.IDMVMContext;
+import org.eclipse.dd.examples.pda.service.PDACommandControl;
+import org.eclipse.dd.examples.pda.service.PDAStartedEvent;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementCompareRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoProvider;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IElementMementoRequest;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.ILabelUpdate;
+import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
+import org.eclipse.debug.ui.DebugUITools;
+import org.eclipse.debug.ui.IDebugUIConstants;
+import org.eclipse.ui.IMemento;
+
+
+/**
+ * View Model node representing a PDA virtual machine.  It extends
+ * the base container node and adds label and memento generation. 
+ */
+@SuppressWarnings("restriction")
+public class PDAVirtualMachineVMNode extends AbstractContainerVMNode
+    implements IElementMementoProvider
+{
+
+    
+	public PDAVirtualMachineVMNode(AbstractDMVMProvider provider, DsfSession session) {
+        super(provider, session);
+	}
+
+	@Override
+	protected void updateElementsInSessionThread(IChildrenUpdate update) {
+        // Get the instance of the service.  Note that there is no race condition
+        // in getting the service since this method is called only in the 
+        // service executor thread.
+        final PDACommandControl commandControl = getServicesTracker().getService(PDACommandControl.class);
+
+        // Check if the service is available.  If it is not, no elements are 
+        // updated.
+        if (commandControl == null) {
+            handleFailedUpdate(update);
+            return;
+        }
+        
+        update.setChild(createVMContext(commandControl.getVirtualMachineDMContext()), 0);
+        update.done();
+	}
+
+	
+    @Override
+	protected void updateLabelInSessionThread(final ILabelUpdate update) {
+        // Get a reference to the run control service.
+        final IRunControl runControl = getServicesTracker().getService(IRunControl.class);
+        if (runControl == null) {
+            handleFailedUpdate(update);
+            return;
+        }
+        
+        // Find the PDA program context.
+        final PDAVirtualMachineDMContext programCtx = 
+            findDmcInPath(update.getViewerInput(), update.getElementPath(), PDAVirtualMachineDMContext.class);
+
+        // Call service to get current program state
+        final boolean isSuspended = runControl.isSuspended(programCtx);
+
+        // Set the program icon based on the running state of the program.
+        String imageKey = null;
+        if (isSuspended) {
+            imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
+        } else {
+            imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
+        }
+        update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+
+        // Retrieve the last state change reason 
+        runControl.getExecutionData(
+            programCtx, 
+            new ViewerDataRequestMonitor<IExecutionDMData>(ImmediateExecutor.getInstance(), update) 
+            { 
+                @Override
+                public void handleCompleted(){
+                    // If the request failed, fail the udpate. 
+                    if (!isSuccess()) {
+                        handleFailedUpdate(update);
+                        return;
+                    }
+    
+                    // Compose the thread name string.
+                    final StringBuilder builder = new StringBuilder(); 
+    
+                    builder.append("PDA [");
+                    builder.append(programCtx.getProgram());
+                    builder.append("]");
+                    
+                    if(isSuspended) {
+                        builder.append(" (Suspended"); 
+                    } else {
+                        builder.append(" (Running"); 
+                    }
+                    // Reason will be null before ContainerSuspendEvent is fired
+                    if(getData().getStateChangeReason() != null) {
+                        builder.append(" : "); 
+                        builder.append(getData().getStateChangeReason());
+                    }
+                    builder.append(")"); 
+                    update.setLabel(builder.toString(), 0);
+                    update.done();
+                }
+            });        
+    }
+
+/*    @Override
+    public int getDeltaFlags(Object e) {
+        if (e instanceof PDAStartedEvent) {
+            return IModelDelta.EXPAND | IModelDelta.SELECT;
+        }
+        return super.getDeltaFlags(e);
+    }
+
+    @Override
+    public void buildDelta(Object e, final VMDelta parentDelta, final int nodeOffset, final RequestMonitor rm) {
+        if (e instanceof PDAStartedEvent) {
+            // When debug session is started expand and select the program.
+            // If the program hits a breakpoint, the top stack frame will then
+            // be selected.
+            parentDelta.addNode(createVMContext(((PDAStartedEvent)e).getDMContext()), IModelDelta.EXPAND | IModelDelta.SELECT);            
+            rm.done();
+        } else {
+            super.buildDelta(e, parentDelta, nodeOffset, rm);
+        }
+    }
+*/
+    
+    private String produceProgramElementName( String viewName , PDAVirtualMachineDMContext execCtx ) {
+        return "PDA." + execCtx.getProgram(); //$NON-NLS-1$
+    }
+    
+    private final String MEMENTO_NAME = "PDAPROGRAM_MEMENTO_NAME"; //$NON-NLS-1$
+    
+    public void compareElements(IElementCompareRequest[] requests) {
+        
+        for ( IElementCompareRequest request : requests ) {
+            
+            Object element = request.getElement();
+            IMemento memento = request.getMemento();
+            String mementoName = memento.getString(MEMENTO_NAME);
+            
+            if (mementoName != null) {
+                if (element instanceof IDMVMContext) {
+                    
+                    IDMContext dmc = ((IDMVMContext)element).getDMContext();
+                    
+                    if ( dmc instanceof PDAVirtualMachineDMContext) {
+                        
+                        String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAVirtualMachineDMContext) dmc );
+                        request.setEqual( elementName.equals( mementoName ) );
+                    } 
+                }
+            }
+            request.done();
+        }
+    }
+    
+    public void encodeElements(IElementMementoRequest[] requests) {
+        
+        for ( IElementMementoRequest request : requests ) {
+            
+            Object element = request.getElement();
+            IMemento memento = request.getMemento();
+            
+            if (element instanceof IDMVMContext) {
+
+                IDMContext dmc = ((IDMVMContext)element).getDMContext();
+
+                if ( dmc instanceof PDAVirtualMachineDMContext) {
+
+                    String elementName = produceProgramElementName( request.getPresentationContext().getId(), (PDAVirtualMachineDMContext) dmc );
+                    memento.putString(MEMENTO_NAME, elementName);
+                } 
+            }
+            request.done();
+        }
+    }
+}
diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html b/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html
index 9e2b92749f4..1d79f31a4fc 100644
--- a/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html
+++ b/plugins/org.eclipse.dd.examples.pda/pdavm/docs/protocol.html
@@ -20,8 +20,11 @@ Clears any breakpoint set on given line
 <h3>data</h3>
 Retrieves data stack information 
 <pre>
-   C: data
+   C: data {thread_id}
    R: {value 1}|{value 2}|{value 3}|...|
+    
+Errors:
+   error: invalid thread
 </pre>
 
 
@@ -29,10 +32,20 @@ Retrieves data stack information
 Returns from the current frame without executing the rest of instructions.  
 
 <pre>
-   C: drop
+If VM running:
+   C: drop {thread_id}
    R: ok
-   E: resumed drop
-   E: suspended drop
+   E: resumed {thread_id} drop
+   E: suspended {thread_id} drop
+   
+If VM suspended:
+   C: drop {thread_id}
+   R: ok
+   E: vmresumed drop
+   E: vmsuspended {thread_id} drop
+
+Errors:
+   error: invalid thread
 </pre>
 
 
@@ -40,11 +53,16 @@ Returns from the current frame without executing the rest of instructions.
 Sets what events cause the execution to stop.
 
 <pre>
-   C: eval {instruction}%20{parameter}|{instruction}%20{parameter}|...
+   C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
    R: ok
-   E: resume client
+   E: resumed {thread_id} client
    E: evalresult result
-   E: suspended eval
+   E: suspended {thread_id} eval
+   
+Errors:
+   error: invalid thread
+   error: cannot evaluate while vm is suspended
+   error: thread running        
 </pre>
 
 
@@ -72,8 +90,11 @@ Instructs the debugger to exit.
 Pops the top value from the data stack  
 
 <pre>
-   C: popdata
+   C: popdata {thread_id}
    R: ok
+   
+Errors:
+   error: invalid thread
 </pre>
 
 
@@ -81,18 +102,27 @@ Pops the top value from the data stack
 Pushes the given value on top of the data stack.
 
 <pre>
-   C: pushdata {value}
+   C: pushdata {thread_id} {value}
    R: ok
+   
+Errors:
+   error: invalid thread
 </pre>
 
 
 <h3>resume</h3>
-Resumes the execution  
+Resumes the execution of a single thread.  Can be issued only if the virtual 
+machine is running.
 
 <pre>
-   C: resume
+   C: resume {thread_id}
    R: ok
-   E: resumed client
+   E: resumed {thread_id} client
+   
+Errors:
+   error: invalid thread
+   error: cannot resume thread when vm is suspended
+   error: thread already running
 </pre>
 
 
@@ -100,11 +130,19 @@ Resumes the execution
 Sets a breakpoint at given line
 
 <pre>
-   C: set {line_number}
+Suspend a single thread:
+   C: set {line_number} 0
    R: ok
-   C: resume
-   E: resumed client
-   E: suspended breakpoint line_number
+   C: resume {thread_id}
+   E: resumed {thread_id} client
+   E: suspended {thread_id} breakpoint line_number
+   
+Suspend the VM:
+   C: set {line_number} 1
+   R: ok
+   C: vmresume
+   E: vmresumed client
+   E: vmsuspended {thread_id} breakpoint line_number
 </pre>
 
 
@@ -112,8 +150,11 @@ Sets a breakpoint at given line
 Sets a data value in the data stack at the given location
 
 <pre>
-   C: setdata {index} {value}
+   C: setdata {thread_id} {index} {value}
    R: ok
+   
+Errors:
+   error: invalid thread
 </pre>
 
 
@@ -121,8 +162,11 @@ Sets a data value in the data stack at the given location
 Sets a variable value 
 
 <pre>
-   C: setvar {frame_number} {variable} {value}
+   C: setvar {thread_id} {frame_number} {variable} {value}
    R: ok
+   
+Errors:
+   error: invalid thread
 </pre>
 
 
@@ -130,8 +174,11 @@ Sets a variable value
 Retrieves command stack information 
 
 <pre>
-   C: stack
-   R: {file}|{line}|{function}|{var_1}|{var_2}|...{file}|{line}|{function}|{var_1}|{var_2}|......
+   C: stack {thread_id}
+   R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
+   
+Errors:
+   error: invalid thread
 </pre>
 
 
@@ -139,10 +186,20 @@ Retrieves command stack information
 Executes next instruction 
 
 <pre>
-   C: step
+If VM running:
+   C: step {thread_id}
    R: ok
-   E: resumed step
-   E: suspended step
+   E: resumed {thread_id} client
+   E: suspended {thread_id} step
+   
+If VM suspended:
+   C: step {thread_id}
+   R: ok
+   E: vmresumed client
+   E: vmsuspended {thread_id} step
+   
+Errors:
+   error: invalid thread
 </pre>
 
 
@@ -150,29 +207,56 @@ Executes next instruction
 Executes instructions until the current subroutine is finished 
 
 <pre>
-   C: stepreturn
+If VM running:
+   C: stepreturn {thread_id}
    R: ok
-   E: resumed step
-   E: suspended step
+   E: resumed {thread_id} client
+   E: suspended {thread_id} step
+   
+If VM suspended:
+   C: stepreturn {thread_id}
+   R: ok
+   E: vmresumed client
+   E: vmsuspended {thread_id} step
+   
+Errors:
+   error: invalid thread
 </pre>
 
 
 <h3>suspend</h3>
-Suspends execution 
+Suspends execution of a single thread.  Can be issued only if the virtual 
+machine is running.
 
 <pre>
-   C: suspend
+   C: suspend {thread_id}
    R: ok
-   E: suspended client
+   E: suspended {thread_id} client
+   
+Errors:
+   error: invalid thread
+      error: vm already suspended
+   error: thread already suspended
 </pre>
 
+<h3>threads</h3>
+Retrieves the list of active threads 
+
+<pre>
+   C: threads
+   R: {thread id} {thread id} ...
+</pre>
 
 <h3>var</h3>
 Retrieves variable value 
 
 <pre>
-   C: var {frame_number} {variable_name}
+   C: var  {thread_id} {frame_number} {variable_name}
    R: {variable_value}
+   
+Errors:
+   error: invalid thread
+   error: variable undefined
 </pre>
 
 
@@ -194,5 +278,31 @@ The <code>watch_operation<code> value can be:
   <li>2 - write watch</li>
   <li>3 - both, etc.</li>
 </ul>
+
+
+<h3>vmresume</h3>
+Resumes the execution of the whole virtual machine  
+ 
+<pre>
+   C: vmresume
+   R: ok
+   E: vmresumed client
+   
+Errors:
+   error: vm already running
+</pre>
+
+<h3>vmsuspend</h3>
+Suspends the execution of the whole virtual machine 
+
+<pre>
+   C: vmsuspend
+   R: ok
+   E: vmsuspended client
+   
+Errors:
+   error: thread already suspended
+</pre>
 </body>
+
 </html>
diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java b/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java
index d371f00c686..443bad80bcb 100644
--- a/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java
+++ b/plugins/org.eclipse.dd.examples.pda/pdavm/src/org/eclipse/dd/examples/pdavm/PDAVirtualMachine.java
@@ -38,55 +38,111 @@ public class PDAVirtualMachine {
         public Object pop() {
             return isEmpty() ? 0 : remove(size() - 1);
         }
-        
+
         public void push(Object value) {
             add(value);
         }
     }
 
     class Args {
-        private final String[] fArgs;
+        final String[] fArgs;
+
         int next = 0;
+
         Args(String[] args) {
             fArgs = args;
         }
-        
+
         String getNextStringArg() {
             if (fArgs.length > next) {
                 return fArgs[next++];
             }
             return "";
         }
-        
+
         int getNextIntArg() {
             String arg = getNextStringArg();
             try {
                 return Integer.parseInt(arg);
-            } catch (NumberFormatException e) {}
+            } catch (NumberFormatException e) {
+            }
             return 0;
         }
-        
+
         Object getNextIntOrStringArg() {
             String arg = getNextStringArg();
             try {
                 return Integer.parseInt(arg);
-            } catch (NumberFormatException e) {}
-            return arg;            
+            } catch (NumberFormatException e) {
+            }
+            return arg;
+        }
+
+        PDAThread getThreadArg() {
+            int id = getNextIntArg();
+            return fThreads.get(id);
         }
     }
 
-    /** The push down automata data stack (the data stack). */
-    private final Stack fStack = new Stack();
+    class PDAThread {
+        final int fID;
 
+        /** The push down automata data stack (the data stack). */
+        final Stack fStack = new Stack();
+
+        /**
+         * PDAThread copy of the code. It can differ from the program if
+         * performing an evaluation.
+         */
+        String[] fThreadCode;
+
+        /** PDAThread copy of the labels. */
+        Map<String, Integer> fThreadLabels;
+
+        /** The stack of stack frames (the control stack) */
+        final List<Frame> fFrames = new LinkedList<Frame>();
+
+        /** Current stack frame (not includced in fFrames) */
+        Frame fCurrentFrame;
+
+        /**
+         * The run flag is true if the thread is running. If the run flag is
+         * false, the thread exits the next time the main instruction loop runs.
+         */
+        boolean fRun = true;
+
+        String fSuspend = null;
+
+        boolean fStep = false;
+
+        boolean fStepReturn = false;
+        
+        int fSavedPC;
+
+        boolean fPerformingEval = false;
+        
+        PDAThread(int id, String function, int pc) {
+            fID = id;
+            fCurrentFrame = new Frame(function, pc);
+            fThreadCode = fCode;
+            fThreadLabels = fLabels;
+        }
+    }
+
+    final Map<Integer, PDAThread> fThreads = new LinkedHashMap<Integer, PDAThread>();
+
+    int fNextThreadId = 1;
+
+    private boolean fStarted = true;
     /**
-     * The code is stored as an array of strings, each line of
-     * the source file being one entry in the array.
+     * The code is stored as an array of strings, each line of the source file
+     * being one entry in the array.
      */
-    private String[] fCode;
+    final String[] fCode;
 
     /** A mapping of labels to indicies in the code array */
-    private Map<String,Integer> fLabels = new HashMap<String, Integer>();
-    
+    final Map<String, Integer> fLabels;
+
     /** Each stack frame is a mapping of variable names to values. */
     class Frame extends LinkedHashMap<String, Object> {
         /**
@@ -95,80 +151,68 @@ public class PDAVirtualMachine {
         final String fFunction;
 
         /**
-         * The current program counter in the frame
-         * the pc points to the next instruction to be executed
+         * The current program counter in the frame the pc points to the next
+         * instruction to be executed
          */
         int fPC;
 
-        public Frame(String function, int pc) {
+        Frame(String function, int pc) {
             fFunction = function;
             fPC = pc;
         }
     }
-    
-    /** The stack of stack frames (the control stack) */
-    private final List<Frame> fFrames = new LinkedList<Frame>();
-
-    /** Current stack frame (not includced in fFrames) */
-    private Frame fCurrentFrame = new Frame("main", 0);
-    
-    /**
-     * Breakpoints are stored as a boolean for each line of code
-     * if the boolean is true, there is a breakpoint on that line
-     */
-    private final Map<Integer, Boolean> fBreakpoints = new HashMap<Integer, Boolean>();
 
     /**
-     * The run flag is true if the VM is running.
-     * If the run flag is false, the VM exits the
-     * next time the main instruction loop runs.
+     * Breakpoints are stored per each each line of code.  The boolean indicates
+     * whether the whole VM should suspend or just the triggering thread.
      */
-    private boolean fRun = true;
+    final Map<Integer, Boolean> fBreakpoints = new HashMap<Integer, Boolean>();
 
     /**
-     * The suspend flag is true if the VM should suspend
-     * running the program and just listen for debug commands.
+     * The suspend flag is true if the VM should suspend running the program and
+     * just listen for debug commands.
      */
-    private String fSuspend;
+    String fSuspendVM;
 
     /** Flag indicating whether the debugger is performing a step. */
-    private boolean fStep = false;
-    
+    boolean fStepVM = false;
+
     /** Flag indicating whether the debugger is performing a step return */
-    private boolean fStepReturn = false;
+    boolean fStepReturnVM = false;
     
-    /** Flag indicating whether the started event was sent. */
-    private boolean fStarted = true;
+    int fSteppingThread = 0;
 
     /** Name of the pda program being debugged */
-    private final String fFilename;    
+    final String fFilename;
 
-    /**The command line argument to start a debug session. */
-    private final boolean fDebug;
+    /** The command line argument to start a debug session. */
+    final boolean fDebug;
 
     /** The port to listen for debug commands on */
-    private final int fCommandPort;
+    final int fCommandPort;
 
-    /** Command socket for receiving debug commands and sending command responses */    
-    private Socket fCommandSocket;
+    /**
+     * Command socket for receiving debug commands and sending command responses
+     */
+    Socket fCommandSocket;
 
     /** Command socket reader */
-    private BufferedReader fCommandReceiveStream;
-    
+    BufferedReader fCommandReceiveStream;
+
     /** Command socket write stream. */
-    private OutputStream fCommandResponseStream;
+    OutputStream fCommandResponseStream;
 
     /** The port to send debug events to */
-    private final int fEventPort;
-    
+    final int fEventPort;
+
     /** Event socket */
-    private Socket fEventSocket;
-    
+    Socket fEventSocket;
+
     /** Event socket and write stream. */
-    private OutputStream fEventStream;
+    OutputStream fEventStream;
 
     /** The eventstops table holds which events cause suspends and which do not. */
-    private final Map<String, Boolean> fEventStops =  new HashMap<String, Boolean>();
+    final Map<String, Boolean> fEventStops = new HashMap<String, Boolean>();
     {
         fEventStops.put("unimpinstr", false);
         fEventStops.put("nosuchlabel", false);
@@ -176,37 +220,35 @@ public class PDAVirtualMachine {
 
     /**
      * The watchpoints table holds watchpoint information.
-     *  variablename_stackframedepth => N
-     *  N = 0 is no watch
-     *  N = 1 is read watch
-     *  N = 2 is write watch
-     *  N = 3 is both, etc.
+     * <p/>
+     * variablename_stackframedepth => N
+     * <ul> 
+     * <li>N = 0 is no watch</li> 
+     * <li>N = 1 is read watch</li>
+     * <li>N = 2 is write watch</li>
+     * <li>N = 3 is both, etc.</li>
      */
-    private final Map<String, Integer> fWatchpoints = new HashMap<String, Integer>();
-    
-    public String[] fSavedCode;
-    public Map<String, Integer> fSavedLables;
-    public int fSavedPC;
-    
+    final Map<String, Integer> fWatchpoints = new HashMap<String, Integer>();
+
     public static void main(String[] args) {
         String programFile = args.length >= 1 ? args[0] : null;
         if (programFile == null) {
             System.err.println("Error: No program specified");
             return;
         }
-        
+
         String debugFlag = args.length >= 2 ? args[1] : "";
         boolean debug = "-debug".equals(debugFlag);
         int commandPort = 0;
         int eventPort = 0;
-                
+
         if (debug) {
             String commandPortStr = args.length >= 3 ? args[2] : "";
             try {
                 commandPort = Integer.parseInt(commandPortStr);
             } catch (NumberFormatException e) {
                 System.err.println("Error: Invalid command port");
-                return;                
+                return;
             }
 
             String eventPortStr = args.length >= 4 ? args[3] : "";
@@ -214,10 +256,10 @@ public class PDAVirtualMachine {
                 eventPort = Integer.parseInt(eventPortStr);
             } catch (NumberFormatException e) {
                 System.err.println("Error: Invalid event port");
-                return;                
+                return;
             }
         }
-        
+
         PDAVirtualMachine pdaVM = null;
         try {
             pdaVM = new PDAVirtualMachine(programFile, debug, commandPort, eventPort);
@@ -228,10 +270,10 @@ public class PDAVirtualMachine {
         }
         pdaVM.run();
     }
-    
-    public PDAVirtualMachine(String inputFile, boolean debug, int commandPort, int eventPort) throws IOException{
+
+    PDAVirtualMachine(String inputFile, boolean debug, int commandPort, int eventPort) throws IOException {
         fFilename = inputFile;
-        
+
         // Load all the code into memory
         FileReader fileReader = new FileReader(inputFile);
         StringWriter stringWriter = new StringWriter();
@@ -249,37 +291,35 @@ public class PDAVirtualMachine {
         code.add(stringWriter.toString().trim());
         fCode = code.toArray(new String[code.size()]);
 
-        mapLabels();
-        
+        fLabels = mapLabels(fCode);
+
         fDebug = debug;
         fCommandPort = commandPort;
         fEventPort = eventPort;
-        if (fDebug) {
-            fSuspend = "client";
-        }
     }
-    
+
     /**
      * Initializes the labels map
      */
-    private void mapLabels() {
-        fLabels = new HashMap<String, Integer>();
-        for (int i = 0; i < fCode.length; i++) {
-            if (fCode[i].length() != 0 && fCode[i].charAt(0) == ':') {
-                fLabels.put(fCode[i].substring(1), i);
+    Map<String, Integer> mapLabels(String[] code) {
+        Map<String, Integer> labels = new HashMap<String, Integer>();
+        for (int i = 0; i < code.length; i++) {
+            if (code[i].length() != 0 && code[i].charAt(0) == ':') {
+                labels.put(code[i].substring(1), i);
             }
         }
-        
+        return labels;
     }
-    
-    private void sendCommandResponse(String response) {
+
+    void sendCommandResponse(String response) {
         try {
             fCommandResponseStream.write(response.getBytes());
             fCommandResponseStream.flush();
-        } catch (IOException e) {}
+        } catch (IOException e) {
+        }
     }
 
-    private void sendDebugEvent(String event, boolean error) {
+    void sendDebugEvent(String event, boolean error) {
         if (fDebug) {
             try {
                 fEventStream.write(event.getBytes());
@@ -287,18 +327,18 @@ public class PDAVirtualMachine {
                 fEventStream.flush();
             } catch (IOException e) {
                 System.err.println("Error: " + e);
-                fRun = false;
+                System.exit(1);
             }
         } else if (error) {
             System.err.println("Error: " + event);
         }
     }
-    
-    private void startDebugger() throws IOException {
+
+    void startDebugger() throws IOException {
         if (fDebug) {
             System.out.println("-debug " + fCommandPort + " " + fEventPort);
         }
-        
+
         ServerSocket commandServerSocket = new ServerSocket(fCommandPort);
         fCommandSocket = commandServerSocket.accept();
         fCommandReceiveStream = new BufferedReader(new InputStreamReader(fCommandSocket.getInputStream()));
@@ -309,32 +349,74 @@ public class PDAVirtualMachine {
         fEventSocket = eventServerSocket.accept();
         fEventStream = new PrintStream(fEventSocket.getOutputStream());
         eventServerSocket.close();
-        
+
         System.out.println("debug connection accepted");
-        
-        fSuspend = "client";
-        sendDebugEvent("started", false);
+
+        fSuspendVM = "client";
     }
-    
-    public void run() {
-        while (fRun) {
+
+    void run() {
+        int id = fNextThreadId++;
+        fThreads.put(id, new PDAThread(id, "main", 0));
+        if (fDebug) {
+            sendDebugEvent("started " + id, false);
+        }
+
+        boolean allThreadsSuspended = false;
+        while (!fThreads.isEmpty()) {
             checkForBreakpoint();
-            if (fSuspend != null) {
+            
+            if (fSuspendVM != null) {
                 debugUI();
-            }
-            yieldToDebug();
-            String instruction = fCode[fCurrentFrame.fPC];
-            fCurrentFrame.fPC++;
-            doOneInstruction(instruction);
-            if (fCurrentFrame.fPC > fCode.length) {
-                fRun = false;
-            } else if (fStepReturn) {
-                instruction = fCode[fCurrentFrame.fPC];
-                if ("return".equals(instruction)) {
-                    fSuspend = "step";
+            } else {
+                yieldToDebug(allThreadsSuspended);
+                if (fSuspendVM != null) {
+                    // Received a command to suspend VM, skip executing threads.
+                    continue;
                 }
             }
+
+            PDAThread[] threadsCopy = fThreads.values().toArray(new PDAThread[fThreads.size()]);
+            allThreadsSuspended = true;
+            for (PDAThread thread : threadsCopy) {
+                if (thread.fSuspend == null) {
+                    allThreadsSuspended = false;
+                    
+                    String instruction = thread.fThreadCode[thread.fCurrentFrame.fPC];
+                    thread.fCurrentFrame.fPC++;
+                    doOneInstruction(thread, instruction);
+                    if (thread.fCurrentFrame.fPC > thread.fThreadCode.length) {
+                        // Thread reached end of code, exit from the thread.
+                        thread.fRun = false;
+                    } else if (thread.fStepReturn) {
+                        // If this thread is in a step-return operation, check
+                        // if we've returned from a call.  
+                        instruction = thread.fThreadCode[thread.fCurrentFrame.fPC];
+                        if ("return".equals(instruction)) {
+                            // Note: this will only be triggered if the current 
+                            // thread also has the fStepReturn flag set.
+                            if (fStepReturnVM) {
+                                fSuspendVM = thread.fID + " step";
+                            } else {
+                                thread.fSuspend = "step";
+                            }
+                        }
+                    }
+                    if (!thread.fRun) {
+                        sendDebugEvent("exited " + thread.fID, false);
+                        fThreads.remove(thread.fID);
+                    } else if (thread.fSuspend != null) {
+                        sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false);
+                        thread.fStep = thread.fStepReturn = thread.fPerformingEval = false;
+                    }
+                } 
+            }
+            
+            // Force thread context switch to avoid starving out other
+            // processes in the system.
+            Thread.yield();
         }
+        
         sendDebugEvent("terminated", false);
         if (fDebug) {
             try {
@@ -347,122 +429,141 @@ public class PDAVirtualMachine {
                 System.out.println("Error: " + e);
             }
         }
-            
-    }
-    
-    private void doOneInstruction(String instr) {
-        if (instr.startsWith(":")) {
-            // label
-            if (fStep) {
-                fSuspend = "step";
-            }
-        } else if (instr.startsWith("#")) {
-            // comment
-        } else {
-            StringTokenizer tokenizer = new StringTokenizer(instr);
-            String op = tokenizer.nextToken();
-            List<String> tokens = new LinkedList<String>();
-            while (tokenizer.hasMoreTokens()) {
-                tokens.add(tokenizer.nextToken());
-            }
-            Args args = new Args(tokens.toArray(new String[tokens.size()]));
 
-            boolean opValid = true;
-            if (op.equals("add")) iAdd(args);
-            else if (op.equals("branch_not_zero")) iBranchNotZero(args);
-            else if (op.equals("call")) iCall(args);
-            else if (op.equals("dec")) iDec(args);
-            else if (op.equals("dup")) iDup(args);
-            else if (op.equals("halt")) iHalt(args);
-            else if (op.equals("output")) iOutput(args);
-            else if (op.equals("pop")) iPop(args);
-            else if (op.equals("push")) iPush(args);
-            else if (op.equals("return")) iReturn(args);
-            else if (op.equals("var")) iVar(args);
-            else if (op.equals("xyzzy")) iInternalEndEval(args);
-            else {
-                opValid = false;
+    }
+
+    void doOneInstruction(PDAThread thread, String instr) {
+        StringTokenizer tokenizer = new StringTokenizer(instr);
+        String op = tokenizer.nextToken();
+        List<String> tokens = new LinkedList<String>();
+        while (tokenizer.hasMoreTokens()) {
+            tokens.add(tokenizer.nextToken());
+        }
+        Args args = new Args(tokens.toArray(new String[tokens.size()]));
+
+        boolean opValid = true;
+        if (op.equals("add")) iAdd(thread, args);
+        else if (op.equals("branch_not_zero")) iBranchNotZero(thread, args);
+        else if (op.equals("call")) iCall(thread, args);
+        else if (op.equals("dec")) iDec(thread, args);
+        else if (op.equals("dup")) iDup(thread, args);
+        else if (op.equals("exec")) iExec(thread, args);            
+        else if (op.equals("halt")) iHalt(thread, args);
+        else if (op.equals("output")) iOutput(thread, args);
+        else if (op.equals("pop")) iPop(thread, args);
+        else if (op.equals("push")) iPush(thread, args);
+        else if (op.equals("return")) iReturn(thread, args);
+        else if (op.equals("var")) iVar(thread, args);
+        else if (op.equals("xyzzy")) iInternalEndEval(thread, args);
+        else if (op.startsWith(":")) {} // label
+        else if (op.startsWith("#")) {} // comment
+        else {
+            opValid = false;
+        }
+
+        if (!opValid) {
+            sendDebugEvent("unimplemented instruction " + op, true);
+            if (fEventStops.get("unimpinstr")) {
+                fSuspendVM = thread.fID + " event unimpinstr";
+                thread.fCurrentFrame.fPC--;
             }
-            
-            if (!opValid) {
-                sendDebugEvent("unimplemented instruction " + op, true);
-                if (fEventStops.get("unimpinstr")) {
-                    fSuspend = "event unimpinstr";
-                    fCurrentFrame.fPC--;
-                }
-            } else if (fStep) {
-                fSuspend = "step";
+        } else if (thread.fStep) {
+            if (fStepVM) {
+                fSuspendVM = thread.fID + " step";
+                fStepVM = false;
+            } else {
+                thread.fSuspend = "step";
             }
+            thread.fStep = false;
         }
     }
-    
-    private void checkForBreakpoint() {
+
+    void checkForBreakpoint() {
         if (fDebug) {
-            int pc = fCurrentFrame.fPC;
-            if (!"eval".equals(fSuspend) && fBreakpoints.containsKey(pc) && fBreakpoints.get(pc)) {
-                fSuspend = "breakpoint " + pc;
+            for (PDAThread thread : fThreads.values()) {
+                int pc = thread.fCurrentFrame.fPC;
+                // Suspend for breakpoint if:
+                // - the VM is not yet set to suspend, for e.g. as a result of step end,
+                // - the thread is not yet suspended and is not performing an evaluation
+                // - the breakpoints table contains a breakpoint for the given line.
+                if (fSuspendVM == null && 
+                    thread.fSuspend == null && !thread.fPerformingEval && 
+                    fBreakpoints.containsKey(pc)) 
+                {
+                    if (fBreakpoints.get(pc)) {
+                        fSuspendVM = thread.fID + " breakpoint " + pc;
+                    } else {
+                        thread.fSuspend = "breakpoint " + pc;
+                        thread.fStep = thread.fStepReturn = false;
+                        sendDebugEvent("suspended " + thread.fID + " " + thread.fSuspend, false);
+                    }
+                }
             }
         }
     }
-    
+
     /**
-     * For each instruction, we check the debug co-routine for
-     * control input. If there is input, we process it.
+     * After each instruction, we check the debug command channel for control input. If
+     * there are commands, process them.
      */
-    private void yieldToDebug() {
+    void yieldToDebug(boolean allThreadsSuspended) {
         if (fDebug) {
             String line = "";
             try {
-                if (fCommandReceiveStream.ready()) {
+                if (allThreadsSuspended || fCommandReceiveStream.ready()) {
                     line = fCommandReceiveStream.readLine();
                     processDebugCommand(line);
                 }
             } catch (IOException e) {
                 System.err.println("Error: " + e);
-                fRun = false;
-                return;
+                System.exit(1);
             }
         }
     }
-    
-    private void debugUI() {
-        if (fSuspend == null) {
-            return;
-        }
-        
+
+    /**
+     *  Service the debugger commands while the VM is suspended
+     */
+    void debugUI() {
         if (!fStarted) {
-            sendDebugEvent("suspended " + fSuspend, false);
+            sendDebugEvent("vmsuspended " + fSuspendVM, false);
         } else {
             fStarted = false;
         }
+
+        // Clear all stepping flags.  In case the VM suspended while
+        // a step operation was being performed for the VM or some thread.
+        fStepVM = fStepReturnVM = false;
+        for (PDAThread thread : fThreads.values()) {
+            thread.fSuspend = null;
+            thread.fStep = thread.fStepReturn = thread.fPerformingEval = false;
+        }
         
-        fStep = false;
-        fStepReturn = false;
-        
-        while (fSuspend != null) {
+        while (fSuspendVM != null) {
             String line = "";
             try {
                 line = fCommandReceiveStream.readLine();
             } catch (IOException e) {
                 System.err.println("Error: " + e);
-                fRun = false;
+                System.exit(1);
                 return;
             }
             processDebugCommand(line);
         }
-        if (fStep) {
-            sendDebugEvent("resumed step", false);
+
+        if (fStepVM || fStepReturnVM) {
+            sendDebugEvent("vmresumed step", false);
         } else {
-            sendDebugEvent("resumed client", false);
+            sendDebugEvent("vmresumed client", false);
         }
     }
-    
-    private void processDebugCommand(String line) {
+
+    void processDebugCommand(String line) {
         StringTokenizer tokenizer = new StringTokenizer(line.trim());
         if (line.length() == 0) {
             return;
         }
-        
+
         String command = tokenizer.nextToken();
         List<String> tokens = new LinkedList<String>();
         while (tokenizer.hasMoreTokens()) {
@@ -471,42 +572,64 @@ public class PDAVirtualMachine {
         Args args = new Args(tokens.toArray(new String[tokens.size()]));
 
         if ("clear".equals(command)) debugClearBreakpoint(args);
-        else if ("data".equals(command)) debugData();
-        else if ("drop".equals(command)) debugDropFrame();
+        else if ("data".equals(command)) debugData(args);
+        else if ("drop".equals(command)) debugDropFrame(args);
         else if ("eval".equals(command)) debugEval(args);
         else if ("eventstop".equals(command)) debugEventStop(args);
         else if ("exit".equals(command)) debugExit();
-        else if ("popdata".equals(command)) debugPop();
+        else if ("popdata".equals(command)) debugPop(args);
         else if ("pushdata".equals(command)) debugPush(args);
-        else if ("resume".equals(command)) debugResume();
+        else if ("resume".equals(command)) debugResume(args);
         else if ("set".equals(command)) debugSetBreakpoint(args);
         else if ("setdata".equals(command)) debugSetData(args);
         else if ("setvar".equals(command)) debugSetVariable(args);
-        else if ("stack".equals(command)) debugStack();
-        else if ("step".equals(command)) debugStep();
-        else if ("stepreturn".equals(command)) debugStepReturn();
-        else if ("suspend".equals(command)) debugSuspend();
+        else if ("stack".equals(command)) debugStack(args);
+        else if ("state".equals(command)) debugState(args);
+        else if ("step".equals(command)) debugStep(args);
+        else if ("stepreturn".equals(command)) debugStepReturn(args);
+        else if ("suspend".equals(command)) debugSuspend(args);
+        else if ("threads".equals(command)) debugThreads();
         else if ("var".equals(command)) debugVar(args);
+        else if ("vmresume".equals(command)) debugVMResume();
+        else if ("vmsuspend".equals(command)) debugVMSuspend();
         else if ("watch".equals(command)) debugWatch(args);
+        else {
+            sendCommandResponse("error: invalid command\n");
+        }
     }
-    
-    private void debugClearBreakpoint(Args args) {
+
+    void debugClearBreakpoint(Args args) {
         int line = args.getNextIntArg();
-        
-        fBreakpoints.put(line, false);
+
+        fBreakpoints.remove(line);
         sendCommandResponse("ok\n");
     }
 
     private static Pattern fPackPattern = Pattern.compile("%([a-fA-F0-9][a-fA-F0-9])");
-    private void debugEval(Args args) {
+
+    void debugEval(Args args) {
+        if (fSuspendVM != null) {
+            sendCommandResponse("error: cannot evaluate while vm is suspended\n");        
+            return;
+        }
+        
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
+        
+        if (thread.fSuspend == null) {
+            sendCommandResponse("error: thread running\n");
+            return;
+        }
         
         StringTokenizer tokenizer = new StringTokenizer(args.getNextStringArg(), "|");
         tokenizer.countTokens();
-        
-        fSavedCode = fCode;
+
         int numEvalLines = tokenizer.countTokens();
-        fCode = new String[fSavedCode.length + numEvalLines + 1];
-        System.arraycopy(fSavedCode, 0, fCode, 0, fSavedCode.length);
+        thread.fThreadCode = new String[fCode.length + numEvalLines + 1];
+        System.arraycopy(fCode, 0, thread.fThreadCode, 0, fCode.length);
         for (int i = 0; i < numEvalLines; i++) {
             String line = tokenizer.nextToken();
             StringBuffer lineBuf = new StringBuffer(line.length());
@@ -516,123 +639,188 @@ public class PDAVirtualMachine {
                 lineBuf.append(line.substring(lastMatchEnd, matcher.start()));
                 String charCode = line.substring(matcher.start() + 1, matcher.start() + 3);
                 try {
-                    lineBuf.append((char)Integer.parseInt(charCode, 16));
-                } catch (NumberFormatException e) {}
+                    lineBuf.append((char) Integer.parseInt(charCode, 16));
+                } catch (NumberFormatException e) {
+                }
                 lastMatchEnd = matcher.end();
             }
             if (lastMatchEnd < line.length()) {
                 lineBuf.append(line.substring(lastMatchEnd));
             }
-            fCode[fSavedCode.length + i] = lineBuf.toString();
+            thread.fThreadCode[fCode.length + i] = lineBuf.toString();
         }
-        fCode[fSavedCode.length + numEvalLines] = "xyzzy";
-        mapLabels(); 
+        thread.fThreadCode[fCode.length + numEvalLines] = "xyzzy";
+        thread.fThreadLabels = mapLabels(fCode);
+
+        thread.fSavedPC = thread.fCurrentFrame.fPC;
+        thread.fCurrentFrame.fPC = fCode.length;
+        thread.fPerformingEval = true;
         
-        fSavedPC = fCurrentFrame.fPC;
-        fCurrentFrame.fPC = fSavedCode.length;
+        thread.fSuspend = null;
         
         sendCommandResponse("ok\n");
-        
-        fSuspend = null;
+
+        sendDebugEvent("resumed " + thread.fID + " eval", false);
     }
-    
-    private void debugData() {
+
+    void debugData(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
+
         StringBuffer result = new StringBuffer();
-        for (Object val : fStack) {
+        for (Object val : thread.fStack) {
             result.append(val);
             result.append('|');
         }
         result.append('\n');
         sendCommandResponse(result.toString());
     }
-    
-    private void debugDropFrame() {
-        if (!fFrames.isEmpty()) {
-            fCurrentFrame = fFrames.remove(fFrames.size() - 1);
+
+    void debugDropFrame(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
         }
-        fCurrentFrame.fPC--;
+
+        if (!thread.fFrames.isEmpty()) {
+            thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1);
+        }
+        thread.fCurrentFrame.fPC--;
         sendCommandResponse("ok\n");
-        sendDebugEvent( "resumed drop", false );
-        sendDebugEvent( "suspended drop", false );
+        if (fSuspendVM != null) {
+            sendDebugEvent("vmresumed drop", false);
+            sendDebugEvent("vmsuspended " + thread.fID + " drop", false);
+        } else {
+            sendDebugEvent("resumed " + thread.fID + " drop", false);
+            sendDebugEvent("suspended " + thread.fID + " drop", false);
+        }
     }
-    
-    private void debugEventStop(Args args) {
+
+    void debugEventStop(Args args) {
         String event = args.getNextStringArg();
         int stop = args.getNextIntArg();
         fEventStops.put(event, stop > 0);
         sendCommandResponse("ok\n");
     }
 
-    private void debugExit() {
+    void debugExit() {
         sendCommandResponse("ok\n");
-        sendDebugEvent( "terminated", false );
+        sendDebugEvent("terminated", false);
         System.exit(0);
     }
-    
-    private void debugPop() {
-        fStack.pop();
-        sendCommandResponse("ok\n");
-    }
-    
-    private void debugPush(Args args) {
-        Object val = args.getNextIntOrStringArg();
-        fStack.push(val);
+
+    void debugPop(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
+
+        thread.fStack.pop();
         sendCommandResponse("ok\n");
     }
 
-    private void debugResume() {
-        fSuspend = null;
-        sendCommandResponse("ok\n");
-    }
-
-    private void debugSetBreakpoint(Args args) {
-        int line = args.getNextIntArg();
+    void debugPush(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
         
-        fBreakpoints.put(line, true);
+        Object val = args.getNextIntOrStringArg();
+        thread.fStack.push(val);
         sendCommandResponse("ok\n");
     }
-    
-    private void debugSetData(Args args) {
+
+    void debugResume(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        } 
+        if (fSuspendVM != null) {
+            sendCommandResponse("error: cannot resume thread when vm is suspended\n");
+            return;
+        } 
+        if (thread.fSuspend == null) {
+            sendCommandResponse("error: thread already running\n");
+            return;
+        } 
+        
+        thread.fSuspend = null;
+        sendDebugEvent("resumed " + thread.fID + " client", false);
+        
+        sendCommandResponse("ok\n");
+    }
+
+    void debugSetBreakpoint(Args args) {
+        int line = args.getNextIntArg();
+        int stopVM = args.getNextIntArg();
+        
+        fBreakpoints.put(line, stopVM != 0);
+        sendCommandResponse("ok\n");
+    }
+
+    void debugSetData(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
+        
         int offset = args.getNextIntArg();
         Object val = args.getNextIntOrStringArg();
 
-        if (offset < fStack.size()) {
-            fStack.set(offset, val);
+        if (offset < thread.fStack.size()) {
+            thread.fStack.set(offset, val);
         } else {
-            fStack.add(0, val);
+            thread.fStack.add(0, val);
         }
         sendCommandResponse("ok\n");
     }
 
-    private void debugSetVariable(Args args) {
+    void debugSetVariable(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
+
         int sfnumber = args.getNextIntArg();
         String var = args.getNextStringArg();
         Object val = args.getNextIntOrStringArg();
-        
-        if (sfnumber > fFrames.size()) {
-            fCurrentFrame.put(var, val);
+
+        if (sfnumber >= thread.fFrames.size()) {
+            thread.fCurrentFrame.put(var, val);
         } else {
-            fFrames.get(sfnumber).put(var, val);
+            thread.fFrames.get(sfnumber).put(var, val);
         }
-        sendCommandResponse("ok\n");        
+        sendCommandResponse("ok\n");
     }
-    
-    private void debugStack() {
+
+    void debugStack(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
+
         StringBuffer result = new StringBuffer();
-        for (Frame frame : fFrames) {
+        for (Frame frame : thread.fFrames) {
             result.append(printFrame(frame));
             result.append('#');
         }
-        result.append(printFrame(fCurrentFrame));
+        result.append(printFrame(thread.fCurrentFrame));
         result.append('\n');
         sendCommandResponse(result.toString());
     }
 
-
     /**
-     * The stack frame output is:
-     * frame # frame # frame ...
-     * where each frame is:
+     * The stack frame output is: frame # frame # frame ... where each frame is:
      * filename | line number | function name | var | var | var | var ...
      */
     private String printFrame(Frame frame) {
@@ -649,161 +837,288 @@ public class PDAVirtualMachine {
         return buf.toString();
     }
 
-    private void debugStep() {
-        // set suspend to 0 to allow the debug loop to exit back to
-        // the instruction loop and thus run an instruction. However,
-        // we want to come back to the debug loop right away, so the
-        // step flag is set to true which will cause the suspend flag
-        // to get set to true when we get to the next instruction.
-        fStep = true;
-        fSuspend = null;
-        sendCommandResponse("ok\n");        
+    void debugState(Args args) {
+        PDAThread thread = args.getThreadArg();
+        String response = null;
+        if (thread == null) {
+            response = fSuspendVM == null ? "running" : fSuspendVM;
+        } else if (fSuspendVM != null) {
+            response = "vm";
+        } else {
+            response = thread.fSuspend == null ? "running" : thread.fSuspend;
+        }
+        sendCommandResponse(response + "\n");
+    }
+    
+    void debugStep(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        } 
+
+        // Set suspend to null to allow the debug loop to exit back to the 
+        // instruction loop and thus run an instruction. However, we want to 
+        // come back to the debug loop right away, so the step flag is set to 
+        // true which will cause the suspend flag to get set to true when we 
+        // get to the next instruction.
+        if (fSuspendVM != null) {
+            // All threads are suspended, so suspend all threads again when 
+            // step completes.
+            fSuspendVM = null;
+            fStepVM = true;
+            // Also mark the thread that initiated the step to mark it as
+            // the triggering thread when suspending.
+            thread.fStep = true;
+        } else {
+            if (thread.fSuspend == null) {
+                sendCommandResponse("error: thread already running\n");
+                return;
+            }
+            thread.fSuspend = null;
+            thread.fStep = true;
+            sendDebugEvent("resumed " + thread.fID + " step", false);
+        }
+        sendCommandResponse("ok\n");
     }
 
-    private void debugStepReturn() {
-        fStepReturn = true;
-        fSuspend = null;
-        sendCommandResponse("ok\n");        
+    void debugStepReturn(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        } 
+        
+        if (fSuspendVM != null) {
+            fSuspendVM = null;
+            fStepReturnVM = true;
+            thread.fStepReturn = true;
+        } else {
+            if (thread.fSuspend == null) {
+                sendCommandResponse("error: thread running\n");
+                return;
+            }
+            thread.fSuspend = null;
+            thread.fStepReturn = true;
+            sendDebugEvent("resumed " + thread.fID + " step", false);
+        }
+        sendCommandResponse("ok\n");
     }
-    
-    private void debugSuspend() {
-        fSuspend = "client";
-        sendCommandResponse("ok\n");        
+
+    void debugSuspend(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        } 
+        if (fSuspendVM != null) {
+            sendCommandResponse("error: vm already suspended\n");
+            return;
+        }
+        if (thread.fSuspend != null) {
+            sendCommandResponse("error: thread already suspended\n");
+            return;
+        } 
+        
+        thread.fSuspend = "client";
+        sendDebugEvent("suspended " + thread.fID + " client", false);
+        sendCommandResponse("ok\n");
     }
-    
-    private void debugVar(Args args) {
+
+    void debugThreads() {
+        StringBuffer response = new StringBuffer();
+        for (int threadId : fThreads.keySet()) {
+            response.append(threadId);
+            response.append(' ');
+        }
+        sendCommandResponse(response.toString().trim() + "\n");
+    }
+
+    void debugVar(Args args) {
+        PDAThread thread = args.getThreadArg();
+        if (thread == null) {
+            sendCommandResponse("error: invalid thread\n");
+            return;
+        }
+
         int sfnumber = args.getNextIntArg();
         String var = args.getNextStringArg();
 
-        if (sfnumber >= fFrames.size()) {
-            sendCommandResponse(fCurrentFrame.get(var).toString() + "\n");
+        Frame frame = sfnumber >= thread.fFrames.size()    
+            ? thread.fCurrentFrame : thread.fFrames.get(sfnumber);
+        
+        Object val = frame.get(var);
+        if (val == null) {
+            sendCommandResponse("error: variable undefined\n");
         } else {
-            sendCommandResponse(fFrames.get(sfnumber).get(var).toString() + "\n");
+            sendCommandResponse(val.toString() + "\n");
         }
     }
-    
-    private void debugWatch(Args args) {
+
+    void debugVMResume() {
+        if (fSuspendVM == null) {
+            sendCommandResponse("error: vm already running\n");
+            return;
+        } 
+
+        fSuspendVM = null;
+        sendCommandResponse("ok\n");
+    }
+
+    void debugVMSuspend() {
+        if (fSuspendVM != null) {
+            sendCommandResponse("error: vm already suspended\n");
+            return;
+        }
+
+        fSuspendVM = "client";
+        sendCommandResponse("ok\n");
+    }
+
+    void debugWatch(Args args) {
         String funcAndVar = args.getNextStringArg();
         int flags = args.getNextIntArg();
         fWatchpoints.put(funcAndVar, flags);
-        sendCommandResponse("ok\n");        
+        sendCommandResponse("ok\n");
     }
 
-    private void iAdd(Args args) {
-        Object val1 = fStack.pop();
-        Object val2 = fStack.pop();
+    void iAdd(PDAThread thread, Args args) {
+        Object val1 = thread.fStack.pop();
+        Object val2 = thread.fStack.pop();
         if (val1 instanceof Integer && val2 instanceof Integer) {
-            int intVal1 = ((Integer)val1).intValue();
-            int intVal2 = ((Integer)val2).intValue();
-            fStack.push(intVal1 + intVal2);
+            int intVal1 = ((Integer) val1).intValue();
+            int intVal2 = ((Integer) val2).intValue();
+            thread.fStack.push(intVal1 + intVal2);
         } else {
-            fStack.push(-1);
+            thread.fStack.push(-1);
         }
     }
 
-    private void iBranchNotZero(Args args) {
-        Object val = fStack.pop();
-        if( val instanceof Integer && ((Integer)val).intValue() != 0 ) {
+    void iBranchNotZero(PDAThread thread, Args args) {
+        Object val = thread.fStack.pop();
+        if (val instanceof Integer && ((Integer) val).intValue() != 0) {
             String label = args.getNextStringArg();
-            if (fLabels.containsKey(label)) {
-                fCurrentFrame.fPC = fLabels.get(label);
+            if (thread.fThreadLabels.containsKey(label)) {
+                thread.fCurrentFrame.fPC = thread.fThreadLabels.get(label);
             } else {
                 sendDebugEvent("no such label " + label, true);
-                if( fEventStops.get("nosuchlabel") ) {
-                    fSuspend = "event nosuchlabel";
-                    fStack.push(val);
-                    fCurrentFrame.fPC--;
+                if (fEventStops.get("nosuchlabel")) {
+                    fSuspendVM = thread.fID + " event nosuchlabel";
+                    thread.fStack.push(val);
+                    thread.fCurrentFrame.fPC--;
                 }
-            } 
+            }
         }
     }
 
-    private void iCall(Args args) {
+    void iCall(PDAThread thread, Args args) {
         String label = args.getNextStringArg();
-        if (fLabels.containsKey(label)) {
-            fFrames.add(fCurrentFrame);
-            fCurrentFrame = new Frame(label, fLabels.get(label));
+        if (thread.fThreadLabels.containsKey(label)) {
+            thread.fFrames.add(thread.fCurrentFrame);
+            thread.fCurrentFrame = new Frame(label, thread.fThreadLabels.get(label));
         } else {
             sendDebugEvent("no such label " + label, true);
-            if( fEventStops.get("nosuchlabel") ) {
-                fSuspend = "event nosuchlabel";
-                fCurrentFrame.fPC--;
+            if (fEventStops.get("nosuchlabel")) {
+                fSuspendVM = thread.fID + " event nosuchlabel";
+                thread.fCurrentFrame.fPC--;
             }
-        } 
+        }
     }
 
-    private void iDec(Args args) {
-        Object val = fStack.pop();
+    void iDec(PDAThread thread, Args args) {
+        Object val = thread.fStack.pop();
         if (val instanceof Integer) {
-            val = new Integer( ((Integer)val).intValue() - 1 );
+            val = new Integer(((Integer) val).intValue() - 1);
         }
-        fStack.push(val);
-    }        
+        thread.fStack.push(val);
+    }
 
-    private void iDup(Args args) {
-        Object val = fStack.pop();
-        fStack.push(val);
-        fStack.push(val);
-    }        
+    void iDup(PDAThread thread, Args args) {
+        Object val = thread.fStack.pop();
+        thread.fStack.push(val);
+        thread.fStack.push(val);
+    }
+    
+    void iExec(PDAThread thread, Args args) {
+        String label = args.getNextStringArg();
+        if (fLabels.containsKey(label)) {
+            int id = fNextThreadId++;
+            fThreads.put(id, new PDAThread(id, label, fLabels.get(label)));
+            sendDebugEvent("started " + id, false);
+        } else {
+            sendDebugEvent("no such label " + label, true);
+            if (fEventStops.get("nosuchlabel")) {
+                thread.fSuspend = "event nosuchlabel";
+                thread.fCurrentFrame.fPC--;
+            }
+        }
+    }
 
-    private void iHalt(Args args) {
-        fRun = false;
-    }        
+    void iHalt(PDAThread thread, Args args) {
+        thread.fRun = false;
+    }
 
-    private void iOutput(Args args) {
-        System.out.println(fStack.pop());
-    }        
+    void iOutput(PDAThread thread, Args args) {
+        System.out.println(thread.fStack.pop());
+    }
 
-    private void iPop(Args args) {
+    void iPop(PDAThread thread, Args args) {
         String arg = args.getNextStringArg();
         if (arg.startsWith("$")) {
             String var = arg.substring(1);
-            fCurrentFrame.put(var, fStack.pop());
-            String key = fCurrentFrame.fFunction + "::" + var;
+            thread.fCurrentFrame.put(var, thread.fStack.pop());
+            String key = thread.fCurrentFrame.fFunction + "::" + var;
             if (fWatchpoints.containsKey(key) && (fWatchpoints.get(key) & 2) != 0) {
-                fSuspend = "watch write " + key;
+                fSuspendVM = thread.fID + " watch write " + key;
             }
         } else {
-            fStack.pop();
+            thread.fStack.pop();
         }
-    }        
+    }
 
-    private void iPush(Args args) {
+    void iPush(PDAThread thread, Args args) {
         String arg = args.getNextStringArg();
         if (arg.startsWith("$")) {
             String var = arg.substring(1);
-            Object val = fCurrentFrame.containsKey(var) ? fCurrentFrame.get(var) : "<undefined>";
-            fStack.push(val);
-            String key = fCurrentFrame.fFunction + "::" + var;
+            Object val = thread.fCurrentFrame.containsKey(var) ? thread.fCurrentFrame.get(var) : "<undefined>";
+            thread.fStack.push(val);
+            String key = thread.fCurrentFrame.fFunction + "::" + var;
             if (fWatchpoints.containsKey(key) && (fWatchpoints.get(key) & 1) != 0) {
-                fSuspend = "watch read " + key;
+                fSuspendVM = thread.fID + " watch read " + key;
             }
         } else {
             Object val = arg;
             try {
                 val = Integer.parseInt(arg);
-            } catch (NumberFormatException e) {}
-            fStack.push(val);                    
+            } catch (NumberFormatException e) {
+            }
+            thread.fStack.push(val);
         }
-    }        
-    private void iReturn(Args args) {
-        if (!fFrames.isEmpty()) {
-            fCurrentFrame = fFrames.remove(fFrames.size() - 1);
-        } 
     }
-    private void iVar(Args args) {
-        String var = args.getNextStringArg();
-        fCurrentFrame.put(var, 0);
-    }        
 
-    private void iInternalEndEval(Args args) {
-        Object result = fStack.pop();
-        fCode = fSavedCode;
-        fLabels = fSavedLables;
-        fCurrentFrame.fPC = fSavedPC;
+    void iReturn(PDAThread thread, Args args) {
+        if (!thread.fFrames.isEmpty()) {
+            thread.fCurrentFrame = thread.fFrames.remove(thread.fFrames.size() - 1);
+        } else {
+            // Execution returned from the top frame, which means this thread
+            // should exit.
+            thread.fRun = false;
+        }
+    }
+
+    void iVar(PDAThread thread, Args args) {
+        String var = args.getNextStringArg();
+        thread.fCurrentFrame.put(var, 0);
+    }
+
+    void iInternalEndEval(PDAThread thread, Args args) {
+        Object result = thread.fStack.pop();
+        thread.fThreadCode = fCode;
+        thread.fThreadLabels = fLabels;
+        thread.fCurrentFrame.fPC = thread.fSavedPC;
         sendDebugEvent("evalresult " + result, false);
-        fSuspend = "eval";
-    }        
-    
-    
+        thread.fSuspend = "eval";
+        thread.fPerformingEval = false;
+    }
+
 }
diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda
index a9fcfc2a853..5aecdc5e6e0 100644
--- a/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda
+++ b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest3.pda
@@ -8,4 +8,6 @@ add
 call zippy
 add
 output
+push 1
+branch_not_zero swishy
 halt
diff --git a/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest9.pda b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest9.pda
new file mode 100644
index 00000000000..336a251d9ab
--- /dev/null
+++ b/plugins/org.eclipse.dd.examples.pda/pdavm/tests/vmtest9.pda
@@ -0,0 +1,23 @@
+push 5
+:thread_create
+exec foo
+dec 
+dup
+branch_not_zero thread_create
+push finished
+output 
+halt
+:foo
+push thread_created
+output
+call inner
+halt
+:inner
+var b
+call inner2
+push 2
+return
+:inner2
+var c
+push 3
+return
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java
index ec15010f9fc..1de0b2aa12f 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/launch/PDAServicesInitSequence.java
@@ -78,7 +78,7 @@ public class PDAServicesInitSequence extends Sequence {
                 bpmService.initialize(new RequestMonitor(getExecutor(), requestMonitor) {
                     @Override
                     protected void handleSuccess() {
-                        bpmService.startTrackingBreakpoints(fCommandControl.getProgramDMContext(), requestMonitor);
+                        bpmService.startTrackingBreakpoints(fCommandControl.getVirtualMachineDMContext(), requestMonitor);
                     }
                 }); 
             }
@@ -107,7 +107,7 @@ public class PDAServicesInitSequence extends Sequence {
         new Step() { 
             @Override
             public void execute(RequestMonitor requestMonitor) {
-                fRunControl.resume(fCommandControl.getProgramDMContext(), requestMonitor);
+                fRunControl.resume(fCommandControl.getVirtualMachineDMContext(), requestMonitor);
             }
         },
     };
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java
index 01f3259de65..a98a5686a06 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDABreakpoints.java
@@ -51,7 +51,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
 
         final Integer fLine;
 
-        public BreakpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, Integer line) {
+        public BreakpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, Integer line) {
             super(sessionId, new IDMContext[] { commandControlCtx });
             fLine = line;
         }
@@ -81,7 +81,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         final String fFunction;
         final String fVariable; 
 
-        public WatchpointDMContext(String sessionId, PDAProgramDMContext commandControlCtx, String function, 
+        public WatchpointDMContext(String sessionId, PDAVirtualMachineDMContext commandControlCtx, String function, 
             String variable) 
         {
             super(sessionId, new IDMContext[] { commandControlCtx });
@@ -164,7 +164,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
 
     public void getBreakpoints(final IBreakpointsTargetDMContext context, final DataRequestMonitor<IBreakpointDMContext[]> rm) {
         // Validate the context
-        if (!fCommandControl.getProgramDMContext().equals(context)) {
+        if (!fCommandControl.getVirtualMachineDMContext().equals(context)) {
             PDAPlugin.failRequest(rm, INVALID_HANDLE, "Invalid breakpoints target context");
             return;
         }
@@ -193,7 +193,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
                 // breakpoints mediator, which was called with the program context
                 // in the services initialization sequence.  So checking if 
                 // programCtx != null is mostly a formality.
-                PDAProgramDMContext programCtx = DMContexts.getAncestorOfType(context, PDAProgramDMContext.class);
+                PDAVirtualMachineDMContext programCtx = DMContexts.getAncestorOfType(context, PDAVirtualMachineDMContext.class);
                 if (programCtx != null) {
                     doInsertBreakpoint(programCtx, attributes, rm);
                 } else {
@@ -209,7 +209,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         }
     }
 
-    private void doInsertBreakpoint(PDAProgramDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm) 
+    private void doInsertBreakpoint(PDAVirtualMachineDMContext programCtx, final Map<String, Object> attributes, final DataRequestMonitor<IBreakpointDMContext> rm) 
     {
         // Compare the program path in the breakpoint with the path in the PDA 
         // program context. Only insert the breakpoint if the program matches. 
@@ -230,7 +230,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         // installed already. PDA can only track a single breakpoint at a 
         // given line, attempting to set the second breakpoint should fail.
         final BreakpointDMContext breakpointCtx = 
-            new BreakpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), line);
+            new BreakpointDMContext(getSession().getId(), fCommandControl.getVirtualMachineDMContext(), line);
         if (fBreakpoints.contains(breakpointCtx)) {
             PDAPlugin.failRequest(rm, REQUEST_FAILED, "Breakpoint already set");
             return;
@@ -244,7 +244,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         // still being processed here.
         fBreakpoints.add(breakpointCtx);
         fCommandControl.queueCommand(
-            new PDASetBreakpointCommand(fCommandControl.getProgramDMContext(), line), 
+            new PDASetBreakpointCommand(fCommandControl.getVirtualMachineDMContext(), line, false), 
             new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
                 @Override
                 protected void handleSuccess() {
@@ -286,7 +286,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         // installed already. PDA can only track a single watchpoint for a given
         // function::variable, attempting to set the second breakpoint should fail.
         final WatchpointDMContext watchpointCtx = 
-            new WatchpointDMContext(getSession().getId(), fCommandControl.getProgramDMContext(), function, variable);
+            new WatchpointDMContext(getSession().getId(), fCommandControl.getVirtualMachineDMContext(), function, variable);
         if (fBreakpoints.contains(watchpointCtx)) {
             PDAPlugin.failRequest(rm, REQUEST_FAILED, "Watchpoint already set");
             return;
@@ -310,7 +310,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         // still being processed here.
         fBreakpoints.add(watchpointCtx);
         fCommandControl.queueCommand(
-            new PDAWatchCommand(fCommandControl.getProgramDMContext(), function, variable, watchOperation), 
+            new PDAWatchCommand(fCommandControl.getVirtualMachineDMContext(), function, variable, watchOperation), 
             new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
                 @Override
                 protected void handleSuccess() {
@@ -350,7 +350,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         fBreakpoints.remove(bpCtx);
 
         fCommandControl.queueCommand(
-            new PDAClearBreakpointCommand(fCommandControl.getProgramDMContext(), bpCtx.fLine), 
+            new PDAClearBreakpointCommand(fCommandControl.getVirtualMachineDMContext(), bpCtx.fLine), 
             new DataRequestMonitor<PDACommandResult>(getExecutor(), rm));        
     }
 
@@ -360,7 +360,7 @@ public class PDABreakpoints extends AbstractDsfService implements IBreakpoints
         // Watchpoints are cleared using the same command, but with a "no watch" operation
         fCommandControl.queueCommand(
             new PDAWatchCommand(
-                fCommandControl.getProgramDMContext(), bpCtx.fFunction, bpCtx.fVariable, PDAWatchCommand.WatchOperation.NONE), 
+                fCommandControl.getVirtualMachineDMContext(), bpCtx.fFunction, bpCtx.fVariable, PDAWatchCommand.WatchOperation.NONE), 
                 new DataRequestMonitor<PDACommandResult>(getExecutor(), rm));        
     }
 
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java
index f2089254e58..b4121dc4799 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDACommandControl.java
@@ -89,7 +89,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
     private boolean fTerminated = false;
     
     //  Data Model context of this command control. 
-    private PDAProgramDMContext fDMContext;
+    private PDAVirtualMachineDMContext fDMContext;
 
     // Synchronous listeners for commands and events.
     private final List<ICommandListener> fCommandListeners = new ArrayList<ICommandListener>();
@@ -137,12 +137,12 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
 
     private void doInitialize(final RequestMonitor rm) {
         // Create the control's data model context.
-        fDMContext = new PDAProgramDMContext(getSession().getId(), fProgram);
+        fDMContext = new PDAVirtualMachineDMContext(getSession().getId(), fProgram);
 
         // Add a listener for PDA events to track the started/terminated state.
         addEventListener(new IEventListener() {
             public void eventReceived(Object output) {
-                if ("started".equals(output)) {
+                if ("started 1".equals(output)) {
                     setStarted();
                 } else if ("terminated".equals(output)) {
                     setTerminated();
@@ -247,7 +247,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
         @Override
         protected IStatus run(IProgressMonitor monitor) {
             while (!isTerminated()) {
-                synchronized(fTxCommands) {
+                synchronized (fTxCommands) {
                     try {
                         // Remove command from send queue.
                         final CommandHandle commandHandle = fTxCommands.take();
@@ -483,10 +483,10 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
     
     /**
      * Return the PDA Debugger top-level Data Model context. 
-     * @see PDAProgramDMContext
+     * @see PDAVirtualMachineDMContext
      */
     @ThreadSafe
-    public PDAProgramDMContext getProgramDMContext() {
+    public PDAVirtualMachineDMContext getVirtualMachineDMContext() {
         return fDMContext;
     }
 
@@ -498,7 +498,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
         processQueues();
 
         // Issue a data model event.
-        getSession().dispatchEvent(new PDAStartedEvent(getProgramDMContext()), getProperties());
+        getSession().dispatchEvent(new PDAStartedEvent(getVirtualMachineDMContext()), getProperties());
     }
     
     /**
@@ -520,7 +520,7 @@ public class PDACommandControl extends AbstractDsfService implements ICommandCon
             processQueues();
             
             // Issue a data model event.
-            getSession().dispatchEvent(new PDATerminatedEvent(getProgramDMContext()), getProperties());
+            getSession().dispatchEvent(new PDATerminatedEvent(getVirtualMachineDMContext()), getProperties());
         }
     }
 
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java
index 29fbfa38061..5d6be6e8da2 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAExpressions.java
@@ -214,11 +214,12 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
         // Create an expression based on the given context and string expression.  
         // The PDA debugger can only evaluate variables as expressions and only
         // in context of a frame.  
+        PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(ctx, PDAThreadDMContext.class);
         IFrameDMContext frameCtx = DMContexts.getAncestorOfType(ctx, IFrameDMContext.class);
-        if (frameCtx != null) {
+        if (threadCtx != null && frameCtx != null) {
             return new ExpressionDMContext(getSession().getId(), frameCtx, expression);
         } else {
-            // If a frame cannot be found in context, return an "invalid" 
+            // If the thread or a frame cannot be found in context, return an "invalid" 
             // expression context, because a null return value is not allowed.
             // Evaluating an invalid expression context will always yield an 
             // error.
@@ -276,6 +277,7 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
     {
         final ExpressionDMContext exprCtx = DMContexts.getAncestorOfType(formattedCtx, ExpressionDMContext.class);
         if (exprCtx != null) {
+            final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
             final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
             
             // First retrieve the stack depth, needed to properly calculate
@@ -290,7 +292,11 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
                         
                         // Send the command to evaluate the variable.
                         fCommandCache.execute(
-                            new PDAVarCommand(fCommandControl.getProgramDMContext(), frameId, exprCtx.getExpression()), 
+                            new PDAVarCommand(
+                                fCommandControl.getVirtualMachineDMContext(),
+                                threadCtx.getID(),
+                                frameId, 
+                                exprCtx.getExpression()), 
                             new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
                                 @Override
                                 protected void handleSuccess() {
@@ -310,6 +316,7 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
         final RequestMonitor rm) 
     {
         if (exprCtx instanceof ExpressionDMContext) {
+            final PDAThreadDMContext threadCtx = DMContexts.getAncestorOfType(exprCtx, PDAThreadDMContext.class);
             final IFrameDMContext frameCtx = DMContexts.getAncestorOfType(exprCtx, IFrameDMContext.class);
             
             // Similarly to retrieving the variable, retrieve the 
@@ -324,7 +331,12 @@ public class PDAExpressions extends AbstractDsfService implements IExpressions {
                         
                         // Send the "write" command to PDA debugger
                         fCommandCache.execute(
-                            new PDASetVarCommand(fCommandControl.getProgramDMContext(), frameId, exprCtx.getExpression(), exprValue), 
+                            new PDASetVarCommand(
+                                fCommandControl.getVirtualMachineDMContext(), 
+                                threadCtx.getID(), 
+                                frameId, 
+                                exprCtx.getExpression(), 
+                                exprValue), 
                             new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
                                 @Override
                                 protected void handleSuccess() {
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java
index df4bb44007e..08944cfa3a1 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARegisters.java
@@ -101,7 +101,7 @@ public class PDARegisters extends AbstractDsfService implements IRegisters {
      * @see org.eclipse.dd.dsf.debug.service.IRegisters#getRegisterGroups(org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext, org.eclipse.dd.dsf.debug.service.IStack.IFrameDMContext, org.eclipse.dd.dsf.concurrent.DataRequestMonitor)
      */
     public void getRegisterGroups(IDMContext ctx, DataRequestMonitor<IRegisterGroupDMContext[]> rm ) {
-    	PDAProgramDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAProgramDMContext.class);
+    	PDAVirtualMachineDMContext execDmc = DMContexts.getAncestorOfType(ctx, PDAVirtualMachineDMContext.class);
         if (execDmc == null) {
             rm.setStatus( new Status( IStatus.ERROR , PDAPlugin.PLUGIN_ID , INVALID_HANDLE , "Container context not found", null ) ) ;   //$NON-NLS-1$
             rm.done();
@@ -738,7 +738,7 @@ public class PDARegisters extends AbstractDsfService implements IRegisters {
         private int fGroupNo;
         private String fGroupName;
 
-        public MIRegisterGroupDMC(PDARegisters service, PDAProgramDMContext execDmc, int groupNo, String groupName) {
+        public MIRegisterGroupDMC(PDARegisters service, PDAVirtualMachineDMContext execDmc, int groupNo, String groupName) {
             super(service.getSession().getId(), new IDMContext[] { execDmc });
             fGroupNo = groupNo;
             fGroupName = groupName;
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java
index 75efec10170..01102212817 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDARunControl.java
@@ -11,7 +11,11 @@
  *******************************************************************************/
 package org.eclipse.dd.examples.pda.service;
 
+import java.util.Arrays;
 import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
 
 import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
 import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
@@ -26,10 +30,13 @@ import org.eclipse.dd.dsf.service.AbstractDsfService;
 import org.eclipse.dd.dsf.service.DsfServiceEventHandler;
 import org.eclipse.dd.dsf.service.DsfSession;
 import org.eclipse.dd.examples.pda.PDAPlugin;
+import org.eclipse.dd.examples.pda.service.commands.AbstractPDACommand;
 import org.eclipse.dd.examples.pda.service.commands.PDACommandResult;
 import org.eclipse.dd.examples.pda.service.commands.PDAResumeCommand;
 import org.eclipse.dd.examples.pda.service.commands.PDAStepCommand;
-import org.eclipse.dd.examples.pda.service.commands.PDASuspendCommand;
+import org.eclipse.dd.examples.pda.service.commands.PDAStepReturnCommand;
+import org.eclipse.dd.examples.pda.service.commands.PDAVMResumeCommand;
+import org.eclipse.dd.examples.pda.service.commands.PDAVMSuspendCommand;
 import org.osgi.framework.BundleContext;
 
 
@@ -55,7 +62,112 @@ public class PDARunControl extends AbstractDsfService
     // The purpose of this pattern is to allow clients that listen to service 
     // events and track service state, to be perfectly in sync with the service
     // state.
+
+    static final private IExecutionDMContext[] EMPTY_TRIGGERING_CONTEXTS_ARRAY = new IExecutionDMContext[0];  
+
+    @Immutable 
+    private static class ThreadResumedEvent extends AbstractDMEvent<IExecutionDMContext> 
+        implements IResumedDMEvent
+    {
+        private final StateChangeReason fReason;
+
+        ThreadResumedEvent(PDAThreadDMContext ctx, StateChangeReason reason) { 
+            super(ctx);
+            fReason = reason;
+        }
+        
+        public StateChangeReason getReason() {
+            return fReason;
+        }
+        
+        @Override
+        public String toString() {
+            return "THREAD RESUMED: " + getDMContext() + " (" + fReason + ")"; 
+        }
+    }
     
+    @Immutable 
+    private static class VMResumedEvent extends AbstractDMEvent<IExecutionDMContext> 
+        implements IContainerResumedDMEvent
+    {
+        private final StateChangeReason fReason;
+        
+        VMResumedEvent(PDAVirtualMachineDMContext ctx, StateChangeReason reason) { 
+            super(ctx);
+            fReason = reason;
+        }
+
+        public StateChangeReason getReason() {
+            return fReason;
+        }
+
+        public IExecutionDMContext[] getTriggeringContexts() {
+            return EMPTY_TRIGGERING_CONTEXTS_ARRAY;
+        }
+        
+        @Override
+        public String toString() {
+            return "VM RESUMED: (" + fReason + ")"; 
+        }
+    }
+    
+    @Immutable
+    private static class ThreadSuspendedEvent extends AbstractDMEvent<IExecutionDMContext> 
+        implements ISuspendedDMEvent
+    {
+        private final StateChangeReason fReason;
+
+        ThreadSuspendedEvent(PDAThreadDMContext ctx, StateChangeReason reason) { 
+            super(ctx);
+            fReason = reason;
+        }
+        
+        public StateChangeReason getReason() {
+            return fReason;
+        }
+
+        @Override
+        public String toString() {
+            return "THREAD SUSPENDED: " + getDMContext() + " (" + fReason + ")"; 
+        }
+    }
+    
+    @Immutable 
+    private static class VMSuspendedEvent extends AbstractDMEvent<IExecutionDMContext> 
+        implements IContainerSuspendedDMEvent
+    {
+        private final StateChangeReason fReason;
+
+        final private IExecutionDMContext[] fTriggeringThreads;  
+        
+        VMSuspendedEvent(PDAVirtualMachineDMContext ctx, PDAThreadDMContext threadCtx, StateChangeReason reason) { 
+            super(ctx);
+            fReason = reason;
+            if (threadCtx != null) {
+                fTriggeringThreads = new IExecutionDMContext[] { threadCtx };
+            } else {
+                fTriggeringThreads = EMPTY_TRIGGERING_CONTEXTS_ARRAY;
+            }
+        }
+    
+        public StateChangeReason getReason() {
+            return fReason;
+        }
+
+        public IExecutionDMContext[] getTriggeringContexts() {
+            return fTriggeringThreads;
+        }
+
+
+        @Override
+        public String toString() {
+            return "THREAD SUSPENDED: " + getDMContext() + 
+                " (" + fReason + 
+                ", trigger = " + Arrays.asList(fTriggeringThreads) +
+                ")"; 
+        }
+    }
+
     @Immutable 
     private static class ExecutionDMData implements IExecutionDMData {
         private final StateChangeReason fReason;
@@ -65,62 +177,63 @@ public class PDARunControl extends AbstractDsfService
         public StateChangeReason getStateChangeReason() { return fReason; }
     }
     
-    @Immutable 
-    private static class ResumedEvent extends AbstractDMEvent<IExecutionDMContext> 
-        implements IResumedDMEvent
+    private static class ThreadStartedEvent extends AbstractDMEvent<IExecutionDMContext> 
+        implements IStartedDMEvent 
     {
-        private final String fPDAEvent;
-
-        ResumedEvent(IExecutionDMContext ctx, String pdaEvent) { 
-            super(ctx);
-            fPDAEvent = pdaEvent;
-        }
-        
-        public StateChangeReason getReason() {
-            if (fPDAEvent.startsWith("resumed breakpoint") || fPDAEvent.startsWith("suspended watch")) {
-                return StateChangeReason.BREAKPOINT;
-            } else if (fPDAEvent.equals("resumed step") || fPDAEvent.equals("resumed drop")) {
-                return StateChangeReason.STEP;
-            } else if (fPDAEvent.equals("resumed client")) {
-                return StateChangeReason.USER_REQUEST;
-            } else {
-                return StateChangeReason.UNKNOWN;
-            } 
+        ThreadStartedEvent(PDAThreadDMContext threadCtx) {
+            super(threadCtx);
         }
     }
     
-    @Immutable
-    private static class SuspendedEvent extends AbstractDMEvent<IExecutionDMContext> 
-        implements ISuspendedDMEvent
+    private static class ThreadExitedEvent extends AbstractDMEvent<IExecutionDMContext> 
+        implements IExitedDMEvent 
     {
-        private final String fPDAEvent;
-        
-        SuspendedEvent(IExecutionDMContext ctx, String pdaEvent) { 
-            super(ctx);
-            fPDAEvent = pdaEvent;
-        }
-        
-        public StateChangeReason getReason() {
-            if (fPDAEvent.startsWith("suspended breakpoint") || fPDAEvent.startsWith("suspended watch")) {
-                return StateChangeReason.BREAKPOINT;
-            } else if (fPDAEvent.equals("suspended step") || fPDAEvent.equals("suspended drop")) {
-                return StateChangeReason.STEP;
-            } else if (fPDAEvent.equals("suspended client")) {
-                return StateChangeReason.USER_REQUEST;
-            } else {
-                return StateChangeReason.UNKNOWN;
-            } 
+        ThreadExitedEvent(PDAThreadDMContext threadCtx) {
+            super(threadCtx);
         }
     }
-
+    
     // Services 
     private PDACommandControl fCommandControl;
-    
-    // State flags
-	private boolean fSuspended = true;
-    private boolean fResumePending = false;
-	private boolean fStepping = false;
-	private StateChangeReason fStateChangeReason;
+
+    // Reference to the virtual machine data model context
+    private PDAVirtualMachineDMContext fDMContext;
+
+    // VM state flags
+	private boolean fVMSuspended = true;
+    private boolean fVMResumePending = false;
+    private boolean fVMSuspendPending = false;
+	private boolean fVMStepping = false;
+	private StateChangeReason fVMStateChangeReason;
+	
+	// Threads' state data 
+    private static class ThreadInfo {
+        final PDAThreadDMContext fContext;
+        boolean fSuspended = false;
+        boolean fResumePending = false;
+        boolean fSuspendPending = false;
+        boolean fStepping = false;
+        StateChangeReason fStateChangeReason = StateChangeReason.UNKNOWN;        
+
+        ThreadInfo(PDAThreadDMContext context) {
+            fContext = context;
+        }
+        
+        @Override
+        public String toString() {
+            return fContext.toString() + " (" +
+                (fSuspended ? "SUSPENDED, " : "SUSPENDED, ") +
+                fStateChangeReason + 
+                (fResumePending ? ", RESUME_PENDING, " : "") +
+                (fSuspendPending ? ", SUSPEND_PENDING, " : "") +
+                (fStepping ? ", SUSPEND_PENDING, " : "") +
+                ")";
+            		
+        }
+    }
+
+	private Map<Integer,  ThreadInfo> fThreads = new LinkedHashMap<Integer,  ThreadInfo>();
+	
 	
     public PDARunControl(DsfSession session) {
         super(session);
@@ -142,14 +255,21 @@ public class PDARunControl extends AbstractDsfService
     }
 
     private void doInitialize(final RequestMonitor rm) {
+        // Cache a reference to the command control and the virtual machine context
         fCommandControl = getServicesTracker().getService(PDACommandControl.class);
+        fDMContext = fCommandControl.getVirtualMachineDMContext();
 
-        // Add ourselves as a listener to PDA events, to catch suspended/resumed 
-        // events.
+        // Create the main thread context.
+        fThreads.put(
+            1,
+            new ThreadInfo(new PDAThreadDMContext(getSession().getId(), fDMContext, 1)));
+
+        // Add the run control service as a listener to PDA events, to catch 
+        // suspended/resumed/started/exited events from the command control.
         fCommandControl.addEventListener(this);
         
-        // Add ourselves as a listener to service events, in order to process
-        // our own suspended/resumed events.
+        // Add the run control service as a listener to service events as well, 
+        // in order to process our own suspended/resumed/started/exited events.
         getSession().addServiceEventListener(this, null);
         
         // Register the service with OSGi
@@ -182,42 +302,137 @@ public class PDARunControl extends AbstractDsfService
         if (!(output instanceof String)) return;
         String event = (String)output;
         
+        int nameEnd = event.indexOf(' ');
+        nameEnd = nameEnd == -1 ? event.length() : nameEnd;
+        String eventName = event.substring(0, nameEnd);
+        
+        PDAThreadDMContext thread = null;
+        StateChangeReason reason = StateChangeReason.UNKNOWN;
+        if (event.length() > nameEnd + 1) {
+            if ( Character.isDigit(event.charAt(nameEnd + 1)) ) {
+                int threadIdEnd = event.indexOf(' ', nameEnd + 1);
+                threadIdEnd = threadIdEnd == -1 ? event.length() : threadIdEnd;
+                try {
+                    int threadId = Integer.parseInt(event.substring(nameEnd + 1, threadIdEnd));
+                    if (fThreads.containsKey(threadId)) {
+                        thread = fThreads.get(threadId).fContext;
+                    } else {
+                        // In case where a suspended event follows directly a 
+                        // started event, a thread may not be in the list of 
+                        // known threads yet.  In this case create the
+                        // thread context based on the ID.
+                        thread = new PDAThreadDMContext(getSession().getId(), fDMContext, threadId);
+                    }
+                } catch (NumberFormatException e) {}
+                if (threadIdEnd + 1 < event.length()) {
+                    reason = parseStateChangeReason(event.substring(threadIdEnd + 1));
+                }
+            } else {
+                reason = parseStateChangeReason(event.substring(nameEnd + 1));
+            }
+        }
+        
         // Handle PDA debugger suspended/resumed events and issue the 
         // corresponding Data Model events.  Do not update the state
         // information until we start dispatching the service events.
-        if (event.startsWith("suspended")) {
-            IDMEvent<?> dmEvent = new SuspendedEvent(fCommandControl.getProgramDMContext(), event);
-            getSession().dispatchEvent(dmEvent, getProperties());
-        } else if (event.startsWith("resumed")) {
-            IDMEvent<?> dmEvent = new ResumedEvent(fCommandControl.getProgramDMContext(), event);
+        IDMEvent<?> dmEvent = null;
+        if (eventName.equals("suspended") && thread != null) {
+            dmEvent = new ThreadSuspendedEvent(thread, reason);
+        } else if (eventName.equals("resumed") && thread != null) {
+            dmEvent = new ThreadResumedEvent(thread, reason);
+        } else if (event.startsWith("vmsuspended")) {
+            dmEvent = new VMSuspendedEvent(fDMContext, thread, reason);
+        } else if (event.startsWith("vmresumed")) {
+            dmEvent = new VMResumedEvent(fDMContext, reason);
+        } else if (event.startsWith("started") && thread != null) {
+            dmEvent = new ThreadStartedEvent(thread);
+        } else if (event.startsWith("exited") && thread != null) {
+            dmEvent = new ThreadExitedEvent(thread);
+        }
+        
+        if (dmEvent != null) {
             getSession().dispatchEvent(dmEvent, getProperties());
         }
     }
     
+    private StateChangeReason parseStateChangeReason(String reasonString) {
+        if (reasonString.startsWith("breakpoint") || reasonString.startsWith("watch")) {
+            return StateChangeReason.BREAKPOINT;
+        } else if (reasonString.equals("step") || reasonString.equals("drop")) {
+            return StateChangeReason.STEP;
+        } else if (reasonString.equals("client")) {
+            return StateChangeReason.USER_REQUEST;
+        } else if (reasonString.startsWith("event")) {
+            return StateChangeReason.SIGNAL;
+        } else {
+            return StateChangeReason.UNKNOWN;
+        } 
+
+    }
     
     @DsfServiceEventHandler 
-    public void eventDispatched(ResumedEvent e) {
-        // This service should be the first to receive the ResumedEvent, 
-        // (before any other listeners are called).  Here, update the
-        // service state information based on the the resumed event.
-        fSuspended = false;
-        fResumePending = false;
-        fStateChangeReason = e.getReason();
-        fStepping = e.getReason().equals(StateChangeReason.STEP);
+    public void eventDispatched(ThreadResumedEvent e) {
+        ThreadInfo info = fThreads.get(((PDAThreadDMContext)e.getDMContext()).getID());
+        if (info != null) {
+            info.fSuspended = false;
+            info.fResumePending = false;
+            info.fStateChangeReason = e.getReason();
+            info.fStepping = e.getReason().equals(StateChangeReason.STEP);
+        }
     }    
 
 
     @DsfServiceEventHandler 
-    public void eventDispatched(SuspendedEvent e) {
-        // This service should be the first to receive the SuspendedEvent also, 
-        // (before any other listeners are called).  Here, update the
-        // service state information based on the the suspended event.
-        fStateChangeReason = e.getReason();
-        fResumePending = false;
-        fSuspended = true;
-        fStepping = false;
+    public void eventDispatched(VMResumedEvent e) {
+        fVMSuspended = false;
+        fVMResumePending = false;
+        fVMStateChangeReason = e.getReason();
+        fVMStepping = e.getReason().equals(StateChangeReason.STEP);
+        for (ThreadInfo info : fThreads.values()) {
+            info.fSuspended = false;
+            info.fStateChangeReason = StateChangeReason.CONTAINER;
+            info.fStepping = false;
+        }
+    }    
+
+    @DsfServiceEventHandler 
+    public void eventDispatched(ThreadSuspendedEvent e) {
+        ThreadInfo info = fThreads.get(((PDAThreadDMContext)e.getDMContext()).getID());
+        if (info != null) {
+            info.fSuspended = true;
+            info.fSuspendPending = false;
+            info.fStateChangeReason = e.getReason();
+            info.fStepping = e.getReason().equals(StateChangeReason.STEP);
+        }
     }
     
+
+    @DsfServiceEventHandler 
+    public void eventDispatched(VMSuspendedEvent e) {
+        fVMStateChangeReason = e.getReason();
+        fVMSuspendPending = false;
+        fVMSuspended = true;
+        fVMStepping = false;
+        List<IExecutionDMContext> triggeringContexts = Arrays.asList(e.getTriggeringContexts());
+        for (ThreadInfo info : fThreads.values()) {
+            info.fSuspended = true;
+            info.fStateChangeReason = triggeringContexts.contains(info.fContext) 
+                ? StateChangeReason.STEP : StateChangeReason.CONTAINER;
+            info.fStepping = false;
+        }        
+    }
+    
+    @DsfServiceEventHandler 
+    public void eventDispatched(ThreadStartedEvent e) {
+        PDAThreadDMContext threadCtx = (PDAThreadDMContext)e.getDMContext();
+        fThreads.put(threadCtx.getID(), new ThreadInfo(threadCtx));
+    }    
+    
+    @DsfServiceEventHandler 
+    public void eventDispatched(ThreadExitedEvent e) {
+        PDAThreadDMContext threadCtx = (PDAThreadDMContext)e.getDMContext();
+        fThreads.remove(threadCtx.getID());
+    }    
     
     public void canResume(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
         rm.setData(doCanResume(context));
@@ -225,7 +440,34 @@ public class PDARunControl extends AbstractDsfService
     }
     
     private boolean doCanResume(IExecutionDMContext context) {
-        return isSuspended(context) && !fResumePending;
+        if (context instanceof PDAThreadDMContext) {
+            PDAThreadDMContext threadContext = (PDAThreadDMContext)context; 
+            // Threads can be resumed only if the VM is not suspended.
+            if (!fVMSuspended) { 
+                ThreadInfo state = fThreads.get(threadContext.getID());
+                if (state != null) {
+                    return state.fSuspended && !state.fResumePending;
+                }
+            }
+        } else {
+            return fVMSuspended && !fVMResumePending;
+        }
+        return false;
+    }
+    
+    private boolean doCanStep(IExecutionDMContext context, StepType stepType) {
+        if (stepType == StepType.STEP_OVER || stepType == StepType.STEP_RETURN) {
+            if (context instanceof PDAThreadDMContext) {
+                PDAThreadDMContext threadContext = (PDAThreadDMContext)context; 
+                // Only threads can be stepped.  But they can be stepped
+                // while the VM is suspended or when just the thread is suspended.
+                ThreadInfo state = fThreads.get(threadContext.getID());
+                if (state != null) {
+                    return state.fSuspended && !state.fResumePending;
+                }
+            }
+        }
+        return false;        
     }
 
     public void canSuspend(IExecutionDMContext context, DataRequestMonitor<Boolean> rm) {
@@ -234,35 +476,86 @@ public class PDARunControl extends AbstractDsfService
     }
     
     private boolean doCanSuspend(IExecutionDMContext context) {
-        return !isSuspended(context);
+        if (context instanceof PDAThreadDMContext) {
+            PDAThreadDMContext threadContext = (PDAThreadDMContext)context; 
+            // Threads can be resumed only if the VM is not suspended.
+            if (!fVMSuspended) { 
+                ThreadInfo state = fThreads.get(threadContext.getID());
+                if (state != null) {
+                    return !state.fSuspended && state.fSuspendPending;
+                }
+            }
+        } else {
+            return !fVMSuspended && !fVMSuspendPending;
+        }
+        return false;
     }
 
 	public boolean isSuspended(IExecutionDMContext context) {
-		return fSuspended;
+        if (context instanceof PDAThreadDMContext) {
+            PDAThreadDMContext threadContext = (PDAThreadDMContext)context; 
+            // Threads can be resumed only if the VM is not suspended.
+            if (!fVMSuspended) { 
+                ThreadInfo state = fThreads.get(threadContext.getID());
+                if (state != null) {
+                    return state.fSuspended;
+                }
+            }
+        } 
+		return fVMSuspended;
 	}
 
 	public boolean isStepping(IExecutionDMContext context) {
-    	return !isSuspended(context) && fStepping;
+	    if (isSuspended(context)) {
+            if (context instanceof PDAThreadDMContext) {
+                PDAThreadDMContext threadContext = (PDAThreadDMContext)context; 
+                // Threads can be resumed only if the VM is not suspended.
+                if (!fVMStepping) { 
+                    ThreadInfo state = fThreads.get(threadContext.getID());
+                    if (state != null) {
+                        return state.fStepping;
+                    }
+                } 
+            } 
+            return fVMStepping;
+	    }
+	    return false;
     }
 
 	public void resume(IExecutionDMContext context, final RequestMonitor rm) {
 		assert context != null;
 
 		if (doCanResume(context)) { 
-            fResumePending = true;
-            fCommandControl.queueCommand(
-            	new PDAResumeCommand(fCommandControl.getProgramDMContext()),
-            	new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { 
-                    @Override
-                    protected void handleFailure() {
-                        // If the resume command failed, we no longer
-                        // expect to receive a resumed event.
-                        fResumePending = false;
-                        super.handleFailure();
+            if (context instanceof PDAThreadDMContext) {
+                final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
+                fThreads.get(threadCtx.getID()).fResumePending = true;
+                fCommandControl.queueCommand(
+                    new PDAResumeCommand(fDMContext, threadCtx.getID()),
+                    new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { 
+                        @Override
+                        protected void handleFailure() {
+                            ThreadInfo threadState = fThreads.get(threadCtx.getID());
+                            if (threadState != null) {
+                                threadState.fResumePending = false;
+                            }
+                            super.handleFailure();
+                        }
                     }
-            	}
-            );
-        }else {
+                );                
+            } else {
+                fVMResumePending = true;
+                fCommandControl.queueCommand(
+                	new PDAVMResumeCommand(fDMContext),
+                	new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { 
+                        @Override
+                        protected void handleFailure() {
+                            fVMResumePending = false;
+                            super.handleFailure();
+                        }
+                	}
+                );
+            }
+        } else {
             PDAPlugin.failRequest(rm, INVALID_STATE, "Given context: " + context + ", is already running.");
         }
 	}
@@ -271,35 +564,79 @@ public class PDARunControl extends AbstractDsfService
 		assert context != null;
 
 		if (doCanSuspend(context)) {
-            fCommandControl.queueCommand(
-                new PDASuspendCommand(fCommandControl.getProgramDMContext()),
-                new DataRequestMonitor<PDACommandResult>(getExecutor(), rm));
-            
+            if (context instanceof PDAThreadDMContext) {
+                final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
+                fThreads.get(threadCtx.getID()).fSuspendPending = true;
+                fCommandControl.queueCommand(
+                    new PDAVMSuspendCommand(fDMContext),
+                    new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { 
+                        @Override
+                        protected void handleFailure() {
+                            ThreadInfo threadState = fThreads.get(threadCtx.getID());
+                            if (threadState != null) {
+                                threadState.fSuspendPending = false;
+                            }
+                            super.handleFailure();
+                        }
+                    }
+                );
+            } else {
+                fVMSuspendPending = true; 
+                fCommandControl.queueCommand(
+                    new PDAVMSuspendCommand(fDMContext),
+                    new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) { 
+                        @Override
+                        protected void handleFailure() {
+                            fVMSuspendPending = false;
+                            super.handleFailure();
+                        }
+                    }
+                );
+            }
         } else {
             PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_STATE, "Given context: " + context + ", is already suspended."); 
         }
     }
     
     public void canStep(IExecutionDMContext context, StepType stepType, DataRequestMonitor<Boolean> rm) {
-        canResume(context, rm);
+        rm.setData(doCanStep(context, stepType));
+        rm.done();
     }
     
     public void step(IExecutionDMContext context, StepType stepType, final RequestMonitor rm) {
     	assert context != null;
     	
-    	if (doCanResume(context)) {
-            fResumePending = true;
-            fStepping = true;
+    	if (doCanStep(context, stepType)) {
+    	    final PDAThreadDMContext threadCtx = (PDAThreadDMContext)context;
+            final boolean vmWasSuspneded = fVMSuspended;
+    	    
+    	    if (vmWasSuspneded) {
+                fVMResumePending = true;
+    	    } else {
+    	        fThreads.get(threadCtx.getID()).fResumePending = true;
+    	    }
 
+    	    AbstractPDACommand<PDACommandResult> stepCommand = 
+    	        stepType == StepType.STEP_RETURN 
+    	            ? new PDAStepReturnCommand(fDMContext, threadCtx.getID())
+    	            : new PDAStepCommand(fDMContext, threadCtx.getID());
+    	           
+    	    
             fCommandControl.queueCommand(
-                new PDAStepCommand(fCommandControl.getProgramDMContext()),
+                stepCommand, 
                 new DataRequestMonitor<PDACommandResult>(getExecutor(), rm) {
                     @Override
                     protected void handleFailure() {
                         // If the step command failed, we no longer
                         // expect to receive a resumed event.
-                        fResumePending = false;
-                        fStepping = false;
+                        if (vmWasSuspneded) {
+                            fVMResumePending = false;
+                        } else {
+                            ThreadInfo threadState = fThreads.get(threadCtx.getID());
+                            if (threadState != null) {
+                                threadState.fResumePending = false;
+                            }
+                        }
                     }
                 });
 
@@ -310,11 +647,26 @@ public class PDARunControl extends AbstractDsfService
     }
 
     public void getExecutionContexts(final IContainerDMContext containerDmc, final DataRequestMonitor<IExecutionDMContext[]> rm) {
-        PDAPlugin.failRequest(rm, NOT_SUPPORTED, "Operation not implemented"); 
+        IExecutionDMContext[] threads = new IExecutionDMContext[fThreads.size()];
+        int i = 0;
+        for (ThreadInfo info : fThreads.values()) {
+            threads[i++] = info.fContext;
+        }
+        rm.setData(threads);
+        rm.done();
     }
     
-	public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm){
-        rm.setData( new ExecutionDMData(fStateChangeReason) );
+	public void getExecutionData(IExecutionDMContext dmc, DataRequestMonitor<IExecutionDMData> rm) {
+	    if (dmc instanceof PDAThreadDMContext) {
+	        ThreadInfo info = fThreads.get(((PDAThreadDMContext)dmc).getID());
+	        if (info == null) {
+                PDAPlugin.failRequest(rm, INVALID_HANDLE, "Unknown DMC type");
+	            return;
+	        } 
+            rm.setData( new ExecutionDMData(info.fStateChangeReason) );
+	    } else {
+	        rm.setData( new ExecutionDMData(fVMStateChangeReason) );
+	    }
         rm.done();
     }
 }
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java
index 90abe899d44..55d3371a801 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStack.java
@@ -13,6 +13,8 @@ package org.eclipse.dd.examples.pda.service;
 import java.util.Hashtable;
 
 import org.eclipse.cdt.core.IAddress;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
 import org.eclipse.dd.dsf.concurrent.DataRequestMonitor;
 import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants;
 import org.eclipse.dd.dsf.concurrent.Immutable;
@@ -55,7 +57,7 @@ public class PDAStack extends AbstractDsfService implements IStack {
 
         final private int fLevel;
 
-        FrameDMContext(String sessionId, IExecutionDMContext execDmc, int level) {
+        FrameDMContext(String sessionId, PDAThreadDMContext execDmc, int level) {
             super(sessionId, new IDMContext[] { execDmc });
             fLevel = level;
         }
@@ -119,7 +121,7 @@ public class PDAStack extends AbstractDsfService implements IStack {
 
         final private String fVariable;
 
-        VariableDMContext(String sessionId, IFrameDMContext frameCtx, String variable) {
+        VariableDMContext(String sessionId, FrameDMContext frameCtx, String variable) {
             super(sessionId, new IDMContext[] { frameCtx });
             fVariable = variable;
         }
@@ -219,9 +221,18 @@ public class PDAStack extends AbstractDsfService implements IStack {
     }
 
     public void getFrameData(final IFrameDMContext frameCtx, final DataRequestMonitor<IFrameDMData> rm) {
+        PDAThreadDMContext threadCtx = 
+            DMContexts.getAncestorOfType(frameCtx, PDAThreadDMContext.class);
+        
+        if (threadCtx == null) {
+            rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + frameCtx, null));
+            rm.done();
+            return;            
+        }
+        
         // Execute the PDA stack command, or retrieve the result from cache if already available.
         fCommandCache.execute(
-            new PDAStackCommand(fCommandControl.getProgramDMContext()),
+            new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
             new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
                 @Override
                 protected void handleSuccess() {
@@ -246,21 +257,24 @@ public class PDAStack extends AbstractDsfService implements IStack {
         // however the argument context is a generic context type, so it could 
         // be an execution context, a frame, a variable, etc. Search the 
         // hierarchy of the argument context to find the execution one.
-        final IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
-        if (execCtx == null) {
-            PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context);
-            return;
+        final PDAThreadDMContext threadCtx = 
+            DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
+        
+        if (threadCtx == null) {
+            rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
+            rm.done();
+            return;            
         }
 
         // Execute the stack command and create the corresponding frame contexts.
         fCommandCache.execute(
-            new PDAStackCommand(fCommandControl.getProgramDMContext()),
+            new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
             new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
                 @Override
                 protected void handleSuccess() {
                     IFrameDMContext[] frameCtxs = new IFrameDMContext[getData().fFrames.length];
                     for (int i = 0; i < getData().fFrames.length; i++) {
-                        frameCtxs[i] = new FrameDMContext(getSession().getId(), execCtx, i);
+                        frameCtxs[i] = new FrameDMContext(getSession().getId(), threadCtx, i);
                     }
                     rm.setData(frameCtxs);
                     rm.done();
@@ -268,10 +282,25 @@ public class PDAStack extends AbstractDsfService implements IStack {
             });
     }
 
-    public void getLocals(final IFrameDMContext frameCtx, final DataRequestMonitor<IVariableDMContext[]> rm) {
-        // Execute the stack command again.
+    public void getLocals(IFrameDMContext context, final DataRequestMonitor<IVariableDMContext[]> rm) {
+        if (!(context instanceof FrameDMContext)) {
+            rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
+            rm.done();
+            return;            
+        }
+        final FrameDMContext frameCtx = (FrameDMContext)context;
+        
+        final PDAThreadDMContext threadCtx = 
+            DMContexts.getAncestorOfType(frameCtx, PDAThreadDMContext.class);
+        
+        if (threadCtx == null) {
+            rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + frameCtx, null));
+            rm.done();
+            return;            
+        }
+
         fCommandCache.execute(
-            new PDAStackCommand(fCommandControl.getProgramDMContext()),
+            new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
             new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
                 @Override
                 protected void handleSuccess() {
@@ -296,9 +325,18 @@ public class PDAStack extends AbstractDsfService implements IStack {
     }
 
     public void getStackDepth(IDMContext context, int maxDepth, final DataRequestMonitor<Integer> rm) {
+        final PDAThreadDMContext threadCtx = 
+            DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
+        
+        if (threadCtx == null) {
+            rm.setStatus(new Status(IStatus.ERROR, PDAPlugin.PLUGIN_ID, INVALID_HANDLE, "Invalid context" + context, null));
+            rm.done();
+            return;            
+        }
+
         // Execute stack command and return the data's size.
         fCommandCache.execute(
-            new PDAStackCommand(fCommandControl.getProgramDMContext()),
+            new PDAStackCommand(fCommandControl.getVirtualMachineDMContext(), threadCtx.getID()),
             new DataRequestMonitor<PDAStackCommandResult>(getExecutor(), rm) {
                 @Override
                 protected void handleSuccess() {
@@ -313,7 +351,7 @@ public class PDAStack extends AbstractDsfService implements IStack {
         // however the argument context is a generic context type, so it could 
         // be an execution context, a frame, a variable, etc. Search the 
         // hierarchy of the argument context to find the execution one.
-        final IExecutionDMContext execCtx = DMContexts.getAncestorOfType(context, IExecutionDMContext.class);
+        final PDAThreadDMContext execCtx = DMContexts.getAncestorOfType(context, PDAThreadDMContext.class);
         if (execCtx == null) {
             PDAPlugin.failRequest(rm, IDsfStatusConstants.INVALID_HANDLE, "Invalid context " + context);
             return;
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java
index 801c561f5bd..1a31a2340d4 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAStartedEvent.java
@@ -11,12 +11,16 @@
 package org.eclipse.dd.examples.pda.service;
 
 import org.eclipse.dd.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IStartedDMEvent;
 
 /**
  * Event issued when the PDA debugger is started.
  */
-public class PDAStartedEvent extends AbstractDMEvent<PDAProgramDMContext> {
-    PDAStartedEvent(PDAProgramDMContext context) {
+public class PDAStartedEvent extends AbstractDMEvent<IExecutionDMContext> 
+    implements IStartedDMEvent
+{
+    PDAStartedEvent(PDAVirtualMachineDMContext context) {
         super(context);
     }
 }
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java
index 0117f90c155..c33bd04b501 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDATerminatedEvent.java
@@ -11,12 +11,16 @@
 package org.eclipse.dd.examples.pda.service;
 
 import org.eclipse.dd.dsf.datamodel.AbstractDMEvent;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExitedDMEvent;
 
 /**
  * Event issued when the PDA debugger exits.
  */
-public class PDATerminatedEvent extends AbstractDMEvent<PDAProgramDMContext> {
-    PDATerminatedEvent(PDAProgramDMContext context) {
+public class PDATerminatedEvent extends AbstractDMEvent<IExecutionDMContext> 
+    implements IExitedDMEvent
+{
+    PDATerminatedEvent(PDAVirtualMachineDMContext context) {
         super(context);
     }
 }
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAThreadDMContext.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAThreadDMContext.java
new file mode 100644
index 00000000000..659d4698978
--- /dev/null
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAThreadDMContext.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.dd.examples.pda.service;
+
+import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
+import org.eclipse.dd.dsf.datamodel.IDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
+
+/**
+ * Context representing a PDA thread.
+ */
+public class PDAThreadDMContext extends AbstractDMContext
+    implements IExecutionDMContext 
+{
+    final private Integer fID;
+    
+    public PDAThreadDMContext(String sessionId, PDAVirtualMachineDMContext vmCtx, int id) {
+        super(sessionId, new IDMContext[] { vmCtx });
+        fID = id;
+    }
+
+    public int getID() {
+        return fID;
+    }
+    
+    @Override
+    public String toString() {
+        return super.baseToString() + ".thread[" + fID + "]";
+    }
+    
+    @Override
+    public int hashCode() {
+        return baseHashCode() + fID.hashCode();
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        return baseEquals(obj) && ((PDAThreadDMContext)obj).fID.equals(fID);
+    }
+}
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAProgramDMContext.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAVirtualMachineDMContext.java
similarity index 82%
rename from plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAProgramDMContext.java
rename to plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAVirtualMachineDMContext.java
index 1dd8208c372..5c333378470 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAProgramDMContext.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/PDAVirtualMachineDMContext.java
@@ -14,12 +14,12 @@ import org.eclipse.core.runtime.PlatformObject;
 import org.eclipse.dd.dsf.datamodel.AbstractDMContext;
 import org.eclipse.dd.dsf.datamodel.IDMContext;
 import org.eclipse.dd.dsf.debug.service.IBreakpoints.IBreakpointsTargetDMContext;
-import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
+import org.eclipse.dd.dsf.debug.service.IRunControl.IContainerDMContext;
 import org.eclipse.dd.dsf.service.DsfSession;
 
 /**
- * Top-level Data Model context for the PDA debugger representing the PDA 
- * program.  
+ * Top-level Data Model context for the PDA debugger representing the while PDA 
+ * virtual machine.  
  * <p>
  * The PDA debugger is a single-threaded application.  Therefore this
  * top level context implements IExecutionDMContext directly, hence this
@@ -32,20 +32,20 @@ import org.eclipse.dd.dsf.service.DsfSession;
  * service to install/remove breakpoints.
  * </p>
  * <p>
- * Note: There should only be one instance of PDACommandControlDMContext created
- * by each PDA command control, so its equals method defaults to using 
+ * Note: There should only be one instance of PDAVirtualMachineDMContext 
+ * created by each PDA command control, so its equals method defaults to using 
  * instance comparison. 
  * </p>
  */
-public class PDAProgramDMContext extends PlatformObject
-    implements IExecutionDMContext, IBreakpointsTargetDMContext 
+public class PDAVirtualMachineDMContext extends PlatformObject
+    implements IContainerDMContext, IBreakpointsTargetDMContext 
 {
     final static IDMContext[] EMPTY_PARENTS_ARRAY = new IDMContext[0];
     
     final private String fSessionId;
     final private String fProgram;
     
-    public PDAProgramDMContext(String sessionId, String program) {
+    public PDAVirtualMachineDMContext(String sessionId, String program) {
         fSessionId = sessionId;
         fProgram = program;
     }
@@ -64,7 +64,7 @@ public class PDAProgramDMContext extends PlatformObject
     
     @Override
     public String toString() {
-        return "PDA(" + getSessionId() + ")";
+        return "pda[" + getSessionId() + "]";
     }
 
     /**
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java
index c0d527af93e..79206e35717 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/AbstractPDACommand.java
@@ -14,7 +14,7 @@ import org.eclipse.dd.dsf.concurrent.Immutable;
 import org.eclipse.dd.dsf.datamodel.IDMContext;
 import org.eclipse.dd.dsf.debug.service.command.ICommand;
 import org.eclipse.dd.dsf.debug.service.command.ICommandResult;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Base class for PDA commands.  The PDA commands consist of a text request and 
@@ -27,7 +27,7 @@ abstract public class AbstractPDACommand<V extends PDACommandResult> implements
     final private IDMContext fContext;
     final private String fRequest;
     
-    public AbstractPDACommand(PDAProgramDMContext context, String request) {
+    public AbstractPDACommand(PDAVirtualMachineDMContext context, String request) {
         fContext = context;
         fRequest = request;
     }
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java
index 35b9717e3f9..df0b96b85ea 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAClearBreakpointCommand.java
@@ -11,7 +11,7 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Clears any breakpoint set on given line
@@ -25,7 +25,7 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
 @Immutable
 public class PDAClearBreakpointCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAClearBreakpointCommand(PDAProgramDMContext context, int line) {
+    public PDAClearBreakpointCommand(PDAVirtualMachineDMContext context, int line) {
         super(context, "clear " + (line - 1));
     }
     
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java
index 2fa76f1bed4..df271216ff3 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADataCommand.java
@@ -11,21 +11,24 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Retrieves data stack information 
  * 
  * <pre>
- *    C: data
+ *    C: data {thread_id}
  *    R: {value 1}|{value 2}|{value 3}|...|
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDADataCommand extends AbstractPDACommand<PDADataCommandResult> {
 
-    public PDADataCommand(PDAProgramDMContext context) {
-        super(context, "data");
+    public PDADataCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "data " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java
index d68c173dd52..128f7353e37 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDADropFrameCommand.java
@@ -11,24 +11,33 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Returns from the current frame without executing the rest of instructions.  
  * 
  * <pre>
- *    C: drop
+ * If VM running:
+ *    C: drop {thread_id}
  *    R: ok
- *    E: resumed drop
- *    E: suspended drop
+ *    E: resumed {thread_id} drop
+ *    E: suspended {thread_id} drop
+ *    
+ * If VM suspended:
+ *    C: drop {thread_id}
+ *    R: ok
+ *    E: vmresumed drop
+ *    E: vmsuspended {thread_id} drop
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
-
  */
 @Immutable
 public class PDADropFrameCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDADropFrameCommand(PDAProgramDMContext context) {
-        super(context, "drop");
+    public PDADropFrameCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "drop " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java
index 10a4d707132..3b6af5d0133 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEvalCommand.java
@@ -11,17 +11,22 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Sets what events cause the execution to stop.
  * 
  * <pre>
- *    C: eval {instruction}%20{parameter}|{instruction}%20{parameter}|...
+ *    C: eval {thread_id} {instruction}%20{parameter}|{instruction}%20{parameter}|...
  *    R: ok
- *    E: resume client
+ *    E: resumed {thread_id} client
  *    E: evalresult result
- *    E: suspended eval
+ *    E: suspended {thread_id} eval
+ *    
+ * Errors:
+ *    error: invalid thread
+ *    error: cannot evaluate while vm is suspended
+ *    error: thread running        
  * </pre>
  * 
  * Where event_name could be <code>unimpinstr</code> or <code>nosuchlabel</code>.  
@@ -29,8 +34,8 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
 @Immutable
 public class PDAEvalCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAEvalCommand(PDAProgramDMContext context, String operation) {
-        super(context, "eval " + operation);
+    public PDAEvalCommand(PDAVirtualMachineDMContext context, int threadId, String operation) {
+        super(context, "eval " + threadId + " " + operation);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java
index d247f829c4b..7537012be38 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAEventStopCommand.java
@@ -11,7 +11,7 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Sets what events cause the execution to stop.
@@ -30,7 +30,7 @@ public class PDAEventStopCommand extends AbstractPDACommand<PDACommandResult> {
 
     public enum Event { UNIMPINSTR, NOSUCHLABEL };
     
-    public PDAEventStopCommand(PDAProgramDMContext context, Event event, boolean enable) {
+    public PDAEventStopCommand(PDAVirtualMachineDMContext context, Event event, boolean enable) {
         super(context, 
               "eventstop " + 
               (event == Event.UNIMPINSTR ? "unimpinstr " : "nosuchlabel ") + 
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java
index 7b7222b7b27..1736c7a4648 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAExitCommand.java
@@ -11,7 +11,7 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Instructs the debugger to exit.
@@ -24,7 +24,7 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
 @Immutable
 public class PDAExitCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAExitCommand(PDAProgramDMContext context) {
+    public PDAExitCommand(PDAVirtualMachineDMContext context) {
         super(context, "exit");
     }
     
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java
index de6649b785b..4b8b1ec92be 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPopDataCommand.java
@@ -11,21 +11,24 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Pops the top value from the data stack  
  * 
  * <pre>
- *    C: popdata
+ *    C: popdata {thread_id}
  *    R: ok
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDAPopDataCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAPopDataCommand(PDAProgramDMContext context) {
-        super(context, "popdata");
+    public PDAPopDataCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "popdata " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java
index d201e9b05ec..d4861428270 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAPushDataCommand.java
@@ -11,21 +11,24 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Pushes the given value on top of the data stack.
  * 
  * <pre>
- *    C: pushdata {value}
+ *    C: pushdata {thread_id} {value}
  *    R: ok
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDAPushDataCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAPushDataCommand(PDAProgramDMContext context, int value) {
-        super(context, "pushdata " + value);
+    public PDAPushDataCommand(PDAVirtualMachineDMContext context, int threadId, int value) {
+        super(context, "pushdata " + threadId + " " + value);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java
index 6a7e46f1a29..b49879bd45f 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAResumeCommand.java
@@ -11,22 +11,28 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
- * Resumes the execution  
+ * Resumes the execution of a single thread.  Can be issued only if the virtual 
+ * machine is running.
  * 
  * <pre>
- *    C: resume
+ *    C: resume {thread_id}
  *    R: ok
- *    E: resumed client
+ *    E: resumed {thread_id} client
+ *    
+ * Errors:
+ *    error: invalid thread
+ *    error: cannot resume thread when vm is suspended
+ *    error: thread already running
  * </pre>
  */
 @Immutable
 public class PDAResumeCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAResumeCommand(PDAProgramDMContext context) {
-        super(context, "resume");
+    public PDAResumeCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "resume " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java
index 4bfd3370df6..c6cad586b14 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetBreakpointCommand.java
@@ -11,24 +11,35 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Sets a breakpoint at given line
  * 
  * <pre>
- *    C: set {line_number}
+ * Suspend a single thread:
+ *    C: set {line_number} 0
  *    R: ok
- *    C: resume
- *    E: resumed client
- *    E: suspended breakpoint line_number
+ *    C: resume {thread_id}
+ *    E: resumed {thread_id} client
+ *    E: suspended {thread_id} breakpoint line_number
+ *    
+ * Suspend the VM:
+ *    C: set {line_number} 1
+ *    R: ok
+ *    C: vmresume
+ *    E: vmresumed client
+ *    E: vmsuspended {thread_id} breakpoint line_number
  * </pre>
  */
 @Immutable
 public class PDASetBreakpointCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDASetBreakpointCommand(PDAProgramDMContext context, int line) {
-        super(context, "set " + (line - 1));
+    public PDASetBreakpointCommand(PDAVirtualMachineDMContext context, int line, boolean stopVM) {
+        super(context, 
+              "set " + 
+              (line - 1) + " " + 
+              (stopVM ? "1" : "0"));
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java
index 706700c8f7f..92972c47ef6 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetDataCommand.java
@@ -11,21 +11,24 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Sets a data value in the data stack at the given location
  * 
  * <pre>
- *    C: setdata {index} {value}
+ *    C: setdata {thread_id} {index} {value}
  *    R: ok
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDASetDataCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDASetDataCommand(PDAProgramDMContext context, int index, String value) {
-        super(context, "setdata " + index + " " + value);
+    public PDASetDataCommand(PDAVirtualMachineDMContext context, int threadId, int index, String value) {
+        super(context, "setdata " + threadId + " " + index + " " + value);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java
index f18340e20d4..5e058ecff83 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASetVarCommand.java
@@ -11,21 +11,24 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Sets a variable value 
  * 
  * <pre>
- *    C: setvar {frame_number} {variable} {value}
+ *    C: setvar {thread_id} {frame_number} {variable} {value}
  *    R: ok
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDASetVarCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDASetVarCommand(PDAProgramDMContext context, int frame, String variable, String value) {
-        super(context, "setvar " + frame + " " + variable + " " + value);
+    public PDASetVarCommand(PDAVirtualMachineDMContext context, int threadId, int frame, String variable, String value) {
+        super(context, "setvar " + threadId + " " + frame + " " + variable + " " + value);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java
index aef4d4aa795..c99f3c32073 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStackCommand.java
@@ -11,21 +11,24 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Retrieves command stack information 
  * 
  * <pre>
- *    C: stack
+ *    C: stack {thread_id}
  *    R: {file}|{line}|{function}|{var_1}|{var_2}|...#{file}|{line}|{function}|{var_1}|{var_2}|...#...
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDAStackCommand extends AbstractPDACommand<PDAStackCommandResult> {
 
-    public PDAStackCommand(PDAProgramDMContext context) {
-        super(context, "stack");
+    public PDAStackCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "stack " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java
index ce50cf5c228..5401c8ec11e 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepCommand.java
@@ -11,23 +11,33 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Executes next instruction 
  * 
  * <pre>
- *    C: step
+ * If VM running:
+ *    C: step {thread_id}
  *    R: ok
- *    E: resumed client
- *    E: suspended step
+ *    E: resumed {thread_id} client
+ *    E: suspended {thread_id} step
+ *    
+ * If VM suspended:
+ *    C: step {thread_id}
+ *    R: ok
+ *    E: vmresumed client
+ *    E: vmsuspended {thread_id} step
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDAStepCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAStepCommand(PDAProgramDMContext context) {
-        super(context, "step");
+    public PDAStepCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "step " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java
index 8b9d7c8a675..7a588019360 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAStepReturnCommand.java
@@ -11,23 +11,33 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Executes instructions until the current subroutine is finished 
  * 
  * <pre>
- *    C: stepreturn
+ * If VM running:
+ *    C: stepreturn {thread_id}
  *    R: ok
- *    E: resumed step
- *    E: suspended step
+ *    E: resumed {thread_id} client
+ *    E: suspended {thread_id} step
+ *    
+ * If VM suspended:
+ *    C: stepreturn {thread_id}
+ *    R: ok
+ *    E: vmresumed client
+ *    E: vmsuspended {thread_id} step
+ *    
+ * Errors:
+ *    error: invalid thread
  * </pre>
  */
 @Immutable
 public class PDAStepReturnCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAStepReturnCommand(PDAProgramDMContext context) {
-        super(context, "stepreturn");
+    public PDAStepReturnCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "stepreturn " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java
index 5abde431178..a3ad5bd86b3 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDASuspendCommand.java
@@ -11,22 +11,28 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
- * Suspends execution 
+ * Suspends execution of a single thread.  Can be issued only if the virtual 
+ * machine is running.
  * 
  * <pre>
- *    C: suspend
+ *    C: suspend {thread_id}
  *    R: ok
- *    E: suspended client
+ *    E: suspended {thread_id} client
+ *    
+ * Errors:
+ *    error: invalid thread
+      error: vm already suspended
+ *    error: thread already suspended
  * </pre>
  */
 @Immutable
 public class PDASuspendCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDASuspendCommand(PDAProgramDMContext context) {
-        super(context, "suspend");
+    public PDASuspendCommand(PDAVirtualMachineDMContext context, int threadId) {
+        super(context, "suspend " + threadId);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMResumeCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMResumeCommand.java
new file mode 100644
index 00000000000..627ffdb9390
--- /dev/null
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMResumeCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.dd.examples.pda.service.commands;
+
+import org.eclipse.dd.dsf.concurrent.Immutable;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Resumes the execution of the whole virtual machine  
+ * 
+ * <pre>
+ *    C: vmresume
+ *    R: ok
+ *    E: vmresumed client
+ *    
+ * Errors:
+ *    error: vm already running
+ * </pre>
+ */
+@Immutable
+public class PDAVMResumeCommand extends AbstractPDACommand<PDACommandResult> {
+
+    public PDAVMResumeCommand(PDAVirtualMachineDMContext context) {
+        super(context, "vmresume");
+    }
+    
+    @Override
+    public PDACommandResult createResult(String resultText) {
+        return new PDACommandResult(resultText);
+    }
+}
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMSuspendCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMSuspendCommand.java
new file mode 100644
index 00000000000..c406ba8b5b5
--- /dev/null
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVMSuspendCommand.java
@@ -0,0 +1,39 @@
+/*******************************************************************************
+ * 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.dd.examples.pda.service.commands;
+
+import org.eclipse.dd.dsf.concurrent.Immutable;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
+
+/**
+ * Suspends the execution of the whole virtual machine 
+ * 
+ * <pre>
+ *    C: vmsuspend
+ *    R: ok
+ *    E: vmsuspended client
+ *    
+ * Errors:
+ *    error: thread already suspended
+ * </pre>
+ */
+@Immutable
+public class PDAVMSuspendCommand extends AbstractPDACommand<PDACommandResult> {
+
+    public PDAVMSuspendCommand(PDAVirtualMachineDMContext context) {
+        super(context, "vmsuspend");
+    }
+    
+    @Override
+    public PDACommandResult createResult(String resultText) {
+        return new PDACommandResult(resultText);
+    }
+}
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java
index cc57a527161..060e807bcbd 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAVarCommand.java
@@ -11,21 +11,25 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Retrieves variable value 
  * 
  * <pre>
- *    C: var {frame_number} {variable_name}
+ *    C: var  {thread_id} {frame_number} {variable_name}
  *    R: {variable_value}
+ *    
+ * Errors:
+ *    error: invalid thread
+ *    error: variable undefined
  * </pre>
  */
 @Immutable
 public class PDAVarCommand extends AbstractPDACommand<PDACommandResult> {
 
-    public PDAVarCommand(PDAProgramDMContext context, int frameId, String name) {
-        super(context, "var " + frameId + " " + name);
+    public PDAVarCommand(PDAVirtualMachineDMContext context, int threadId, int frameId, String name) {
+        super(context, "var " + threadId + " " + frameId + " " + name);
     }
     
     @Override
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java
index f6bf1982545..7b1bb1c0a22 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/examples/pda/service/commands/PDAWatchCommand.java
@@ -11,7 +11,7 @@
 package org.eclipse.dd.examples.pda.service.commands;
 
 import org.eclipse.dd.dsf.concurrent.Immutable;
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 
 /**
  * Sets a watchpoint on a given variable
@@ -19,9 +19,9 @@ import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
  * <pre>
  *    C: watch {function}::{variable_name} {watch_operation}
  *    R: ok
- *    C: resume
- *    R: resume client
- *    E: suspended watch {watch_operation} {function}::{variable_name}
+ *    C: vmresume
+ *    R: vmresumed client
+ *    E: vmsuspended {thread_id} watch {watch_operation} {function}::{variable_name}
  * </pre>
  */
 @Immutable
@@ -42,7 +42,7 @@ public class PDAWatchCommand extends AbstractPDACommand<PDACommandResult> {
         }
     }
     
-    public PDAWatchCommand(PDAProgramDMContext context, String function, String variable, WatchOperation operation) {
+    public PDAWatchCommand(PDAVirtualMachineDMContext context, String function, String variable, WatchOperation operation) {
         super(context, "watch " + function+ "::" + variable + " " + getWatchOperationCode(operation));
     }
     
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java
index 5d1f330f0d1..15e03f1dbd1 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/BasicTests.java
@@ -82,7 +82,7 @@ public class BasicTests extends CommandControlTestsBase {
             }
         });
         
-        final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getProgramDMContext(), "data");
+        final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getVirtualMachineDMContext(), "data 1");
         
         // Test sending the command and checking all listeners were called.
         Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() {
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java
index b2b2fb60d6c..e50b142cb1f 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/CommandControlTestsBase.java
@@ -105,7 +105,7 @@ public class CommandControlTestsBase {
 
     protected void sendCommand(String command, String expectedResult) throws Throwable {
 
-        final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getProgramDMContext(), command);
+        final PDATestCommand testCommand = new PDATestCommand(fCommandControl.getVirtualMachineDMContext(), command);
         
         // Test sending the command and checking all listeners were called.
         Query<PDACommandResult> sendCommandQuery = new Query<PDACommandResult>() {
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java
index 36ba23c3527..2e8c6aa1112 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/PDATestCommand.java
@@ -10,7 +10,7 @@
  *******************************************************************************/
 package org.eclipse.dd.tests.pda.service.command;
 
-import org.eclipse.dd.examples.pda.service.PDAProgramDMContext;
+import org.eclipse.dd.examples.pda.service.PDAVirtualMachineDMContext;
 import org.eclipse.dd.examples.pda.service.commands.AbstractPDACommand;
 import org.eclipse.dd.examples.pda.service.commands.PDACommandResult;
 
@@ -18,7 +18,7 @@ import org.eclipse.dd.examples.pda.service.commands.PDACommandResult;
  * 
  */
 class PDATestCommand extends AbstractPDACommand<PDACommandResult> {
-    PDATestCommand(PDAProgramDMContext context, String command) {
+    PDATestCommand(PDAVirtualMachineDMContext context, String command) {
         super(context, command);
     }
     
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java
index 2225c20f1ef..4d8f7c62482 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test1.java
@@ -30,7 +30,7 @@ public class Test1 extends CommandControlTestsBase {
 
     @Test
     public void testRun() throws Throwable {
-        sendCommand("resume");
+        sendCommand("vmresume");
         expectOutput("\"hello\"");
         expectOutput("\"barfoo\"");
         expectOutput("\"first\"");
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java
index 88dc69f1878..8be032a6603 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test2.java
@@ -31,79 +31,161 @@ public class Test2 extends CommandControlTestsBase {
 
     @Test
     public void testCommonDebugCommands() throws Throwable {
-        expectEvent("started");
+        expectEvent("started 1");
         // test step
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
         // test breakpoint
-        sendCommand("set 4");
-        sendCommand("data", "6|");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 4");
+        sendCommand("set 4 1");
+        sendCommand("data 1", "6|");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 breakpoint 4");
         // test data stack
-        sendCommand("data", "6|7|8|9|");
-        sendCommand("popdata");
-        sendCommand("data", "6|7|8|");
-        sendCommand("pushdata 11");
-        sendCommand("data", "6|7|8|11|");
-        sendCommand("setdata 1 2");
-        sendCommand("data", "6|2|8|11|");
+        sendCommand("data 1", "6|7|8|9|");
+        sendCommand("popdata 1");
+        sendCommand("data 1", "6|7|8|");
+        sendCommand("pushdata 1 11");
+        sendCommand("data 1", "6|7|8|11|");
+        sendCommand("setdata 1 1 2");
+        sendCommand("data 1", "6|2|8|11|");
         // test call stack
-        sendCommand("set 12");
-        sendCommand("set 19");
-        sendCommand("stepreturn");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 12");
+        sendCommand("set 12 1");
+        sendCommand("set 19 1");
+        sendCommand("stepreturn 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 breakpoint 12");
         sendCommand("clear 19");
-        sendCommand("stack", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" );
-        sendCommand("stepreturn");
-        expectEvent("resumed client");
-        expectEvent("suspended step");
-        sendCommand("stack", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" );
-        sendCommand("stepreturn");
-        expectEvent("resumed client");
-        expectEvent("suspended step");
-        sendCommand("stack", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" );
-        sendCommand("set 6");
-        sendCommand("stepreturn");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 6");
+        sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" );
+        sendCommand("stepreturn 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" );
+        sendCommand("stepreturn 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" );
+        sendCommand("set 6 1");
+        sendCommand("stepreturn 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 breakpoint 6");
         // test set and clear
-        sendCommand("set 27");
-        sendCommand("set 29");
-        sendCommand("set 33");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 33");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 27");
+        sendCommand("set 27 1");
+        sendCommand("set 29 1");
+        sendCommand("set 33 1");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 breakpoint 33");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 breakpoint 27");
         sendCommand("clear 33");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 29");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 breakpoint 29");
         // test var and setvar
-        sendCommand("set 47");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 47");
-        sendCommand("var 1 b", "4");
-        sendCommand("var 2 b", "2");
-        sendCommand("var 1 a", "0");
-        sendCommand("setvar 1 a 99");
-        sendCommand("data", "6|2|8|11|27|1|4|");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("var 1 a", "99");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("data", "6|2|8|11|27|1|4|99|");
+        sendCommand("set 47 1");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 breakpoint 47");
+        sendCommand("var 1 1 b", "4");
+        sendCommand("var 1 2 b", "2");
+        sendCommand("var 1 1 a", "0");
+        sendCommand("setvar 1 1 a 99");
+        sendCommand("data 1", "6|2|8|11|27|1|4|");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("var 1 1 a", "99");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("data 1", "6|2|8|11|27|1|4|99|");
+        sendCommand("var 1 1 x", "error: variable undefined");
+        sendCommand("setvar 1 1 x 100");
+        sendCommand("var 1 1 x", "100");
         // test exit
         sendCommand("exit");
         expectEvent("terminated");
     }
+    
+    @Test
+    public void testCommonDebugCommandsWithThreadRC() throws Throwable {
+        expectEvent("started 1");
+        // test breakpoint
+        sendCommand("set 3 0");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("suspended 1 breakpoint 3");
+        sendCommand("data 1", "6|7|8|");
+        // test step
+        sendCommand("step 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 step");
+        // test data stack
+        sendCommand("data 1", "6|7|8|9|");
+        sendCommand("popdata 1");
+        sendCommand("data 1", "6|7|8|");
+        sendCommand("pushdata 1 11");
+        sendCommand("data 1", "6|7|8|11|");
+        sendCommand("setdata 1 1 2");
+        sendCommand("data 1", "6|2|8|11|");
+        // test call stack
+        sendCommand("set 12 0");
+        sendCommand("set 19 0");
+        sendCommand("stepreturn 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 breakpoint 12");
+        sendCommand("clear 19");
+        sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|12|sub2" );
+        sendCommand("stepreturn 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 step");
+        sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|18|sub1|m|n#" + fProgram + "|13|sub2" );
+        sendCommand("stepreturn 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 step");
+        sendCommand("stack 1", fProgram + "|6|main#" + fProgram + "|22|sub1|m|n" );
+        sendCommand("set 6 0");
+        sendCommand("stepreturn 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 breakpoint 6");
+        // test set and clear
+        sendCommand("set 27 0");
+        sendCommand("set 29 0");
+        sendCommand("set 33 0");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("suspended 1 breakpoint 33");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("suspended 1 breakpoint 27");
+        sendCommand("clear 33");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("suspended 1 breakpoint 29");
+        // test var and setvar
+        sendCommand("set 47 0");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("suspended 1 breakpoint 47");
+        sendCommand("var 1 1 b", "4");
+        sendCommand("var 1 2 b", "2");
+        sendCommand("var 1 1 a", "0");
+        sendCommand("setvar 1 1 a 99");
+        sendCommand("data 1", "6|2|8|11|27|1|4|");
+        sendCommand("step 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 step");
+        sendCommand("var 1 1 a", "99");
+        sendCommand("step 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 step");
+        sendCommand("data 1", "6|2|8|11|27|1|4|99|");
+        // test exit
+        sendCommand("exit");
+        expectEvent("terminated");
+    }
+
 }
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java
index 2df4d2339b1..00ac9b6c24a 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test3.java
@@ -31,43 +31,59 @@ public class Test3 extends CommandControlTestsBase {
 
     @Test
     public void testUncaughtEvents() throws Throwable {
-        expectEvent("started");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        expectEvent("started 1");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
         expectEvent("unimplemented instruction foobar");
         expectEvent("no such label zippy");
+        expectEvent("no such label swishy");
+        expectEvent("exited 1");
         expectEvent("terminated");
     }
-    
+
     @Test
     public void testCaughtUnimpinstrEvents() throws Throwable {
-        expectEvent("started");
+        expectEvent("started 1");
         sendCommand("eventstop unimpinstr 1");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
         expectEvent("unimplemented instruction foobar");
-        expectEvent("suspended event unimpinstr");
+        expectEvent("vmsuspended 1 event unimpinstr");
         sendCommand("eventstop unimpinstr 0");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
         expectEvent("unimplemented instruction foobar");
         expectEvent("no such label zippy");
+        expectEvent("no such label swishy");
+        expectEvent("exited 1");
         expectEvent("terminated");
     }
 
     @Test
     public void testCaughtNosuchlabelEvents() throws Throwable {
-        expectEvent("started");
+        expectEvent("started 1");
         sendCommand("eventstop nosuchlabel 1");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
         expectEvent("unimplemented instruction foobar");
         expectEvent("no such label zippy");
-        expectEvent("suspended event nosuchlabel");
+        expectEvent("vmsuspended 1 event nosuchlabel");
         sendCommand("eventstop nosuchlabel 0");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        sendCommand("set 11 1");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
         expectEvent("no such label zippy");
+        expectEvent("vmsuspended 1 breakpoint 11");
+        sendCommand("eventstop nosuchlabel 1");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("no such label swishy");
+        expectEvent("vmsuspended 1 event nosuchlabel");
+        sendCommand("eventstop nosuchlabel 0");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("no such label swishy");
+        expectEvent("exited 1");
         expectEvent("terminated");
     }
 
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java
index 27543a9dc10..49a124de346 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test6.java
@@ -31,49 +31,54 @@ public class Test6 extends CommandControlTestsBase {
 
     @Test
     public void testWatchPoints() throws Throwable {
-        expectEvent("started");
+        expectEvent("started 1");
         sendCommand("watch inner::a 1");
         sendCommand("watch main::a 2");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended watch write main::a");
-        sendCommand("stack", fProgram + "|4|main|a|b");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended watch read inner::a");
-        sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|25|inner|a|c");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 watch write main::a");
+        sendCommand("stack 1", fProgram + "|4|main|a|b");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 watch read inner::a");
+        sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|25|inner|a|c");
         sendCommand("watch inner::a 0");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("exited 1");        
         expectEvent("terminated");
     }
     
     @Test
     public void testEval() throws Throwable {
-        expectEvent("started");
-        sendCommand("set 25");
-        sendCommand("resume");
-        expectEvent("resumed client");
-        expectEvent("suspended breakpoint 25");
+        expectEvent("started 1");
 
-        sendCommand("eval push%204|push%205|add");
-        expectEvent("resumed client");
+        sendCommand("eval 1 test_error", "error: cannot evaluate while vm is suspended");
+        
+        sendCommand("set 25 0");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("suspended 1 breakpoint 25");
+
+        sendCommand("eval 1 push%204|push%205|add");
+        expectEvent("resumed 1 eval");
         expectEvent("evalresult 9");
-        expectEvent("suspended eval");
+        expectEvent("suspended 1 eval");
 
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
-        sendCommand("data", "4|4|");
-        sendCommand("eval call%20other");
-        expectEvent("resumed client");
+        sendCommand("step 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 step");
+        sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
+        sendCommand("data 1", "4|4|");
+        sendCommand("eval 1 call%20other");
+        expectEvent("resumed 1 eval");
         expectEvent("evalresult 15");
-        expectEvent("suspended eval");
-        sendCommand("stack", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
-        sendCommand("data", "4|4|");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        expectEvent("suspended 1 eval");
+        sendCommand("stack 1", fProgram + "|10|main|a|b#" + fProgram + "|26|inner|a|c");
+        sendCommand("data 1", "4|4|");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("exited 1");
         expectEvent("terminated");
     }
 }
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java
index 389f227d617..dc4a74a1004 100644
--- a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test8.java
@@ -31,40 +31,64 @@ public class Test8 extends CommandControlTestsBase {
 
     @Test
     public void testDropFrame() throws Throwable {
-        expectEvent("started");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c");
-        sendCommand("drop");
-        expectEvent("resumed drop");
-        expectEvent("suspended drop");
-        sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|7|inner|b");
-        sendCommand("step");
-        expectEvent("resumed step");
-        expectEvent("suspended step");
-        sendCommand("stack", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2");
-        sendCommand("resume");
-        expectEvent("resumed client");
+        expectEvent("started 1");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c");
+        sendCommand("drop 1");
+        expectEvent("vmresumed drop");
+        expectEvent("vmsuspended 1 drop");
+        sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|7|inner|b");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("exited 1");
         expectEvent("terminated");
     }
-    
+
+    @Test
+    public void testDropFrameWithThreadRC() throws Throwable {
+        expectEvent("started 1");
+        sendCommand("set 12 0");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("suspended 1 breakpoint 12");
+        sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|12|inner2|c");
+        sendCommand("drop 1");
+        expectEvent("resumed 1 drop");
+        expectEvent("suspended 1 drop");
+        sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|7|inner|b");
+        sendCommand("step 1");
+        expectEvent("resumed 1 step");
+        expectEvent("suspended 1 step");
+        sendCommand("stack 1", fProgram + "|2|main|a#" + fProgram + "|8|inner|b#" + fProgram + "|10|inner2");
+        sendCommand("clear 12");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("exited 1");
+        expectEvent("terminated");
+    }
+
 }
diff --git a/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test9.java b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test9.java
new file mode 100644
index 00000000000..743b56d1987
--- /dev/null
+++ b/plugins/org.eclipse.dd.examples.pda/src/org/eclipse/dd/tests/pda/service/command/Test9.java
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * 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.dd.tests.pda.service.command;
+
+import java.io.File;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.dd.examples.pda.PDAPlugin;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * 
+ */
+public class Test9 extends CommandControlTestsBase {
+
+    @BeforeClass
+    public static void setProgram() {
+        File programFile = PDAPlugin.getFileInPlugin(new Path("pdavm/tests/vmtest9.pda"));
+
+        fProgram = programFile.getPath();
+    }
+
+    @Test
+    public void testThreadsWithVMRC() throws Throwable {
+        expectEvent("started 1");
+        sendCommand("state", "client");
+        sendCommand("state 1", "vm");
+        
+        // Check error responses
+        sendCommand("vmsuspend", "error: vm already suspended");
+        sendCommand("resume 1", "error: cannot resume thread when vm is suspended");
+
+        // Run to thread create routine
+        sendCommand("threads", "1");
+        sendCommand("set 2 1");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("vmsuspended 1 breakpoint 2");
+        sendCommand("state", "1 breakpoint 2");
+        sendCommand("state 1", "vm");
+        
+        // Step over first thread create
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("started 2");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("state", "1 step");
+        sendCommand("state 1", "vm");
+        sendCommand("threads", "1 2");
+        sendCommand("stack 1", fProgram + "|3|main");
+        sendCommand("stack 2", fProgram + "|9|foo");
+        sendCommand("step 1");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 1 step");
+        sendCommand("stack 1", fProgram + "|4|main");
+        sendCommand("stack 2", fProgram + "|10|foo");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectOutput("thread_created");
+        expectEvent("vmsuspended 1 breakpoint 2");
+        
+        // Step over second thread create
+        sendCommand("step 2");
+        expectEvent("vmresumed step");
+        expectEvent("started 3");
+        expectEvent("vmsuspended 2 step");
+        sendCommand("threads", "1 2 3");
+        sendCommand("stack 1", fProgram + "|3|main");
+        sendCommand("stack 2", fProgram + "|13|foo#" + fProgram + "|15|inner");
+        sendCommand("stack 3", fProgram + "|9|foo");
+        sendCommand("step 3");
+        expectEvent("vmresumed step");
+        expectEvent("vmsuspended 3 step");
+        sendCommand("stack 1", fProgram + "|4|main");
+        sendCommand("stack 2", fProgram + "|13|foo#" + fProgram + "|16|inner|b");
+        sendCommand("stack 3", fProgram + "|10|foo");
+
+        // Run to the end and watch threads starting/exiting.
+        sendCommand("clear 2");
+        sendCommand("vmresume");  
+        expectOutput("thread_created");
+        expectEvent("vmresumed client");       
+        expectEvent("started 4");
+        expectEvent("exited 2");
+        expectEvent("started 5");       
+        expectEvent("exited 3");
+        expectEvent("started 6");       
+        expectEvent("exited 4");
+        expectEvent("exited 1");
+        expectEvent("exited 5");
+        expectEvent("exited 6");
+        expectEvent("terminated");        
+    }
+
+    @Test
+    public void testThreadsWithThreadRC() throws Throwable {
+        expectEvent("started 1");
+        
+        // Check error responses for thread run control
+        sendCommand("set 1 0");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("suspended 1 breakpoint 1");
+        sendCommand("state", "running");
+        sendCommand("state 1", "breakpoint 1");
+        
+        sendCommand("resume", "error: invalid thread");        
+        sendCommand("vmresume", "error: vm already running");        
+        sendCommand("clear 1");
+        sendCommand("suspend 1", "error: thread already suspended");
+        sendCommand("vmsuspend");
+        expectEvent("vmsuspended client");
+        sendCommand("state", "client");
+        sendCommand("state 1", "vm");
+        sendCommand("suspend 1", "error: vm already suspended");
+        sendCommand("resume 1", "error: cannot resume thread when vm is suspended");        
+        
+        // Create breakpoints at thread create and thread entry point.
+        sendCommand("set 2 0");
+        sendCommand("set 10 0");
+        sendCommand("vmresume");
+        expectEvent("vmresumed client");
+        expectEvent("suspended 1 breakpoint 2");
+
+        // Create first thread, and run it to completion
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("started 2");
+        expectEvent("suspended 2 breakpoint 10");
+        expectEvent("suspended 1 breakpoint 2");
+        sendCommand("state 1", "breakpoint 2");
+        sendCommand("state 2", "breakpoint 10");
+        sendCommand("threads", "1 2");
+        sendCommand("resume 2");
+        expectEvent("resumed 2 client");
+        expectEvent("exited 2");
+        sendCommand("threads", "1");
+
+        // Create second thread, step it
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("started 3");
+        expectEvent("suspended 3 breakpoint 10");
+        expectEvent("suspended 1 breakpoint 2");
+        sendCommand("threads", "1 3");
+        sendCommand("stack 1", fProgram + "|2|main");
+        sendCommand("stack 3", fProgram + "|10|foo");
+        sendCommand("step 3");
+        expectEvent("resumed 3 step");
+        expectEvent("suspended 3 step");
+        sendCommand("state 1", "breakpoint 2");
+        sendCommand("state 3", "step");
+        sendCommand("stack 1", fProgram + "|2|main");
+        sendCommand("stack 3", fProgram + "|11|foo");
+        
+        // Create the rest of threads
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("started 4");
+        expectEvent("suspended 4 breakpoint 10");
+        expectEvent("suspended 1 breakpoint 2");
+        sendCommand("threads", "1 3 4");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        expectEvent("started 5");
+        expectEvent("suspended 5 breakpoint 10");
+        expectEvent("suspended 1 breakpoint 2");
+        sendCommand("threads", "1 3 4 5");
+        sendCommand("resume 1");
+        expectEvent("resumed 1 client");
+        
+        // Main thread exits
+        expectEvent("started 6");
+        expectEvent("suspended 6 breakpoint 10");
+        expectEvent("exited 1");
+        sendCommand("threads", "3 4 5 6");
+        
+        // Exit
+        sendCommand("exit");
+        expectEvent("terminated");
+    }
+
+}
diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java
index ab7947a8cd2..087f2515c77 100644
--- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java
+++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/ContainerVMNode.java
@@ -68,38 +68,36 @@ public class ContainerVMNode extends AbstractContainerVMNode
 
 	
     @Override
-	protected void updateLabelInSessionThread(ILabelUpdate[] updates) {
-        for (final ILabelUpdate update : updates) {
-        	final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
-            if ( runControl == null ) {
-                handleFailedUpdate(update);
-                continue;
-            }
-            
-            final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class);
-
-            String imageKey = null;
-            if (runControl.isSuspended(dmc)) {
-                imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
-            } else {
-                imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
-            }
-            update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
-            
-            runControl.getProcessData(
-                dmc,
-                new ViewerDataRequestMonitor<GDBProcessData>(getExecutor(), update) {
-					@Override
-                    public void handleCompleted() {
-                        if (!isSuccess()) {
-                            update.done();
-                            return;
-                        }
-                        update.setLabel(getData().getName(), 0);
-                        update.done();
-                    }
-                });
+	protected void updateLabelInSessionThread(final ILabelUpdate update) {
+    	final GDBRunControl runControl = getServicesTracker().getService(GDBRunControl.class);
+        if ( runControl == null ) {
+            handleFailedUpdate(update);
+            return;
         }
+        
+        final GDBControlDMContext dmc = findDmcInPath(update.getViewerInput(), update.getElementPath(), GDBControlDMContext.class);
+
+        String imageKey = null;
+        if (runControl.isSuspended(dmc)) {
+            imageKey = IDebugUIConstants.IMG_OBJS_THREAD_SUSPENDED;
+        } else {
+            imageKey = IDebugUIConstants.IMG_OBJS_THREAD_RUNNING;
+        }
+        update.setImageDescriptor(DebugUITools.getImageDescriptor(imageKey), 0);
+        
+        runControl.getProcessData(
+            dmc,
+            new ViewerDataRequestMonitor<GDBProcessData>(getExecutor(), update) {
+				@Override
+                public void handleCompleted() {
+                    if (!isSuccess()) {
+                        update.done();
+                        return;
+                    }
+                    update.setLabel(getData().getName(), 0);
+                    update.done();
+                }
+            });
     }
 
 	@Override
diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java
index 5feeaef3506..a79760fdfb8 100644
--- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java
+++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java
@@ -11,42 +11,21 @@
  *******************************************************************************/
 package org.eclipse.dd.gdb.internal.ui.viewmodel.launch;
 
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
-
-import org.eclipse.dd.dsf.concurrent.DsfRunnable;
-import org.eclipse.dd.dsf.concurrent.RequestMonitor;
 import org.eclipse.dd.dsf.concurrent.ThreadSafe;
-import org.eclipse.dd.dsf.datamodel.DMContexts;
-import org.eclipse.dd.dsf.datamodel.IDMContext;
-import org.eclipse.dd.dsf.datamodel.IDMEvent;
-import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.DelayedStackRefreshUpdatePolicy;
-import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.FullStackRefreshEvent;
+import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.AbstractLaunchVMProvider;
 import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode;
 import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode;
 import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode;
-import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent;
-import org.eclipse.dd.dsf.debug.service.IRunControl;
-import org.eclipse.dd.dsf.debug.service.IRunControl.IExecutionDMContext;
-import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent;
 import org.eclipse.dd.dsf.service.DsfSession;
 import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter;
 import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode;
-import org.eclipse.dd.dsf.ui.viewmodel.IVMModelProxy;
 import org.eclipse.dd.dsf.ui.viewmodel.IVMNode;
-import org.eclipse.dd.dsf.ui.viewmodel.datamodel.AbstractDMVMProvider;
-import org.eclipse.dd.dsf.ui.viewmodel.update.IVMUpdatePolicy;
 import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.GDBExitedEvent;
 import org.eclipse.dd.gdb.internal.provisional.service.command.GDBControl.GDBStartedEvent;
 import org.eclipse.dd.mi.service.command.MIInferiorProcess.InferiorExitedDMEvent;
 import org.eclipse.dd.mi.service.command.MIInferiorProcess.InferiorStartedDMEvent;
-import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.IDebugEventSetListener;
-import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchesListener2;
 import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
 
@@ -55,16 +34,9 @@ import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationCont
  * 
  */
 @SuppressWarnings("restriction")
-public class LaunchVMProvider extends AbstractDMVMProvider 
+public class LaunchVMProvider extends AbstractLaunchVMProvider 
     implements IDebugEventSetListener, ILaunchesListener2
 {
-    /**
-	 * Delay (in milliseconds) before a full stack trace will be requested.
-	 */
-	private static final int FRAME_UPDATE_DELAY= 200;
-	
-    private final Map<IExecutionDMContext,ScheduledFuture<?>> fRefreshStackFramesFutures = new HashMap<IExecutionDMContext,ScheduledFuture<?>>();
-
 	@ThreadSafe
     public LaunchVMProvider(AbstractVMAdapter adapter, IPresentationContext presentationContext, DsfSession session)
     {
@@ -89,85 +61,6 @@ public class LaunchVMProvider extends AbstractDMVMProvider
         DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
     }
     
-    @Override
-	protected IVMUpdatePolicy[] createUpdateModes() {
-		return new IVMUpdatePolicy[] { new DelayedStackRefreshUpdatePolicy() };
-    }
-    
-    public void handleDebugEvents(final DebugEvent[] events) {
-        if (isDisposed()) return;
-        
-        // We're in session's executor thread.  Re-dispach to VM Adapter 
-        // executor thread and then call root layout node.
-        try {
-            getExecutor().execute(new Runnable() {
-                public void run() {
-                    if (isDisposed()) return;
-    
-                    for (final DebugEvent event : events) {
-                        handleEvent(event);
-                    }
-                }});
-        } catch (RejectedExecutionException e) {
-            // Ignore.  This exception could be thrown if the provider is being 
-            // shut down.  
-        }
-    }
-
-    @Override
-    protected void handleEvent(IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) {
-    	super.handleEvent(proxyStrategy, event, rm);
-    	
-		if (event instanceof IRunControl.ISuspendedDMEvent) {
-    		final IExecutionDMContext exeContext= ((IRunControl.ISuspendedDMEvent) event).getDMContext();
-    		ScheduledFuture<?> refreshStackFramesFuture = getRefreshFuture(exeContext);
-    		// trigger delayed full stack frame update
-    		if (refreshStackFramesFuture != null) {
-    			// cancel previously scheduled frame update
-    			refreshStackFramesFuture.cancel(false);
-    		}
-
-    		refreshStackFramesFuture = getSession().getExecutor().schedule(
-	            new DsfRunnable() { 
-	                public void run() {
-	                    if (getSession().isActive()) {
-	                        getExecutor().execute(new Runnable() {
-	                            public void run() {
-	                                // trigger full stack frame update
-	                                ScheduledFuture<?> future= fRefreshStackFramesFutures.get(exeContext);
-	                                if (future != null && !isDisposed()) {
-	                                    fRefreshStackFramesFutures.remove(exeContext);
-	                                    handleEvent(new FullStackRefreshEvent(exeContext));
-	                                }
-	                            }});
-	                    }
-	                }
-	            },
-			    FRAME_UPDATE_DELAY, TimeUnit.MILLISECONDS);
-			fRefreshStackFramesFutures.put(exeContext, refreshStackFramesFuture);
-    	} else if (event instanceof IRunControl.IResumedDMEvent) {
-    		IExecutionDMContext exeContext= ((IRunControl.IResumedDMEvent) event).getDMContext();
-    		ScheduledFuture<?> refreshStackFramesFuture= fRefreshStackFramesFutures.get(exeContext);
-    		if (refreshStackFramesFuture != null) {
-    			// cancel previously scheduled frame update
-    			refreshStackFramesFuture.cancel(false);
-    			fRefreshStackFramesFutures.remove(exeContext);
-    		}
-    	}
-    }
-
-    /**
-     * Returns the future for the given execution context or for any child of the 
-     * given execution context.
-     */
-    private ScheduledFuture<?> getRefreshFuture(IExecutionDMContext execCtx) {
-        for (IExecutionDMContext refreshCtx : fRefreshStackFramesFutures.keySet()) {
-            if (refreshCtx.equals(execCtx) || DMContexts.isAncestorOf(refreshCtx, execCtx)) {
-                return fRefreshStackFramesFutures.remove(refreshCtx);
-            }
-        }
-        return null;
-    }
     
     @Override
     public void dispose() {
@@ -176,42 +69,6 @@ public class LaunchVMProvider extends AbstractDMVMProvider
         super.dispose();
     }
     
-    public void launchesAdded(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.ADDED)); 
-    }
-    
-    public void launchesRemoved(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.REMOVED)); 
-    }
-    
-    public void launchesChanged(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.CHANGED)); 
-    }
-    
-    public void launchesTerminated(ILaunch[] launches) {
-        handleLaunchesEvent(new LaunchesEvent(launches, LaunchesEvent.Type.TERMINATED)); 
-    }
-    
-    private void handleLaunchesEvent(final LaunchesEvent event) {
-        if (isDisposed()) return;
-        
-        // We're in session's executor thread.  Re-dispach to VM Adapter 
-        // executor thread and then call root layout node.
-        try {
-            getExecutor().execute(new Runnable() {
-                public void run() {
-                    if (isDisposed()) return;
-    
-                    IRootVMNode rootLayoutNode = getRootVMNode();
-                    if (rootLayoutNode != null && rootLayoutNode.getDeltaFlags(event) != 0) {
-                        handleEvent(event);
-                    }
-                }});
-        } catch (RejectedExecutionException e) {
-            // Ignore.  This exception could be thrown if the provider is being 
-            // shut down.  
-        }
-    }
     
     @Override
     protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) {
@@ -223,22 +80,7 @@ public class LaunchVMProvider extends AbstractDMVMProvider
         {
             return false;
         }
-        
-
-        // To optimize view performance when stepping rapidly, skip events that came 
-        // before the last suspended events.  However, the debug view can get suspended
-        // events for different threads, so make sure to skip only the events if they
-        // were in the same hierarchy as the last suspended event.
-        if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent<?>) {
-            IDMContext newEventDmc = ((IDMEvent<?>)newEvent).getDMContext();
-            IDMContext eventToSkipDmc = ((IDMEvent<?>)eventToSkip).getDMContext();
-            
-            if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) {
-                return true;
-            }
-        }
-        
-        return false;
+        return super.canSkipHandlingEvent(newEvent, eventToSkip);
     }
 
 }