Browse Source

removed buffering context, enabled single stepping

Andreas Mülder 13 years ago
parent
commit
7d4066f5b7

+ 0 - 158
plugins/org.yakindu.sct.model.sexec.interpreter/src/org/yakindu/sct/model/sexec/interpreter/impl/BufferingExecutionContext.java

@@ -1,158 +0,0 @@
-/**
- * Copyright (c) 2012 committers of YAKINDU 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:
- *     committers of YAKINDU - initial API and implementation
- */
-package org.yakindu.sct.model.sexec.interpreter.impl;
-
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import org.yakindu.sct.model.sexec.ExecutionRegion;
-import org.yakindu.sct.model.sexec.ExecutionState;
-import org.yakindu.sct.model.sgraph.RegularState;
-import org.yakindu.sct.simulation.core.runtime.ExecutionException;
-import org.yakindu.sct.simulation.core.runtime.IExecutionContext;
-import org.yakindu.sct.simulation.core.runtime.IExecutionContextListener;
-import org.yakindu.sct.simulation.core.runtime.impl.ExecutionContextImpl;
-import org.yakindu.sct.simulation.core.runtime.impl.ExecutionEvent;
-import org.yakindu.sct.simulation.core.runtime.impl.ExecutionVariable;
-import org.yakindu.sct.simulation.core.runtime.timer.VirtualClock;
-
-public class BufferingExecutionContext extends ExecutionContextImpl implements IExecutionContextListener {
-
-	protected IExecutionContext delegate;
-	protected boolean delegateNotify = true;
-
-	private HashMap<String, Object> setVariables = new HashMap<String, Object>();
-
-	
-	public BufferingExecutionContext(IExecutionContext delegate) {
-		this.delegate = delegate;
-		delegate.addExecutionContextListener(this);
-	}
-
-	public List<ExecutionEvent> getDeclaredEvents() {
-		return delegate.getDeclaredEvents();
-	}
-
-	public void declareEvent(ExecutionEvent event) {
-		delegate.declareEvent(event);
-	}
-
-
-	public void resetRaisedEvents() {
-		delegate.resetRaisedEvents();
-	}
-
-	
-	public ExecutionEvent getDeclaredEvent(String eventName) {
-		return delegate.getDeclaredEvent(eventName);
-	}
-
-	public boolean isEventRaised(String eventName) {
-		return delegate.isEventRaised(eventName);
-	}
-
-	public List<ExecutionVariable> getVariables() {
-		return delegate.getVariables();
-	}
-
-	public void declareVariable(ExecutionVariable variable) {
-		delegate.declareVariable(variable);
-	}
-
-	public ExecutionVariable getVariable(String varName) {
-		return delegate.getVariable(varName);
-	}
-
-	public void setVariableValue(String name, Object value)
-			throws ExecutionException {
-		synchronized (setVariables) {
-			setVariables.put(name, value);
-		}
-	}
-
-	public void flush() {
-		synchronized (raisedEvents) {
-			delegateNotify = false;
-			for (ExecutionEvent event : raisedEvents) {
-				delegate.raiseEvent(event.getName(), event.getValue());
-			}
-			raisedEvents.clear();
-			delegateNotify = true;
-		}
-		synchronized (setVariables) {
-			Set<Entry<String, Object>> entrySet = setVariables.entrySet();
-			for (Entry<String, Object> entry : entrySet) {
-				delegate.setVariableValue(entry.getKey(), entry.getValue());
-			}
-			setVariables.clear();
-		}
-	}
-
-	public Set<RegularState> getActiveLeafStates() {
-		return delegate.getActiveLeafStates();
-	}
-
-	public Set<RegularState> getAllActiveStates() {
-		return delegate.getAllActiveStates();
-	}
-
-	public ExecutionState[] getStateConfiguration() {
-		return delegate.getStateConfiguration();
-	}
-
-	public void initStateConfigurationVector(int size) {
-		delegate.initStateConfigurationVector(size);
-	}
-
-	public void call(String procedureId) {
-		delegate.call(procedureId);
-	}
-
-	public double getTimeScaleFactor() {
-		return delegate.getTimeScaleFactor();
-	}
-
-	public void setTimeScaleFactor(double factor) {
-		delegate.setTimeScaleFactor(factor);
-	}
-
-	public VirtualClock getVirtualClock() {
-		return delegate.getVirtualClock();
-	}
-
-	public ExecutionState getHistoryStateConfiguration(ExecutionRegion region) {
-		return delegate.getHistoryStateConfiguration(region);
-	}
-
-	public void saveHistoryStateConfiguration(ExecutionRegion region) {
-		delegate.saveHistoryStateConfiguration(region);
-	}
-
-
-	public void eventRaised(ExecutionEvent event) {
-		if ( delegateNotify ) {
-			notifyEventRaised(event);
-		}
-	}
-
-	public void variableValueChanged(ExecutionVariable variable) {
-		notifyVariableValueChanged(variable);
-		
-	}
-
-	public void timeScaleFactorChanged(double oldFactor, double newFactor) {
-		notifyTimeScaleFactorChanged(oldFactor, newFactor);
-	}
-
-	
-}

+ 7 - 9
plugins/org.yakindu.sct.model.sexec.interpreter/src/org/yakindu/sct/model/sexec/interpreter/impl/ExecutionFlowInterpreter.xtend

@@ -58,7 +58,6 @@ class ExecutionFlowInterpreter extends AbstractExecutionFacade implements IExecu
 	IStatementInterpreter interpreter
 	@Inject
 	IExecutionContext executionContext
-	BufferingExecutionContext externalExecutionContext
 	@Inject
 	StextNameProvider provider
 	@Inject 
@@ -78,7 +77,6 @@ class ExecutionFlowInterpreter extends AbstractExecutionFacade implements IExecu
 
 	override initialize(ExecutionFlow flow) {
 		this.flow = flow;
-		externalExecutionContext = new BufferingExecutionContext(executionContext)
 		for(scope : flow.scopes){
 			scope.declareContents
 		} 
@@ -101,10 +99,6 @@ class ExecutionFlowInterpreter extends AbstractExecutionFacade implements IExecu
 		interpreterName
 	}
 	
-	override getExecutionContext(){
-		return externalExecutionContext
-	}
-	
 	def dispatch declareContents(InternalScope scope) {
 		for(declaration : scope.declarations){
 				declaration.addToScope
@@ -124,8 +118,7 @@ class ExecutionFlowInterpreter extends AbstractExecutionFacade implements IExecu
 	}
 	
 	override runCycle() {
-		
-		externalExecutionContext.flush
+		executionContext.flush
 		
 		nextSVIdx = 0; // this is a member that can be manipulated during state reactions in case of orthogonality
 		
@@ -288,7 +281,7 @@ class ExecutionFlowInterpreter extends AbstractExecutionFacade implements IExecu
 	def dispatch execute(ScheduleTimeEvent scheduleTimeEvent){
 		var timeEvent = scheduleTimeEvent.timeEvent
 		var duration = interpreter.evaluateStatement(scheduleTimeEvent.timeValue, executionContext)
-		timingService.scheduleTimeEvent(externalExecutionContext,timeEvent.name,timeEvent.periodic, duration as Integer)
+		timingService.scheduleTimeEvent(executionContext,timeEvent.name,timeEvent.periodic, duration as Integer)
 		null
 	}
 	
@@ -308,4 +301,9 @@ class ExecutionFlowInterpreter extends AbstractExecutionFacade implements IExecu
 	override void timeScaleFactorChanged(double oldFactor, double newFactor){
 		timingService.setTimeScaleFactor(newFactor)
 	}
+
+	override getExecutionContext() {
+		return executionContext;
+	}
+	
 }

+ 6 - 11
plugins/org.yakindu.sct.model.sexec.interpreter/xtend-gen/org/yakindu/sct/model/sexec/interpreter/impl/ExecutionFlowInterpreter.java

@@ -37,7 +37,6 @@ import org.yakindu.sct.model.sexec.UnscheduleTimeEvent;
 import org.yakindu.sct.model.sexec.interpreter.IExecutionFlowInterpreter;
 import org.yakindu.sct.model.sexec.interpreter.IStatementInterpreter;
 import org.yakindu.sct.model.sexec.interpreter.ITimingService;
-import org.yakindu.sct.model.sexec.interpreter.impl.BufferingExecutionContext;
 import org.yakindu.sct.model.sgraph.Declaration;
 import org.yakindu.sct.model.sgraph.Scope;
 import org.yakindu.sct.model.sgraph.Statement;
@@ -64,8 +63,6 @@ public class ExecutionFlowInterpreter extends AbstractExecutionFacade implements
   @Inject
   private IExecutionContext executionContext;
   
-  private BufferingExecutionContext externalExecutionContext;
-  
   @Inject
   private StextNameProvider provider;
   
@@ -89,8 +86,6 @@ public class ExecutionFlowInterpreter extends AbstractExecutionFacade implements
   
   public void initialize(final ExecutionFlow flow) {
     this.flow = flow;
-    BufferingExecutionContext _bufferingExecutionContext = new BufferingExecutionContext(this.executionContext);
-    this.externalExecutionContext = _bufferingExecutionContext;
     EList<Scope> _scopes = flow.getScopes();
     for (final Scope scope : _scopes) {
       this.declareContents(scope);
@@ -117,10 +112,6 @@ public class ExecutionFlowInterpreter extends AbstractExecutionFacade implements
     return this.interpreterName;
   }
   
-  public IExecutionContext getExecutionContext() {
-    return this.externalExecutionContext;
-  }
-  
   protected void _declareContents(final InternalScope scope) {
     EList<Declaration> _declarations = scope.getDeclarations();
     for (final Declaration declaration : _declarations) {
@@ -143,7 +134,7 @@ public class ExecutionFlowInterpreter extends AbstractExecutionFacade implements
   }
   
   public void runCycle() {
-    this.externalExecutionContext.flush();
+    this.executionContext.flush();
     this.nextSVIdx = 0;
     this.execute(this.brc);
     ExecutionState[] _stateConfiguration = this.executionContext.getStateConfiguration();
@@ -454,7 +445,7 @@ public class ExecutionFlowInterpreter extends AbstractExecutionFacade implements
       Object duration = this.interpreter.evaluateStatement(_timeValue, this.executionContext);
       String _name = timeEvent.getName();
       boolean _isPeriodic = timeEvent.isPeriodic();
-      this.timingService.scheduleTimeEvent(this.externalExecutionContext, _name, _isPeriodic, (((Integer) duration)).intValue());
+      this.timingService.scheduleTimeEvent(this.executionContext, _name, _isPeriodic, (((Integer) duration)).intValue());
       _xblockexpression = (null);
     }
     return _xblockexpression;
@@ -481,6 +472,10 @@ public class ExecutionFlowInterpreter extends AbstractExecutionFacade implements
     this.timingService.setTimeScaleFactor(newFactor);
   }
   
+  public IExecutionContext getExecutionContext() {
+    return this.executionContext;
+  }
+  
   public void declareContents(final Scope scope) {
     if (scope instanceof InterfaceScope) {
       _declareContents((InterfaceScope)scope);

+ 10 - 0
plugins/org.yakindu.sct.simulation.core/src/org/yakindu/sct/simulation/core/runtime/IExecutionContext.java

@@ -42,11 +42,17 @@ public interface IExecutionContext {
 	 */
 	public List<ExecutionEvent> getRaisedEvents();
 
+	public List<ExecutionEvent> getScheduledEvents();
+
 	/**
 	 * Clears the collection of raised events
 	 */
 	public void resetRaisedEvents();
 
+	public void unraiseEvent(String eventName);
+
+	public void flush();
+
 	/**
 	 * Raises an event with an value, can be null
 	 * 
@@ -61,6 +67,8 @@ public interface IExecutionContext {
 	 */
 	public boolean isEventRaised(String eventName);
 
+	public boolean isEventScheduled(String name);
+
 	/**
 	 * Returns a readonly (!) List of all variables
 	 */
@@ -132,4 +140,6 @@ public interface IExecutionContext {
 
 	public abstract ExecutionEvent getDeclaredEvent(String eventName);
 
+	public void unscheduleEvent(String eventName);
+
 }

+ 7 - 32
plugins/org.yakindu.sct.simulation.core/src/org/yakindu/sct/simulation/core/runtime/impl/EventDrivenExecutionFacadeController.java

@@ -11,33 +11,23 @@
 
 package org.yakindu.sct.simulation.core.runtime.impl;
 
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-
-import org.yakindu.sct.simulation.core.runtime.IExecutionContextListener;
+import org.yakindu.sct.simulation.core.runtime.IExecutionContext;
 import org.yakindu.sct.simulation.core.runtime.IExecutionFacade;
 import org.yakindu.sct.simulation.core.runtime.IExecutionFacadeController;
 
 /**
  * Event Driven implementation of the {@link IExecutionFacadeController}.
  * 
- * RunCycle is invoked on the {@link IExecutionFacade} each time a event is
- * raised.
- * 
  * @author andreas muelder - Initial contribution and API
  * 
  */
 public class EventDrivenExecutionFacadeController extends
-		AbstractExecutionFacadeController implements IExecutionContextListener {
+		AbstractExecutionFacadeController {
 
 	private Thread cycleRunner;
 
-	private BlockingQueue<ExecutionEvent> events;
-
 	public EventDrivenExecutionFacadeController(IExecutionFacade facade) {
 		super(facade);
-		facade.getExecutionContext().addExecutionContextListener(this);
-		events = new LinkedBlockingQueue<ExecutionEvent>();
 	}
 
 	public void start() {
@@ -60,30 +50,15 @@ public class EventDrivenExecutionFacadeController extends
 		super.terminate();
 	}
 
-	public void eventRaised(ExecutionEvent event) {
-		events.add(event);
-	}
-
-	public void variableValueChanged(ExecutionVariable variable) {
-		// Nothing to do
-	}
-
 	private final class CycleRunner implements Runnable {
 		public void run() {
-			try {
-				while (!terminated && !suspended) {
-					events.take();
-					if (facade.getExecutionContext().getRaisedEvents().size() > 0) {
-						facade.runCycle();
-					}
+			while (!terminated && !suspended) {
+				IExecutionContext context = facade.getExecutionContext();
+				if (context.getRaisedEvents().size() > 0
+						|| context.getScheduledEvents().size() > 0) {
+					facade.runCycle();
 				}
-			} catch (InterruptedException e) {
-				e.printStackTrace();
 			}
 		}
 	}
-
-	public void timeScaleFactorChanged(double oldFactor, double newFactor) {
-
-	}
 }

+ 64 - 1
plugins/org.yakindu.sct.simulation.core/src/org/yakindu/sct/simulation/core/runtime/impl/ExecutionContextImpl.java

@@ -14,6 +14,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -28,7 +29,6 @@ import org.yakindu.sct.simulation.core.runtime.IExecutionContext;
 import org.yakindu.sct.simulation.core.runtime.timer.VirtualClock;
 
 import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
 
 /**
  * 
@@ -40,6 +40,7 @@ public class ExecutionContextImpl extends AbstractExecutionContext implements
 
 	private List<ExecutionVariable> variables;
 	private List<ExecutionEvent> declaredEvents;
+	protected List<ExecutionEvent> scheduledToRaiseEvents;
 	protected List<ExecutionEvent> raisedEvents;
 	private ExecutionState[] activeStateConfig;
 	private Map<Integer, ExecutionState> historyStateConfig;
@@ -50,6 +51,7 @@ public class ExecutionContextImpl extends AbstractExecutionContext implements
 		variables = new ArrayList<ExecutionVariable>();
 		declaredEvents = new ArrayList<ExecutionEvent>();
 		raisedEvents = new ArrayList<ExecutionEvent>();
+		scheduledToRaiseEvents = new ArrayList<ExecutionEvent>();
 		timeScaleFactor = 1.0d;
 		virtualClock = new VirtualClock();
 		activeStateConfig = null;
@@ -62,6 +64,12 @@ public class ExecutionContextImpl extends AbstractExecutionContext implements
 		}
 	}
 
+	public List<ExecutionEvent> getScheduledToRaiseEvents() {
+		synchronized (scheduledToRaiseEvents) {
+			return Collections.unmodifiableList(scheduledToRaiseEvents);
+		}
+	}
+
 	public void declareEvent(ExecutionEvent event) {
 		synchronized (declaredEvents) {
 			declaredEvents.add(event);
@@ -71,6 +79,10 @@ public class ExecutionContextImpl extends AbstractExecutionContext implements
 	public List<ExecutionEvent> getRaisedEvents() {
 		return Collections.unmodifiableList(raisedEvents);
 	}
+	
+	public List<ExecutionEvent> getScheduledEvents() {
+		return Collections.unmodifiableList(scheduledToRaiseEvents);
+	}
 
 	public void resetRaisedEvents() {
 		synchronized (raisedEvents) {
@@ -79,6 +91,18 @@ public class ExecutionContextImpl extends AbstractExecutionContext implements
 	}
 
 	public void raiseEvent(String eventName, Object value) {
+		ExecutionEvent event = getDeclaredEvent(eventName);
+		if (event == null)
+			throw new ExecutionException("Event with name " + eventName
+					+ " is undefined!");
+		ExecutionEvent eventCopy = event.getCopy();
+		if (value != null) {
+			eventCopy.setValue(value);
+		}
+		scheduledToRaiseEvents.add(eventCopy);
+	}
+
+	protected void raiseEventInternal(String eventName, Object value) {
 		synchronized (raisedEvents) {
 			ExecutionEvent event = getDeclaredEvent(eventName);
 			if (event == null)
@@ -93,6 +117,13 @@ public class ExecutionContextImpl extends AbstractExecutionContext implements
 		}
 	}
 
+	public void flush() {
+		for (ExecutionEvent event : scheduledToRaiseEvents) {
+			raiseEventInternal(event.getName(), event.getValue());
+		}
+		scheduledToRaiseEvents.clear();
+	}
+
 	@Override
 	public ExecutionEvent getDeclaredEvent(String eventName) {
 		synchronized (declaredEvents) {
@@ -218,4 +249,36 @@ public class ExecutionContextImpl extends AbstractExecutionContext implements
 	public VirtualClock getVirtualClock() {
 		return virtualClock;
 	}
+
+	public void unraiseEvent(String eventName) {
+		synchronized (raisedEvents) {
+			Iterator<ExecutionEvent> iterator = raisedEvents.iterator();
+			while (iterator.hasNext()) {
+				if (iterator.next().getName().equals(eventName)) {
+					iterator.remove();
+				}
+			}
+		}
+	}
+	public void unscheduleEvent(String eventName) {
+		synchronized (scheduledToRaiseEvents) {
+			Iterator<ExecutionEvent> iterator = scheduledToRaiseEvents.iterator();
+			while (iterator.hasNext()) {
+				if (iterator.next().getName().equals(eventName)) {
+					iterator.remove();
+				}
+			}
+		}
+	}
+
+	public boolean isEventScheduled(String name) {
+		synchronized (scheduledToRaiseEvents) {
+			for (ExecutionEvent event : scheduledToRaiseEvents) {
+				if (name.equals(event.getName())) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
 }

BIN
plugins/org.yakindu.sct.simulation.ui/icons/Event_disabled.gif


BIN
plugins/org.yakindu.sct.simulation.ui/icons/Event_enabled.gif


+ 0 - 1
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/ExecutionContextContentProvider.java

@@ -131,7 +131,6 @@ public class ExecutionContextContentProvider implements ITreeContentProvider,
 	}
 
 	public void eventRaised(ExecutionEvent event) {
-		System.out.println("raised " + event.getName());
 	}
 	
 	public void timeScaleFactorChanged(double oldFactor, double newFactor) {

+ 68 - 43
plugins/org.yakindu.sct.simulation.ui/src/org/yakindu/sct/simulation/ui/view/SimulationView.java

@@ -10,7 +10,8 @@
  */
 package org.yakindu.sct.simulation.ui.view;
 
-import org.apache.commons.lang.time.DurationFormatUtils;
+import static org.apache.commons.lang.time.DurationFormatUtils.formatDuration;
+
 import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.PlatformObject;
 import org.eclipse.debug.core.DebugEvent;
@@ -70,6 +71,7 @@ public class SimulationView extends ViewPart implements IDebugContextListener,
 		IDebugEventSetListener {
 
 	private static final String INITIAL_TIME = "00:00:00:00";
+
 	private TreeViewer viewer;
 	private SCTDebugTarget debugTarget;
 	private Text scaleFactor;
@@ -183,7 +185,7 @@ public class SimulationView extends ViewPart implements IDebugContextListener,
 
 	private void createClocks(Composite parent) {
 		// Virtual Clock
-		Label label = kit.createLabel(parent, "virtual time:");
+		Label label = kit.createLabel(parent, "scaled time:");
 		GridDataFactory.fillDefaults().applyTo(label);
 		lblVirtualTime = new Label(parent, SWT.NONE);
 		lblVirtualTime.setFont(font);
@@ -192,7 +194,7 @@ public class SimulationView extends ViewPart implements IDebugContextListener,
 		GridDataFactory.fillDefaults().grab(true, false).span(2, 0)
 				.applyTo(lblVirtualTime);
 		// Real time clock
-		Label label2 = kit.createLabel(parent, "real time:");
+		Label label2 = kit.createLabel(parent, "time:");
 		GridDataFactory.fillDefaults().applyTo(label2);
 		lblRealTime = new Label(parent, SWT.NONE);
 		lblRealTime.setFont(font);
@@ -239,10 +241,17 @@ public class SimulationView extends ViewPart implements IDebugContextListener,
 				Object firstElement = ((IStructuredSelection) event
 						.getSelection()).getFirstElement();
 				if (firstElement instanceof ExecutionEvent) {
+					ExecutionEvent casted = (ExecutionEvent) firstElement;
 					IExecutionContext input = (IExecutionContext) viewer
 							.getInput();
-					input.raiseEvent(((ExecutionEvent) firstElement).getName(),
-							null);
+					if (input.isEventRaised(casted.getName())) {
+						input.unraiseEvent(casted.getName());
+					} else if (input.isEventScheduled(casted.getName())) {
+						input.unscheduleEvent(casted.getName());
+					} else {
+						input.raiseEvent(casted.getName(), null);
+					}
+					viewer.refresh();
 				}
 			}
 		});
@@ -288,6 +297,12 @@ public class SimulationView extends ViewPart implements IDebugContextListener,
 				}
 			});
 			break;
+		case DebugEvent.SUSPEND:
+			getClock().suspend();
+			break;
+		case DebugEvent.RESUME:
+			getClock().resume();
+			break;
 		}
 	}
 
@@ -309,56 +324,30 @@ public class SimulationView extends ViewPart implements IDebugContextListener,
 		mgr.add(hideTimeEvent);
 	}
 
+	protected VirtualClock getClock() {
+		IExecutionFacade facade = (IExecutionFacade) debugTarget
+				.getAdapter(IExecutionFacade.class);
+		VirtualClock virtualClock = facade.getExecutionContext()
+				.getVirtualClock();
+		return virtualClock;
+	}
+
 	public class ClockUpdater implements Runnable {
 
-		private static final String PATTERN = "HH:mm:ss:SS";
 		private boolean terminated = false;
+		private UpdateUIThread updateUI = new UpdateUIThread();
+		private StopClock resetLabel = new StopClock();
 
 		public void run() {
 			while (!terminated) {
-				Display.getDefault().asyncExec(new Runnable() {
-					public void run() {
-						IExecutionFacade facade = (IExecutionFacade) debugTarget
-								.getAdapter(IExecutionFacade.class);
-						VirtualClock virtualClock = facade
-								.getExecutionContext().getVirtualClock();
-						if (virtualClock.getStartTime() > 0) {
-							if (lblVirtualTime != null
-									&& !lblVirtualTime.isDisposed()) {
-								String text = DurationFormatUtils
-										.formatDuration(virtualClock.getTime()
-												- virtualClock.getStartTime(),
-												PATTERN);
-								lblVirtualTime.setText(text);
-							}
-							if (lblRealTime != null
-									&& !lblRealTime.isDisposed()) {
-								String text = DurationFormatUtils.formatDuration(
-										System.currentTimeMillis()
-												- virtualClock.getStartTime(),
-										PATTERN);
-								lblRealTime.setText(text);
-							}
-						}
-					}
-				});
+				Display.getDefault().asyncExec(updateUI);
 				try {
 					Thread.sleep(100);
 				} catch (InterruptedException e) {
 					e.printStackTrace();
 				}
 			}
-			// reset the lbls when updater terminated
-			Display.getDefault().asyncExec(new Runnable() {
-				public void run() {
-					if (lblRealTime != null && !lblRealTime.isDisposed()) {
-						lblRealTime.setText(INITIAL_TIME);
-					}
-					if (lblVirtualTime != null && !lblVirtualTime.isDisposed()) {
-						lblVirtualTime.setText(INITIAL_TIME);
-					}
-				}
-			});
+			Display.getDefault().asyncExec(resetLabel);
 		}
 
 		public boolean isTerminated() {
@@ -370,4 +359,40 @@ public class SimulationView extends ViewPart implements IDebugContextListener,
 		}
 	}
 
+	private final class StopClock implements Runnable {
+		public void run() {
+			if (lblRealTime != null && !lblRealTime.isDisposed()) {
+				lblRealTime.setText(INITIAL_TIME);
+			}
+			if (lblVirtualTime != null && !lblVirtualTime.isDisposed()) {
+				lblVirtualTime.setText(INITIAL_TIME);
+			}
+		}
+	}
+
+	private final class UpdateUIThread implements Runnable {
+
+		private static final String PATTERN = "HH:mm:ss:SS";
+
+		public void run() {
+			// if (!debugTarget.isSuspended()) {
+			VirtualClock virtualClock = getClock();
+			if (virtualClock.getStartTime() > 0) {
+				if (lblVirtualTime != null && !lblVirtualTime.isDisposed()) {
+					String text = formatDuration(virtualClock.getTime()
+							- virtualClock.getStartTime(), PATTERN);
+					lblVirtualTime.setText(text);
+				}
+				if (lblRealTime != null && !lblRealTime.isDisposed()) {
+					String text = formatDuration(
+							System.currentTimeMillis()
+									- virtualClock.getPauseTime()
+									- virtualClock.getStartTime(), PATTERN);
+					lblRealTime.setText(text);
+				}
+			}
+			// }
+		}
+	}
+
 }