Merge remote-tracking branch 'origin/master' into BETA_JAVA11
diff --git a/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/ConsoleTerminateAllActionTests.java b/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/ConsoleTerminateAllActionTests.java
index 0485e47..314941e 100644
--- a/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/ConsoleTerminateAllActionTests.java
+++ b/org.eclipse.jdt.debug.tests/console tests/org/eclipse/jdt/debug/tests/console/ConsoleTerminateAllActionTests.java
@@ -14,8 +14,10 @@
 
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.internal.ui.commands.actions.TerminateAllActionDelegate;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.debug.tests.TestUtil;
 import org.eclipse.ui.IViewPart;
 import org.eclipse.ui.IWorkbenchPage;
 import org.eclipse.ui.IWorkbenchWindow;
@@ -53,6 +55,8 @@
 				assertNotNull(thread1);
 				thread2 = launchToBreakpoint("TerminateAll_02");
 				assertNotNull(thread2);
+				// wait for the Console View to be shown by the output in the launched snippet
+				TestUtil.waitForJobs(getName(), 100, DEFAULT_TIMEOUT, ProcessConsole.class);
 				ConsoleView view = null;
 				IWorkbenchWindow[] workbenchWindows = PlatformUI.getWorkbench().getWorkbenchWindows();
 				for (int i = 0; i < workbenchWindows.length; i++) {
@@ -72,7 +76,9 @@
 				TerminateAllActionDelegate d = new TerminateAllActionDelegate();
 				d.init(view);
 				d.run(null);
-				Thread.sleep(1000);
+				Thread.sleep(1_000);
+				// wait for the terminate action to finish
+				TestUtil.waitForJobs(getName(), 100, DEFAULT_TIMEOUT, ProcessConsole.class);
 				assertEquals(2, DebugPlugin.getDefault().getLaunchManager().getLaunches().length);
 				assertEquals(true, DebugPlugin.getDefault().getLaunchManager().getLaunches()[0].isTerminated());
 				assertEquals(true, DebugPlugin.getDefault().getLaunchManager().getLaunches()[1].isTerminated());
diff --git a/org.eclipse.jdt.debug.tests/testprograms/MethodCall.java b/org.eclipse.jdt.debug.tests/testprograms/MethodCall.java
new file mode 100644
index 0000000..640eb53
--- /dev/null
+++ b/org.eclipse.jdt.debug.tests/testprograms/MethodCall.java
@@ -0,0 +1,29 @@
+/*******************************************************************************
+ * Copyright (c) 2018 Simeon Andreev 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:
+ *     Simeon Andreev - initial API and implementation
+ *******************************************************************************/
+
+public class MethodCall {
+
+	private int i;
+	private int sum = 0;
+
+	public static void main(String[] args) {
+		MethodCall mc = new MethodCall();
+		mc.go();
+	}
+
+	public void go() {
+		calculateSum();
+	}
+
+	protected void calculateSum() {
+		sum += i;
+	}
+}
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java
index 08afb03..b3c6cc0 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/test/stepping/StepResultTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2017 Till Brychcy and others.
+ * Copyright (c) 2018 Till Brychcy 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
@@ -10,6 +10,8 @@
  *******************************************************************************/
 package org.eclipse.jdt.debug.test.stepping;
 
+import org.eclipse.core.runtime.preferences.DefaultScope;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
 import org.eclipse.debug.core.model.ILineBreakpoint;
 import org.eclipse.debug.core.model.IStackFrame;
 import org.eclipse.debug.core.model.IVariable;
@@ -20,7 +22,9 @@
 import org.eclipse.jdt.debug.core.IJavaStackFrame;
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.core.IJavaValue;
+import org.eclipse.jdt.debug.core.JDIDebugModel;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
 import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants;
 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
 import org.eclipse.jface.preference.IPreferenceStore;
@@ -535,4 +539,31 @@
 		}
 	}
 
+	public void testNoReturnValueAfterStepReturnWhichExceedsTimeout() throws Exception {
+		IEclipsePreferences node = DefaultScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
+		int origPrefValue = node.getInt(JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, JDIDebugModel.DEF_SHOW_STEP_TIMEOUT);
+		node.putInt(JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, -1);
+
+		String typeName = "StepResult1";
+		ILineBreakpoint bp1 = createLineBreakpoint(28, "StepResult1");
+		bp1.setEnabled(true);
+
+		IJavaThread thread = null;
+		try {
+			thread = launchToLineBreakpoint(typeName, bp1, false);
+			IJavaStackFrame stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
+			assertEquals("h", stackFrame.getMethodName());
+
+			thread = stepReturn(stackFrame);
+			stackFrame = (IJavaStackFrame) thread.getTopStackFrame();
+			assertEquals("g", stackFrame.getMethodName());
+			IVariable varInG = stackFrame.getVariables()[0];
+			assertEquals("no method return value", varInG.getName());
+			assertEquals("(Not observed to speed up the long running step operation)", varInG.getValue().toString());
+		} finally {
+			node.putInt(JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, origPrefValue);
+			terminateAndRemove(thread);
+			removeAllBreakpoints();
+		}
+	}
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
index aaa5fa2..ba30b29 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AbstractDebugTest.java
@@ -199,7 +199,7 @@
 			"org.eclipse.debug.tests.targets.HcrClass5", "org.eclipse.debug.tests.targets.HcrClass6", "org.eclipse.debug.tests.targets.HcrClass7", "org.eclipse.debug.tests.targets.HcrClass8",
 			"org.eclipse.debug.tests.targets.HcrClass9", "TestContributedStepFilterClass", "TerminateAll_01", "TerminateAll_02", "StepResult1",
 			"StepResult2", "StepResult3", "StepUncaught", "TriggerPoint_01", "BulkThreadCreationTest", "MethodExitAndException",
-			"Bug534319earlyStart", "Bug534319lateStart", "Bug534319singleThread", "Bug534319startBetwen" };
+			"Bug534319earlyStart", "Bug534319lateStart", "Bug534319singleThread", "Bug534319startBetwen", "MethodCall" };
 
 	/**
 	 * the default timeout
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
index 1c8e529..08dd4a6 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/AutomatedSuite.java
@@ -178,44 +178,6 @@
 			addTest(new TestSuite(PListParserTests.class));
 		}
 
-	//Breakpoints tests
-		addTest(new TestSuite(TypeNameBreakpointTests.class));
-		addTest(new TestSuite(DeferredBreakpointTests.class));
-		addTest(new TestSuite(ConditionalBreakpointsTests.class));
-		addTest(new TestSuite(HitCountBreakpointsTests.class));
-		addTest(new TestSuite(ThreadFilterBreakpointsTests.class));
-		addTest(new TestSuite(SuspendVMBreakpointsTests.class));
-		addTest(new TestSuite(PreLaunchBreakpointTest.class));
-		addTest(new TestSuite(ImportBreakpointsTest.class));
-		addTest(new TestSuite(BreakpointWorkingSetTests.class));
-		addTest(new TestSuite(MethodBreakpointTests.class));
-		addTest(new TestSuite(ExceptionBreakpointTests.class));
-		addTest(new TestSuite(WatchpointTests.class));
-		addTest(new TestSuite(PatternBreakpointTests.class));
-		addTest(new TestSuite(TargetPatternBreakpointTests.class));
-		addTest(new TestSuite(BreakpointListenerTests.class));
-		addTest(new TestSuite(JavaBreakpointListenerTests.class));
-		addTest(new TestSuite(MiscBreakpointsTests.class));
-		addTest(new TestSuite(ThreadNameChangeTests.class));
-		addTest(new TestSuite(BreakpointLocationVerificationTests.class));
-		addTest(new TestSuite(RunToLineTests.class));
-		addTest(new TestSuite(TestToggleBreakpointsTarget.class));
-		addTest(new TestSuite(TriggerPointBreakpointsTests.class));
-		addTest(new TestSuite(JavaThreadEventHandlerTests.class));
-
-		if (JavaProjectHelper.isJava8Compatible()) {
-			addTest(new TestSuite(TestToggleBreakpointsTarget8.class));
-		}
-		if (JavaProjectHelper.isJava5Compatible()) {
-			addTest(new TestSuite(MethodBreakpointTests15.class));
-			addTest(new TestSuite(TestIntegerAccessUnboxing15.class));
-			addTest(new TestSuite(StepIntoSelectionWithGenerics.class));
-			addTest(new TestSuite(ConditionalBreakpointsWithGenerics.class));
-			addTest(new TestSuite(GenericsEvalTests.class));
-			addTest(new TestSuite(DetailFormatterTests.class));
-			addTest(new TestSuite(AlternateStratumTests.class));
-		}
-
 	//Sourcelookup tests
 		addTest(new TestSuite(SourceLookupTests.class));
 		addTest(new TestSuite(FolderSourceContainerTests.class));
@@ -355,5 +317,43 @@
 		if (JavaProjectHelper.isJava9Compatible()) {
 			addTest(new TestSuite(LongModulePathTests.class));
 		}
+
+		// Breakpoints tests
+		addTest(new TestSuite(TypeNameBreakpointTests.class));
+		addTest(new TestSuite(DeferredBreakpointTests.class));
+		addTest(new TestSuite(HitCountBreakpointsTests.class));
+		addTest(new TestSuite(ThreadFilterBreakpointsTests.class));
+		addTest(new TestSuite(SuspendVMBreakpointsTests.class));
+		addTest(new TestSuite(PreLaunchBreakpointTest.class));
+		addTest(new TestSuite(ImportBreakpointsTest.class));
+		addTest(new TestSuite(BreakpointWorkingSetTests.class));
+		addTest(new TestSuite(MethodBreakpointTests.class));
+		addTest(new TestSuite(ExceptionBreakpointTests.class));
+		addTest(new TestSuite(WatchpointTests.class));
+		addTest(new TestSuite(PatternBreakpointTests.class));
+		addTest(new TestSuite(TargetPatternBreakpointTests.class));
+		addTest(new TestSuite(BreakpointListenerTests.class));
+		addTest(new TestSuite(JavaBreakpointListenerTests.class));
+		addTest(new TestSuite(MiscBreakpointsTests.class));
+		addTest(new TestSuite(ThreadNameChangeTests.class));
+		addTest(new TestSuite(BreakpointLocationVerificationTests.class));
+		addTest(new TestSuite(RunToLineTests.class));
+		addTest(new TestSuite(TestToggleBreakpointsTarget.class));
+		addTest(new TestSuite(TriggerPointBreakpointsTests.class));
+		addTest(new TestSuite(JavaThreadEventHandlerTests.class));
+
+		if (JavaProjectHelper.isJava8Compatible()) {
+			addTest(new TestSuite(TestToggleBreakpointsTarget8.class));
+		}
+		if (JavaProjectHelper.isJava5Compatible()) {
+			addTest(new TestSuite(MethodBreakpointTests15.class));
+			addTest(new TestSuite(TestIntegerAccessUnboxing15.class));
+			addTest(new TestSuite(StepIntoSelectionWithGenerics.class));
+			addTest(new TestSuite(ConditionalBreakpointsWithGenerics.class));
+			addTest(new TestSuite(GenericsEvalTests.class));
+			addTest(new TestSuite(DetailFormatterTests.class));
+			addTest(new TestSuite(AlternateStratumTests.class));
+		}
+		addTest(new TestSuite(ConditionalBreakpointsTests.class));
 	}
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
index d0f785a..079d42d 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/TestUtil.java
@@ -13,6 +13,7 @@
 import java.lang.management.ManagementFactory;
 import java.lang.management.ThreadInfo;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -21,6 +22,9 @@
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.ILaunch;
+import org.eclipse.debug.core.ILaunchManager;
 import org.eclipse.jdt.debug.testplugin.JavaTestPlugin;
 import org.eclipse.swt.widgets.Display;
 import org.junit.Assert;
@@ -47,6 +51,14 @@
 
 		// Ensure that the Thread.interrupted() flag didn't leak.
 		Assert.assertFalse("The main thread should not be interrupted at the end of a test", Thread.interrupted());
+
+		ILaunchManager launchManager = DebugPlugin.getDefault().getLaunchManager();
+		List<ILaunch> launches = Arrays.asList(launchManager.getLaunches());
+		// in case some test left a launch, remove it before reporting a failure, so that further tests can work on a clean Debug View state
+		for (ILaunch launch : launches) {
+			launchManager.removeLaunch(launch);
+		}
+		Assert.assertEquals("expected no launches after test", Collections.EMPTY_LIST, launches);
 	}
 
 	public static void log(int severity, String owner, String message, Throwable... optionalError) {
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java
index e204929..f33290f 100755
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/ConditionalBreakpointsTests.java
@@ -13,11 +13,13 @@
 import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.debug.core.model.IStackFrame;
 import org.eclipse.debug.core.model.IVariable;
+import org.eclipse.debug.internal.ui.views.console.ProcessConsole;
 import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaPrimitiveValue;
 import org.eclipse.jdt.debug.core.IJavaStackFrame;
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
+import org.eclipse.jdt.debug.tests.TestUtil;
 
 /**
  * Tests conditional breakpoints.
@@ -193,9 +195,9 @@
 	 * @throws Exception
 	 */
 	public void testSuspendLongRunningCondition() throws Exception {
-		String typeName = "MethodLoop";
+		String typeName = "MethodCall";
 		IJavaLineBreakpoint first = createLineBreakpoint(19, typeName);
-		createConditionalLineBreakpoint(29, typeName, "for (int x = 0; x < 1000; x++) { System.out.println(x);} Thread.sleep(200); return true;", true);
+		createConditionalLineBreakpoint(27, typeName, "for (int x = 0; x < 1000; x++) { System.out.println(x);} Thread.sleep(1000); return true;", true);
 
 		IJavaThread thread= null;
 		try {
@@ -203,17 +205,22 @@
 			IStackFrame top = thread.getTopStackFrame();
 			assertNotNull("Missing top frame", top);
 			thread.resume();
-			Thread.sleep(100);
+			// wait for evaluation to start
+			long start = System.currentTimeMillis();
+			while ((System.currentTimeMillis() - start) <= DEFAULT_TIMEOUT && !thread.isPerformingEvaluation()) {
+				Thread.sleep(10);
+			}
+			assertTrue("Expected evaluation for second breakpoint", thread.isPerformingEvaluation());
+			/*
+			 * Check that we can suspend during the breakpoint condition evaluation. The suspend will interrupt the evaluation, meaning the
+			 * conditional breakpoint won't actually be hit. Suspending will however result in stopping the thread at the breakpoint location.
+			 */
 			thread.suspend();
+			TestUtil.waitForJobs(getName(), 100, DEFAULT_TIMEOUT, ProcessConsole.class);
 			assertTrue("Thread should be suspended", thread.isSuspended());
 			IJavaStackFrame frame = (IJavaStackFrame) thread.getTopStackFrame();
 			assertNotNull("Missing top frame", frame);
 			assertEquals("Wrong location", "calculateSum", frame.getName());
-			thread.resume();
-			Thread.sleep(300);
-			// TODO: see bug 519382 - [tests] testSuspendLongRunningCondition: thread sporadically stays suspended
-			// For whatever reason we sometimes see that thread is not resumed.
-			// assertFalse("Thread should be resumed", thread.isSuspended());
 		} finally {
 			terminateAndRemove(thread);
 			removeAllBreakpoints();
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TestToggleBreakpointsTarget.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TestToggleBreakpointsTarget.java
index 7da9341..40f2330 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TestToggleBreakpointsTarget.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TestToggleBreakpointsTarget.java
@@ -16,6 +16,7 @@
 import org.eclipse.jdt.debug.core.IJavaLineBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaMethodBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaWatchpoint;
+import org.eclipse.jdt.debug.tests.TestUtil;
 
 /**
  * Tests the Java debugger's 'toggle breakpoints target'.
@@ -44,6 +45,7 @@
 			IJavaLineBreakpoint breakpoint = (IJavaLineBreakpoint) added;
 			assertEquals("Wrong line number", 23, breakpoint.getLineNumber());
 			assertEquals("Wrong type name", "a.b.c.SomeClass", breakpoint.getTypeName());
+			TestUtil.waitForJobs(getName(), 100, DEFAULT_TIMEOUT);
 		} finally {
 			manager.removeBreakpointListener(listener);
 			removeAllBreakpoints();
@@ -68,6 +70,7 @@
 			IJavaWatchpoint breakpoint = (IJavaWatchpoint) added;
 			assertEquals("Wrong type name", "a.b.c.SomeClass", breakpoint.getTypeName());
 			assertEquals("Wrong field name", "someField", breakpoint.getFieldName());
+			TestUtil.waitForJobs(getName(), 100, DEFAULT_TIMEOUT);
 		} finally {
 			manager.removeBreakpointListener(listener);
 			removeAllBreakpoints();
@@ -95,6 +98,7 @@
 			// this will actually fail to suspend since 'SomeClass' is not qualified, but we can't resolve the type
 			// without a build path, etc. (not a regression)
 			assertEquals("Wrong signature", "(Ljava/lang/String;LSomeClass;)V", breakpoint.getMethodSignature());
+			TestUtil.waitForJobs(getName(), 100, DEFAULT_TIMEOUT);
 		} finally {
 			manager.removeBreakpointListener(listener);
 			removeAllBreakpoints();
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TypeNameBreakpointTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TypeNameBreakpointTests.java
index e19efdb..4a73ee8 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TypeNameBreakpointTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/breakpoints/TypeNameBreakpointTests.java
@@ -10,10 +10,14 @@
  *******************************************************************************/
 package org.eclipse.jdt.debug.tests.breakpoints;
 
+import java.util.Arrays;
+
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
+import org.eclipse.debug.core.ILaunchManager;
 import org.eclipse.jdt.debug.core.IJavaBreakpoint;
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.core.JDIDebugModel;
@@ -447,6 +451,7 @@
 		finally {
 			terminateAndRemove(thread);
 			removeAllBreakpoints();
+			removeLaunch();
 		}
 	}
 
@@ -465,6 +470,7 @@
 		finally {
 			terminateAndRemove(thread);
 			removeAllBreakpoints();
+			removeLaunch();
 		}
 	}
 
@@ -483,6 +489,14 @@
 		finally {
 			terminateAndRemove(thread);
 			removeAllBreakpoints();
+			removeLaunch();
 		}
 	}
+
+	private void removeLaunch() {
+		ILaunchManager launchManager = getLaunchManager();
+		ILaunch[] launches = launchManager.getLaunches();
+		assertEquals("expected exactly 1 launch but got: " + Arrays.toString(launches), 1, launches.length);
+		launchManager.removeLaunch(launches[0]);
+	}
 }
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/ConsoleInputTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/ConsoleInputTests.java
index 966c47e..f50b909 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/ConsoleInputTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/ConsoleInputTests.java
@@ -92,6 +92,7 @@
 		} finally {
 			ConsoleLineTracker.setDelegate(null);
 			launch.getProcesses()[0].terminate();
+			getLaunchManager().removeLaunch(launch);
 		}
 	}
 
@@ -133,6 +134,7 @@
 		} finally {
 			ConsoleLineTracker.setDelegate(null);
 			launch.getProcesses()[0].terminate();
+			getLaunchManager().removeLaunch(launch);
 		}
 	}
 
@@ -314,6 +316,7 @@
 		} finally {
 			ConsoleLineTracker.setDelegate(null);
 			launch.getProcesses()[0].terminate();
+			getLaunchManager().removeLaunch(launch);
 		}
 	}
 
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EventDispatcherTest.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EventDispatcherTest.java
index 18a5d45..8e32f58 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EventDispatcherTest.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/EventDispatcherTest.java
@@ -84,12 +84,14 @@
 				}
 			}
 		};
+		IJavaThread suspendedThread = null;
 		try {
 			DebugPlugin.getDefault().addDebugEventListener(debugListener);
 			createLineBreakpoint(24, "BulkThreadCreationTest");
-			launchToBreakpoint("BulkThreadCreationTest");
+			suspendedThread = launchToBreakpoint("BulkThreadCreationTest");
 		}
 		finally {
+			terminateAndRemove(suspendedThread);
 			removeAllBreakpoints();
 			DebugPlugin.getDefault().removeDebugEventListener(debugListener);
 		}
diff --git a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
index 142b919..93f0a66 100644
--- a/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug.ui; singleton:=true
-Bundle-Version: 3.9.100.qualifier
+Bundle-Version: 3.10.0.qualifier
 Bundle-Activator: org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
diff --git a/org.eclipse.jdt.debug.ui/plugin.properties b/org.eclipse.jdt.debug.ui/plugin.properties
index abe533a..82aa951 100644
--- a/org.eclipse.jdt.debug.ui/plugin.properties
+++ b/org.eclipse.jdt.debug.ui/plugin.properties
@@ -158,6 +158,9 @@
 showSystemThreads.label=Show &System Threads
 showSystemThreads.tooltip=Show System Threads
 
+showRunningThreads.label=Show &Running Threads
+showRunningThreads.tooltip=Show Running Threads
+
 showMonitorThreadInfo.label=Show &Monitors
 showMonitorThreadInfo.tooltip=Show the Thread & Monitor Information
 
diff --git a/org.eclipse.jdt.debug.ui/plugin.xml b/org.eclipse.jdt.debug.ui/plugin.xml
index 9cdacd2..6dc3cdb 100644
--- a/org.eclipse.jdt.debug.ui/plugin.xml
+++ b/org.eclipse.jdt.debug.ui/plugin.xml
@@ -2076,6 +2076,16 @@
                menubarPath="org.eclipse.jdt.debug.ui.LaunchView.javaSubmenu/javaPart"
                tooltip="%showSystemThreads.tooltip">
          </action>
+         <action
+               class="org.eclipse.jdt.internal.debug.ui.actions.ShowRunningThreadsAction"
+               helpContextId="show_running_threads_action_context"
+               icon="$nl$/icons/full/obj16/thread_obj.png"
+               id="org.eclipse.jdt.debug.ui.launchViewActions.ShowRunningThreads"
+               label="%showRunningThreads.label"
+               menubarPath="org.eclipse.jdt.debug.ui.LaunchView.javaSubmenu/javaPart"
+               style="toggle"
+               tooltip="%showRunningThreads.tooltip">
+         </action>
   <action
         helpContextId="show_monitors_action_context"
         label="%showMonitorThreadInfo.label"
diff --git a/org.eclipse.jdt.debug.ui/pom.xml b/org.eclipse.jdt.debug.ui/pom.xml
index f04dd11..6a176c9 100644
--- a/org.eclipse.jdt.debug.ui/pom.xml
+++ b/org.eclipse.jdt.debug.ui/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug.ui</artifactId>
-  <version>3.9.100-SNAPSHOT</version>
+  <version>3.10.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
   <properties>
     <code.ignoredWarnings>-warn:+resource,-deprecation,unavoidableGenericProblems</code.ignoredWarnings>
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/IJavaDebugUIConstants.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/IJavaDebugUIConstants.java
index 56bb695..1dc8069 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/IJavaDebugUIConstants.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/debug/ui/IJavaDebugUIConstants.java
@@ -87,6 +87,13 @@
 	public static final String PREF_SHOW_SYSTEM_THREADS = PLUGIN_ID + ".show_system_threads"; //$NON-NLS-1$
 
 	/**
+	 * Boolean preference indicating whether running threads should appear visible in the debug view.
+	 *
+	 * @since 3.10
+	 */
+	public static final String PREF_SHOW_RUNNING_THREADS = PLUGIN_ID + ".show_running_threads"; //$NON-NLS-1$
+
+	/**
 	 * Boolean preference indicating whether thread groups should be displayed in the debug view.
 	 *
 	 * @since 3.2
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
index d2632d3..0842f16 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 IBM Corporation 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
@@ -63,6 +63,7 @@
 	public static String JavaDebugPreferencePage_Value_must_be_a_valid_integer_greater_than__0__ms_1;
 	public static String JavaDebugPreferencePage_Replace_classfiles_containing_compilation_errors_1;
 	public static String JavaDebugPreferencePage_ShowStepResult_1;
+	public static String JavaDebugPreferencePage_ShowStepTimeout_ms_1;
 	public static String JavaDebugPreferencePage_Communication_1;
 	public static String JavaDebugPreferencePage_Debugger__timeout__2;
 	public static String JavaDebugPreferencePage__Launch_timeout__ms___1;
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
index 7e8604e..202af01 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/DebugUIMessages.properties
@@ -31,6 +31,7 @@
 JavaDebugPreferencePage_Value_must_be_a_valid_integer_greater_than__0__ms_1=Value must be a valid integer greater than or equal to {0} ms
 JavaDebugPreferencePage_Replace_classfiles_containing_compilation_errors_1=Replace &classfiles containing compilation errors
 JavaDebugPreferencePage_ShowStepResult_1=S&how method result after a step operation (if supported by the VM; may be slow)
+JavaDebugPreferencePage_ShowStepTimeout_ms_1=Don't show &if step operation takes longer than (ms):
 JavaDebugPreferencePage_Communication_1=Communication
 JavaDebugPreferencePage_Debugger__timeout__2=Debugger &timeout (ms):
 JavaDebugPreferencePage__Launch_timeout__ms___1=&Launch timeout (ms):
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java
index 859781c..49f77d1 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JDIDebugUIPreferenceInitializer.java
@@ -54,6 +54,7 @@
 		store.setDefault(IJDIPreferencesConstants.PREF_SHOW_DETAILS, IJDIPreferencesConstants.DETAIL_PANE);
 
 		store.setDefault(IJavaDebugUIConstants.PREF_SHOW_SYSTEM_THREADS, false);
+		store.setDefault(IJavaDebugUIConstants.PREF_SHOW_RUNNING_THREADS, true);
 		store.setDefault(IJavaDebugUIConstants.PREF_SHOW_MONITOR_THREAD_INFO, true);
 		store.setDefault(IJavaDebugUIConstants.PREF_SHOW_THREAD_GROUPS, false);
 		store.setDefault(IJDIPreferencesConstants.PREF_OPEN_INSPECT_POPUP_ON_EXCEPTION, false);
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
index d62f968..62f880c 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/JavaDebugPreferencePage.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 IBM Corporation 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
@@ -98,6 +98,7 @@
 	// Timeout preference widgets
 	private JavaDebugIntegerFieldEditor fTimeoutText;
 	private JavaDebugIntegerFieldEditor fConnectionTimeoutText;
+	private JavaDebugIntegerFieldEditor fShowStepTimeoutText;
 
 	public JavaDebugPreferencePage() {
 		super();
@@ -175,6 +176,15 @@
 		SWTFactory.createVerticalSpacer(composite, 1);
 		fShowStepResult = SWTFactory.createCheckButton(composite, DebugUIMessages.JavaDebugPreferencePage_ShowStepResult_1, null, false, 1);
 
+		Composite space1 = SWTFactory.createComposite(composite, composite.getFont(), 1, 1, GridData.FILL_HORIZONTAL);
+		fShowStepTimeoutText = new JavaDebugIntegerFieldEditor(JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, DebugUIMessages.JavaDebugPreferencePage_ShowStepTimeout_ms_1, space1);
+		fShowStepTimeoutText.setPage(this);
+		fShowStepTimeoutText.setValidateStrategy(StringFieldEditor.VALIDATE_ON_KEY_STROKE);
+		fShowStepTimeoutText.setValidRange(-1, Integer.MAX_VALUE);
+		fShowStepTimeoutText.setErrorMessage(NLS.bind(DebugUIMessages.JavaDebugPreferencePage_Value_must_be_a_valid_integer_greater_than__0__ms_1, new Object[] {
+				new Integer(-1) }));
+		fShowStepTimeoutText.load();
+
 		SWTFactory.createVerticalSpacer(composite, 1);
 		fAdvancedSourcelookup = SWTFactory.createCheckButton(composite, DebugUIMessages.JavaDebugPreferencePage_advancedSourcelookup, null, false, 1);
 
@@ -182,6 +192,7 @@
 
 		fTimeoutText.setPropertyChangeListener(this);
 		fConnectionTimeoutText.setPropertyChangeListener(this);
+		fShowStepTimeoutText.setPropertyChangeListener(this);
 		return composite;
 	}
 
@@ -212,6 +223,7 @@
 			prefs.putInt(JDIDebugPlugin.PREF_DEFAULT_WATCHPOINT_SUSPEND_POLICY, fWatchpoint.getSelectionIndex());
 			prefs.putBoolean(JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS, fPerformHCRWithCompilationErrors.getSelection());
 			prefs.putBoolean(JDIDebugModel.PREF_SHOW_STEP_RESULT, fShowStepResult.getSelection());
+			prefs.putInt(JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, fShowStepTimeoutText.getIntValue());
 			prefs.putInt(JDIDebugModel.PREF_REQUEST_TIMEOUT, fTimeoutText.getIntValue());
 			prefs.putBoolean(JDIDebugModel.PREF_FILTER_BREAKPOINTS_FROM_UNRELATED_SOURCES, fFilterUnrelatedBreakpoints.getSelection());
 			prefs.putBoolean(JDIDebugPlugin.PREF_ENABLE_ADVANCED_SOURCELOOKUP, fAdvancedSourcelookup.getSelection());
@@ -256,6 +268,7 @@
 			fWatchpoint.select(prefs.getInt(JDIDebugPlugin.PREF_DEFAULT_WATCHPOINT_SUSPEND_POLICY, 0));
 			fPerformHCRWithCompilationErrors.setSelection(prefs.getBoolean(JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS, true));
 			fShowStepResult.setSelection(prefs.getBoolean(JDIDebugModel.PREF_SHOW_STEP_RESULT, true));
+			fShowStepTimeoutText.setStringValue(new Integer(prefs.getInt(JDIDebugModel.PREF_SHOW_STEP_RESULT, JDIDebugModel.DEF_SHOW_STEP_TIMEOUT)).toString());
 			fTimeoutText.setStringValue(new Integer(prefs.getInt(JDIDebugModel.PREF_REQUEST_TIMEOUT, JDIDebugModel.DEF_REQUEST_TIMEOUT)).toString());
 			fFilterUnrelatedBreakpoints.setSelection(prefs.getBoolean(JDIDebugModel.PREF_FILTER_BREAKPOINTS_FROM_UNRELATED_SOURCES, true));
 			fAdvancedSourcelookup.setSelection(prefs.getBoolean(JDIDebugPlugin.PREF_ENABLE_ADVANCED_SOURCELOOKUP, true));
@@ -293,6 +306,7 @@
 		fWatchpoint.select(prefs.getInt(bundleId, JDIDebugPlugin.PREF_DEFAULT_WATCHPOINT_SUSPEND_POLICY, 0, null));
 		fPerformHCRWithCompilationErrors.setSelection(prefs.getBoolean(bundleId, JDIDebugModel.PREF_HCR_WITH_COMPILATION_ERRORS, true, null));
 		fShowStepResult.setSelection(prefs.getBoolean(bundleId, JDIDebugModel.PREF_SHOW_STEP_RESULT, true, null));
+		fShowStepTimeoutText.setStringValue(new Integer(prefs.getInt(bundleId, JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, JDIDebugModel.DEF_SHOW_STEP_TIMEOUT, null)).toString());
 		fTimeoutText.setStringValue(new Integer(prefs.getInt(bundleId, JDIDebugModel.PREF_REQUEST_TIMEOUT, JDIDebugModel.DEF_REQUEST_TIMEOUT, null)).toString());
 		fFilterUnrelatedBreakpoints.setSelection(prefs.getBoolean(bundleId, JDIDebugModel.PREF_FILTER_BREAKPOINTS_FROM_UNRELATED_SOURCES, true, null));
 		fAdvancedSourcelookup.setSelection(prefs.getBoolean(bundleId, JDIDebugPlugin.PREF_ENABLE_ADVANCED_SOURCELOOKUP, true, null));
@@ -315,8 +329,11 @@
 				if (fConnectionTimeoutText != null && event.getSource() != fConnectionTimeoutText) {
 					fConnectionTimeoutText.refreshValidState();
 				}
+				if (fShowStepTimeoutText != null && event.getSource() != fShowStepTimeoutText) {
+					fShowStepTimeoutText.refreshValidState();
+				}
 			}
-			setValid(fTimeoutText.isValid() && fConnectionTimeoutText.isValid());
+			setValid(fTimeoutText.isValid() && fConnectionTimeoutText.isValid() && fShowStepTimeoutText.isValid());
 			getContainer().updateButtons();
 			updateApplyButton();
 		}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/AbstractThreadsViewFilterAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/AbstractThreadsViewFilterAction.java
new file mode 100644
index 0000000..d57deb8
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/AbstractThreadsViewFilterAction.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2015 IBM Corporation 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:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.ui.actions;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.debug.core.DebugEvent;
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.debug.core.DebugPlugin;
+import org.eclipse.debug.core.IDebugEventSetListener;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
+import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * An action delegate that toggles the state of its viewer to show/hide certain java threads.
+ */
+abstract class AbstractThreadsViewFilterAction extends ViewFilterAction implements IDebugEventSetListener {
+
+	@Override
+	public boolean select(Viewer viewer, Object parentElement, Object element) {
+		if (!getPreferenceValue()) {
+
+			IJavaThread thread = getJavaThread(element);
+
+			if (thread != null) {
+				try {
+					return selectThread(thread);
+				}
+				catch (DebugException e) {
+				}
+			}
+		}
+		return true;
+	}
+
+	private void refresh(Object source) {
+		final IJavaThread thread = getJavaThread(source);
+		if (thread != null) {
+			try {
+				if (isCandidateThread(thread)) {
+					Runnable r = new Runnable() {
+						@Override
+						public void run() {
+							StructuredViewer viewer = getStructuredViewer();
+							if (viewer != null) {
+								viewer.refresh();
+							}
+						}
+					};
+					JDIDebugUIPlugin.getStandardDisplay().asyncExec(r);
+					return;
+				}
+			}
+			catch (DebugException e) {
+			}
+		}
+	}
+
+	protected abstract boolean isCandidateThread(final IJavaThread thread) throws DebugException;
+
+	protected abstract boolean selectThread(IJavaThread thread) throws DebugException;
+
+	private IJavaThread getJavaThread(Object element) {
+		IJavaThread thread = null;
+
+		if (element instanceof IJavaThread) {
+			thread = (IJavaThread) element;
+		} else if (element instanceof IAdaptable) {
+			thread = ((IAdaptable) element).getAdapter(IJavaThread.class);
+		}
+
+		return thread;
+	}
+
+	@Override
+	public void init(IViewPart view) {
+		super.init(view);
+		DebugPlugin.getDefault().addDebugEventListener(this);
+	}
+
+	@Override
+	public void dispose() {
+		DebugPlugin.getDefault().removeDebugEventListener(this);
+		super.dispose();
+	}
+
+	@Override
+	public void handleDebugEvents(DebugEvent[] events) {
+		if (getValue()) {
+			// if showing all threads, no need to worry about displaying/hiding
+			return;
+		}
+		for (int i = 0; i < events.length; i++) {
+			DebugEvent event = events[i];
+			switch (event.getKind()) {
+				case DebugEvent.RESUME:
+					if (event.getDetail() == DebugEvent.CLIENT_REQUEST) {
+						// when a thread resumes we need to refresh the viewer to re-filter it
+						refresh(event.getSource());
+					}
+					break;
+			}
+		}
+	}
+}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ShowRunningThreadsAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ShowRunningThreadsAction.java
new file mode 100644
index 0000000..3937449
--- /dev/null
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ShowRunningThreadsAction.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 2017 Igor Fedorenko.
+ * 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:
+ *     Igor Fedorenko - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.debug.ui.actions;
+
+import org.eclipse.debug.core.DebugException;
+import org.eclipse.jdt.debug.core.IJavaThread;
+import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ui.IViewPart;
+
+/**
+ * An action delegate that toggles the state of its viewer to show/hide running threads.
+ */
+public class ShowRunningThreadsAction extends AbstractThreadsViewFilterAction {
+
+	@Override
+	public void init(IViewPart view) {
+		// compensate for a bug in how ViewFilterAction stores compositeKey value
+		// which does not allow default==true and explicit==false
+		IPreferenceStore store = getPreferenceStore();
+		String preferenceKey = getPreferenceKey();
+		if (store.contains(preferenceKey)) {
+			String compositeKey = view.getSite().getId() + "." + preferenceKey; //$NON-NLS-1$
+			store.setDefault(compositeKey, store.getBoolean(preferenceKey));
+		}
+
+		super.init(view);
+	}
+
+	@Override
+	protected String getPreferenceKey() {
+		return IJavaDebugUIConstants.PREF_SHOW_RUNNING_THREADS;
+	}
+
+	@Override
+	protected boolean selectThread(IJavaThread thread) throws DebugException {
+		return thread.isSuspended();
+	}
+
+	@Override
+	protected boolean isCandidateThread(IJavaThread thread) throws DebugException {
+		return true;
+	}
+}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ShowSystemThreadsAction.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ShowSystemThreadsAction.java
index 7abe841..2cfea81 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ShowSystemThreadsAction.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/actions/ShowSystemThreadsAction.java
@@ -10,122 +10,29 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.debug.ui.actions;
 
-import org.eclipse.core.runtime.IAdaptable;
-import org.eclipse.debug.core.DebugEvent;
 import org.eclipse.debug.core.DebugException;
-import org.eclipse.debug.core.DebugPlugin;
-import org.eclipse.debug.core.IDebugEventSetListener;
 import org.eclipse.jdt.debug.core.IJavaThread;
 import org.eclipse.jdt.debug.ui.IJavaDebugUIConstants;
-import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
-import org.eclipse.jface.viewers.StructuredViewer;
-import org.eclipse.jface.viewers.Viewer;
-import org.eclipse.ui.IViewPart;
 
 /**
  * An action delegate that toggles the state of its viewer to
  * show/hide System Threads.
  */
-public class ShowSystemThreadsAction extends ViewFilterAction implements IDebugEventSetListener {
+public class ShowSystemThreadsAction extends AbstractThreadsViewFilterAction {
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jdt.internal.debug.ui.actions.ThreadFilterAction#getPreferenceKey()
-	 */
 	@Override
 	protected String getPreferenceKey() {
 		return IJavaDebugUIConstants.PREF_SHOW_SYSTEM_THREADS;
 	}
 
-	/* (non-Javadoc)
-	 * @see org.eclipse.jface.viewers.ViewerFilter#select(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
-	 */
 	@Override
-	public boolean select(Viewer viewer, Object parentElement, Object element) {
-	    if (!getValue()) {
-
-            IJavaThread thread = getJavaThread(element);
-
-	        if (thread != null) {
-	            try {
-	                // Show only non-system threads and suspended threads.
-	                return !thread.isSystemThread() || thread.isSuspended();
-	            } catch (DebugException e) {
-	            }
-	        }
-	    }
-	    return true;
+	protected boolean selectThread(IJavaThread thread) throws DebugException {
+		// Show only non-system threads and suspended threads.
+		return !thread.isSystemThread() || thread.isSuspended();
 	}
 
-	private IJavaThread getJavaThread(Object element) {
-	    IJavaThread thread = null;
-
-	    if (element instanceof IJavaThread) {
-			thread = (IJavaThread) element;
-		} else if (element instanceof IAdaptable) {
-			thread = ((IAdaptable)element).getAdapter(IJavaThread.class);
-		}
-
-	    return thread;
-	}
-
-    /* (non-Javadoc)
-	 * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
-	 */
 	@Override
-	public void init(IViewPart view) {
-		super.init(view);
-		DebugPlugin.getDefault().addDebugEventListener(this);
-	}
-	/* (non-Javadoc)
-	 * @see org.eclipse.ui.IActionDelegate2#dispose()
-	 */
-	@Override
-	public void dispose() {
-		super.dispose();
-		DebugPlugin.getDefault().removeDebugEventListener(this);
-	}
-
-	/* (non-Javadoc)
-	 * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[])
-	 */
-	@Override
-	public void handleDebugEvents(DebugEvent[] events) {
-		if (getValue()) {
-			// if showing system threads, no need to worry about displaying/hiding
-			return;
-		}
-		for (int i = 0; i < events.length; i++) {
-			DebugEvent event = events[i];
-			switch (event.getKind()) {
-				case DebugEvent.RESUME:
-					if (event.getDetail() == DebugEvent.CLIENT_REQUEST) {
-						// when a system thread resumes we need to refresh the viewer to re-filter it
-						refresh(event.getSource());
-					}
-					break;
-			}
-		}
-	}
-
-	private void refresh(Object source) {
-        final IJavaThread thread = getJavaThread(source);
-        if (thread != null) {
-			try {
-				if (thread.isSystemThread()) {
-					Runnable r = new Runnable() {
-						@Override
-						public void run() {
-							StructuredViewer viewer = getStructuredViewer();
-							if (viewer != null) {
-								viewer.refresh();
-							}
-						}
-					};
-					JDIDebugUIPlugin.getStandardDisplay().asyncExec(r);
-					return;
-				}
-			} catch (DebugException e) {
-			}
-		}
+	protected boolean isCandidateThread(IJavaThread thread) throws DebugException {
+		return thread.isSystemThread();
 	}
 }
diff --git a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
index dd9809c..1d3aada 100644
--- a/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.debug/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.debug; singleton:=true
-Bundle-Version: 3.11.200.qualifier
+Bundle-Version: 3.12.0.qualifier
 Bundle-ClassPath: jdi.jar,
  jdimodel.jar,
  tools.jar
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java
index d1e64bf..96c9367 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/debug/core/JDIDebugModel.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2016 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 IBM Corporation 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
@@ -110,6 +110,21 @@
 			+ ".PREF_SHOW_STEP_RESULT"; //$NON-NLS-1$
 
 	/**
+	 * Preference key for specifying if the timeout (in ms) after which the return method result of a step operation is not observed any longer (0
+	 * means no timeout, a negative value means: simulate a timeout condition).
+	 *
+	 * @since 3.12
+	 */
+	public static final String PREF_SHOW_STEP_TIMEOUT = getPluginIdentifier() + ".PREF_SHOW_STEP_TIMEOUT"; //$NON-NLS-1$
+
+	/**
+	 * The default value for {@link #PREF_SHOW_STEP_TIMEOUT} timeout when no preference is set.
+	 *
+	 * @since 3.12
+	 */
+	public static final int DEF_SHOW_STEP_TIMEOUT = 7000;
+
+	/**
 	 * Not to be instantiated.
 	 */
 	private JDIDebugModel() {
@@ -336,8 +351,9 @@
 			String typeName, int lineNumber, int charStart, int charEnd,
 			int hitCount, boolean register, Map<String, Object> attributes)
 			throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaLineBreakpoint(resource, typeName, lineNumber,
 				charStart, charEnd, hitCount, register, attributes);
 	}
@@ -397,8 +413,9 @@
 			IResource resource, String sourceName, String pattern,
 			int lineNumber, int charStart, int charEnd, int hitCount,
 			boolean register, Map<String, Object> attributes) throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaPatternBreakpoint(resource, sourceName, pattern,
 				lineNumber, charStart, charEnd, hitCount, register, attributes);
 	}
@@ -481,8 +498,9 @@
 			String sourcePath, String classNamePattern, int lineNumber,
 			int charStart, int charEnd, int hitCount, boolean register,
 			Map<String, Object> attributes) throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaStratumLineBreakpoint(resource, stratum, sourceName,
 				sourcePath, classNamePattern, lineNumber, charStart, charEnd,
 				hitCount, register, attributes);
@@ -537,8 +555,9 @@
 			IResource resource, String sourceName, int lineNumber,
 			int charStart, int charEnd, int hitCount, boolean register,
 			Map<String, Object> attributes) throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaTargetPatternBreakpoint(resource, sourceName,
 				lineNumber, charStart, charEnd, hitCount, register, attributes);
 	}
@@ -584,8 +603,9 @@
 			IResource resource, String exceptionName, boolean caught,
 			boolean uncaught, boolean checked, boolean register, Map<String, Object> attributes)
 			throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaExceptionBreakpoint(resource, exceptionName, caught,
 				uncaught, checked, register, attributes);
 	}
@@ -646,8 +666,9 @@
 			String typeName, String fieldName, int lineNumber, int charStart,
 			int charEnd, int hitCount, boolean register, Map<String, Object> attributes)
 			throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaWatchpoint(resource, typeName, fieldName, lineNumber,
 				charStart, charEnd, hitCount, register, attributes);
 	}
@@ -716,8 +737,9 @@
 			boolean nativeOnly, int lineNumber, int charStart, int charEnd,
 			int hitCount, boolean register, Map<String, Object> attributes)
 			throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaMethodBreakpoint(resource, typePattern, methodName,
 				methodSignature, entry, exit, nativeOnly, lineNumber,
 				charStart, charEnd, hitCount, register, attributes);
@@ -775,8 +797,9 @@
 			String methodSignature, int lineNumber, int charStart, int charEnd,
 			int hitCount, boolean register, Map<String, Object> attributes)
 			throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaMethodEntryBreakpoint(resource, typeName, methodName,
 				methodSignature, lineNumber, charStart, charEnd, hitCount,
 				register, attributes);
@@ -807,16 +830,19 @@
 				.getBreakpointManager();
 		IBreakpoint[] breakpoints = manager.getBreakpoints(modelId);
 		for (int i = 0; i < breakpoints.length; i++) {
-			if (!(breakpoints[i] instanceof IJavaLineBreakpoint))
+			if (!(breakpoints[i] instanceof IJavaLineBreakpoint)) {
 				continue;
+			}
 			IJavaLineBreakpoint breakpoint = (IJavaLineBreakpoint) breakpoints[i];
 			IMarker marker = breakpoint.getMarker();
 			if (marker != null && marker.exists()
 					&& marker.getType().equals(markerType)) {
 				String breakpointTypeName = breakpoint.getTypeName();
-				if (JavaDebugUtils.typeNamesEqual(breakpointTypeName, typeName) || (breakpointTypeName != null && breakpointTypeName.startsWith(typeName + '$')))
-					if (breakpoint.getLineNumber() == lineNumber)
+				if (JavaDebugUtils.typeNamesEqual(breakpointTypeName, typeName) || (breakpointTypeName != null && breakpointTypeName.startsWith(typeName + '$'))) {
+					if (breakpoint.getLineNumber() == lineNumber) {
 						return breakpoint;
+					}
+				}
 			}
 		}
 		return null;
@@ -850,8 +876,9 @@
 				.getBreakpointManager();
 		IBreakpoint[] breakpoints = manager.getBreakpoints(modelId);
 		for (int i = 0; i < breakpoints.length; i++) {
-			if (!(breakpoints[i] instanceof IJavaLineBreakpoint))
+			if (!(breakpoints[i] instanceof IJavaLineBreakpoint)) {
 				continue;
+			}
 			IJavaLineBreakpoint breakpoint = (IJavaLineBreakpoint) breakpoints[i];
 			IMarker marker = breakpoint.getMarker();
 			if (marker != null && marker.exists()
@@ -859,8 +886,9 @@
 				String breakpointTypeName = breakpoint.getTypeName();
 				if ((JavaDebugUtils.typeNamesEqual(breakpointTypeName, typeName) || (breakpointTypeName != null && breakpointTypeName.startsWith(typeName + '$')))
 						&& breakpoint.getLineNumber() == lineNumber
-						&& resource.equals(marker.getResource()))
+						&& resource.equals(marker.getResource())) {
 					return breakpoint;
+				}
 			}
 		}
 		return null;
@@ -888,8 +916,9 @@
 	@Deprecated
 	public static Preferences getPreferences() {
 		JDIDebugPlugin deflt = JDIDebugPlugin.getDefault();
-		if (deflt != null)
+		if (deflt != null) {
 			return deflt.getPluginPreferences();
+		}
 		return null;
 	}
 
@@ -916,12 +945,13 @@
 	@Deprecated
 	public static void savePreferences() {
 		IEclipsePreferences node = InstanceScope.INSTANCE.getNode(JDIDebugPlugin.getUniqueIdentifier());
-		if(node != null)
+		if(node != null) {
 			try {
 				node.flush();
 			} catch (BackingStoreException bse) {
 				JDIDebugPlugin.log(bse);
 			}
+		}
 	}
 
 	/**
@@ -964,8 +994,9 @@
 	public static IJavaClassPrepareBreakpoint createClassPrepareBreakpoint(
 			IResource resource, String typeName, int memberType, int charStart,
 			int charEnd, boolean register, Map<String, Object> attributes) throws CoreException {
-		if (attributes == null)
+		if (attributes == null) {
 			attributes = new HashMap<>(10);
+		}
 		return new JavaClassPrepareBreakpoint(resource, typeName, memberType,
 				charStart, charEnd, register, attributes);
 	}
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java
index df13b94..7caaa6d 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/JDIDebugPluginPreferenceInitializer.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2016 IBM Corporation and others.
+ * Copyright (c) 2004, 2018 IBM Corporation 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
@@ -44,6 +44,7 @@
 		node.putInt(JDIDebugPlugin.PREF_ALL_INSTANCES_MAX_COUNT, 100);
 		node.putBoolean(JDIDebugModel.PREF_FILTER_BREAKPOINTS_FROM_UNRELATED_SOURCES, true);
 		node.putBoolean(JDIDebugModel.PREF_SHOW_STEP_RESULT, true);
+		node.putInt(JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, JDIDebugModel.DEF_SHOW_STEP_TIMEOUT);
 		node.putBoolean(JDIDebugPlugin.PREF_ENABLE_ADVANCED_SOURCELOOKUP, true);
 	}
 }
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java
index 7f1c9c7..f49d0c0 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2017 IBM Corporation and others.
+ * Copyright (c) 2000, 2018 IBM Corporation 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
@@ -128,6 +128,7 @@
 	public static String JDIStackFrame_ExceptionThrown;
 	public static String JDIStackFrame_ThrowingException;
 	public static String JDIStackFrame_NoMethodReturnValue;
+	public static String JDIStackFrame_NotObservedBecauseOfTimeout;
 
 	public static String JDIThisVariable_exception_while_retrieving_type_this;
 	public static String JDIThisVariableexception_retrieving_reference_type_name;
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties
index fcf0b5d..43bcd6e 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIDebugModelMessages.properties
@@ -1,5 +1,5 @@
 ###############################################################################
-# Copyright (c) 2000, 2017 IBM Corporation and others.
+# Copyright (c) 2000, 2018 IBM Corporation 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
@@ -96,6 +96,7 @@
 JDIStackFrame_ExceptionThrown={0}() threw
 JDIStackFrame_ThrowingException={0}() is throwing
 JDIStackFrame_NoMethodReturnValue=no method return value
+JDIStackFrame_NotObservedBecauseOfTimeout=(Not observed to speed up the long running step operation)
 
 JDIThisVariable_exception_while_retrieving_type_this={0} occurred while retrieving type ''this''.
 JDIThisVariableexception_retrieving_reference_type_name={0} occurred retrieving reference type name.
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
index 5b554f4..8477498 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIStackFrame.java
@@ -411,6 +411,9 @@
 				} else if (methodResult.fResultType == ResultType.throwing) {
 					String name = MessageFormat.format(JDIDebugModelMessages.JDIStackFrame_ThrowingException, methodResult.fMethod.name());
 					variables.add(0, new JDIReturnValueVariable(name, JDIValue.createValue(getJavaDebugTarget(), methodResult.fValue), true));
+				} else if (methodResult.fResultType == ResultType.step_timeout) {
+					String msg = JDIDebugModelMessages.JDIStackFrame_NotObservedBecauseOfTimeout;
+					variables.add(0, new JDIReturnValueVariable(JDIDebugModelMessages.JDIStackFrame_NoMethodReturnValue, new JDIPlaceholderValue(getJavaDebugTarget(), msg), false));
 				}
 			} else if(JDIThread.showStepResultIsEnabled()) {
 				variables.add(0, new JDIReturnValueVariable(JDIDebugModelMessages.JDIStackFrame_NoMethodReturnValue, new JDIPlaceholderValue(getJavaDebugTarget(), ""), false)); //$NON-NLS-1$
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
index 4f08b2d..00fc3b0 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/JDIThread.java
@@ -18,6 +18,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Vector;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IAdaptable;
@@ -260,6 +261,8 @@
 	 */
 	private MethodExitRequest fCurrentMethodExitRequest;
 
+	private Thread fCurrentMethodExitRequestDisabler;
+
 	/**
 	 * The current ExceptionRequest if a step-return or step-over is in progress.
 	 */
@@ -293,6 +296,8 @@
 
 	private MethodResult fStepResultCandidate;
 
+	private AtomicBoolean fStepResultTimeoutTriggered = new AtomicBoolean();
+
 	/**
 	 * Result of the last step step-over or step-return operation or method exit breakpoint of exception break point
 	 */
@@ -2033,7 +2038,7 @@
 								IStatus.ERROR,
 								JDIDebugPlugin.getUniqueIdentifier(),
 								SUSPEND_TIMEOUT,
-								MessageFormat.format(JDIDebugModelMessages.JDIThread_suspend_timeout, new Integer(timeout).toString()),
+								MessageFormat.format(JDIDebugModelMessages.JDIThread_suspend_timeout, Integer.valueOf(timeout).toString()),
 								null);
 						IStatusHandler handler = DebugPlugin.getDefault()
 								.getStatusHandler(status);
@@ -2542,6 +2547,11 @@
 						removeJDIEventListener(this, fCurrentMethodExitRequest);
 						manager.deleteEventRequest(fCurrentMethodExitRequest);
 						fCurrentMethodExitRequest = null;
+						Thread t = fCurrentMethodExitRequestDisabler;
+						if (t != null) {
+							t.interrupt();
+							fCurrentMethodExitRequestDisabler = null;
+						}
 					}
 					if (fCurrentExceptionRequest != null) {
 						removeJDIEventListener(this, fCurrentExceptionRequest);
@@ -2554,6 +2564,7 @@
 						fCurrentMethodEntryRequest = null;
 					}
 					fStepResultCandidate = null;
+					fStepResultTimeoutTriggered.set(false);
 					List<IJavaStackFrame> frames = computeStackFrames();
 					int frameCount = 0;
 					StackFrame currentFrame = null;
@@ -2593,7 +2604,9 @@
 						methodExitRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
 						methodExitRequest.enable();
 						fCurrentMethodExitRequest = methodExitRequest;
-						fStepResultMethod = currentFrame.location().method();
+						Method method = currentFrame.location().method();
+
+						fStepResultMethod = method;
 						fStepReturnTargetFrameCount = frameCount - 1; // depth of the frame that is returned to
 						addJDIEventListener(this, methodExitRequest);
 
@@ -2614,6 +2627,39 @@
 							fStepOverFrameCount = frameCount; // depth of the frame where the step-over is being done
 							addJDIEventListener(this, methodEntryRequest);
 						}
+
+						int timeout = getStepResultTimeout();
+						if (timeout != 0) {
+							Runnable r = () -> {
+								try {
+									if (timeout > 0) {
+										Thread.sleep(timeout);
+									}
+								} catch (InterruptedException e) {
+									return;
+								}
+								fStepResultTimeoutTriggered.set(true);
+								if (fCurrentMethodExitRequest == methodExitRequest) {
+									try {
+										methodExitRequest.disable();
+										if (fCurrentExceptionRequest == exceptionRequest) {
+											exceptionRequest.disable();
+										}
+									} catch (Exception e) {
+										// ignore
+									}
+								}
+							};
+							if (timeout > 0) {
+								Thread t = new Thread(r, "JDIThread: MethodExitDisabler"); //$NON-NLS-1$
+								t.setDaemon(true);
+								t.start();
+								fCurrentMethodExitRequestDisabler = t;
+							} else {
+								// negative timeout: simulate immediate timeout (for testing)
+								r.run();
+							}
+						}
 					}
 				}
 				return request;
@@ -2683,6 +2729,11 @@
 						manager.deleteEventRequest(fCurrentMethodExitRequest);
 					}
 					fCurrentMethodExitRequest = null;
+					Thread t = fCurrentMethodExitRequestDisabler;
+					if (t != null) {
+						t.interrupt();
+						fCurrentMethodExitRequestDisabler = null;
+					}
 				}
 				if (fCurrentExceptionRequest != null) {
 					removeJDIEventListener(this, fCurrentExceptionRequest);
@@ -2804,11 +2855,21 @@
 				StepEvent stepEvent = (StepEvent) event;
 				Location currentLocation = stepEvent.location();
 
-				if (fStepResultCandidate != null) {
+				if (fStepResultTimeoutTriggered.get()) {
+					Method m = fStepResultMethod;
+					if (m != null) {
+						setMethodResult(new MethodResult(m, -1, null, ResultType.step_timeout));
+					}
+					fStepResultMethod = null;
+					fStepReturnTargetFrameCount = -1;
+					fStepResultCandidate = null;
+					fStepResultTimeoutTriggered.set(false);
+				} else if (fStepResultCandidate != null) {
 					setMethodResult(fStepResultCandidate);
 					fStepResultMethod = null;
 					fStepReturnTargetFrameCount = -1;
 					fStepResultCandidate = null;
+					fStepResultTimeoutTriggered.set(false);
 				}
 
 				if (getStepKind() == StepRequest.STEP_OVER) {
@@ -3744,6 +3805,10 @@
 		return Platform.getPreferencesService().getBoolean(JDIDebugPlugin.getUniqueIdentifier(), JDIDebugModel.PREF_SHOW_STEP_RESULT, true, null);
 	}
 
+	public static int getStepResultTimeout() {
+		return Platform.getPreferencesService().getInt(JDIDebugPlugin.getUniqueIdentifier(), JDIDebugModel.PREF_SHOW_STEP_TIMEOUT, JDIDebugModel.DEF_SHOW_STEP_TIMEOUT, null);
+	}
+
 	protected boolean isSupported(Location currentLocation) {
 		if (currentLocation == null) {
 			return false;
diff --git a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java
index 0312188..11ca266 100644
--- a/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java
+++ b/org.eclipse.jdt.debug/model/org/eclipse/jdt/internal/debug/core/model/MethodResult.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2016, 2017 Till Brychcy and others.
+ * Copyright (c) 2016, 2018 Till Brychcy 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
@@ -26,7 +26,10 @@
 		returning,
 
 		/** fValue is exception being thrown in a exception breakpoint */
-		throwing
+		throwing,
+
+		/** fValue is not set because the step operation took too long */
+		step_timeout
 	}
 
 	public MethodResult(Method method, int targetFrameCount, Value value, ResultType resultType) {
diff --git a/org.eclipse.jdt.debug/pom.xml b/org.eclipse.jdt.debug/pom.xml
index 21b69bb..05abe2a 100644
--- a/org.eclipse.jdt.debug/pom.xml
+++ b/org.eclipse.jdt.debug/pom.xml
@@ -18,6 +18,6 @@
   </parent>
   <groupId>org.eclipse.jdt</groupId>
   <artifactId>org.eclipse.jdt.debug</artifactId>
-  <version>3.11.200-SNAPSHOT</version>
+  <version>3.12.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 </project>
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMType.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMType.java
index 16e04d6..8802eca 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMType.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/StandardVMType.java
@@ -42,6 +42,7 @@
 import org.eclipse.core.runtime.Path;
 import org.eclipse.core.runtime.Platform;
 import org.eclipse.core.runtime.Status;
+import org.eclipse.debug.core.DebugException;
 import org.eclipse.debug.core.DebugPlugin;
 import org.eclipse.debug.core.ILaunchManager;
 import org.eclipse.debug.core.Launch;
@@ -219,6 +220,10 @@
 				} else {
 					info = generateLibraryInfo(javaHome, javaExecutable);
 					if (info == null) {
+						// Bug 536943: try again in case we have a timing problem with process execution and output retrieval
+						info = generateLibraryInfo(javaHome, javaExecutable);
+					}
+					if (info == null) {
 						info = getDefaultLibraryInfo(javaHome);
 						fgFailedInstallPath.put(installPath, info);
 					} else {
@@ -685,6 +690,7 @@
 				}
 				p = DebugPlugin.exec(cmdLine, null, envp);
 				IProcess process = DebugPlugin.newProcess(new Launch(null, ILaunchManager.RUN_MODE, null), p, "Library Detection"); //$NON-NLS-1$
+				process.setAttribute(IProcess.ATTR_CMDLINE, String.join(" ", cmdLine)); //$NON-NLS-1$
 				for (int i= 0; i < 600; i++) {
 					// Wait no more than 30 seconds (600 * 50 milliseconds)
 					if (process.isTerminated()) {
@@ -693,10 +699,12 @@
 					try {
 						Thread.sleep(50);
 					} catch (InterruptedException e) {
+						LaunchingPlugin.log(e);
 					}
 				}
+				checkProcessResult(process);
 				info = parseLibraryInfo(process);
-			} catch (CoreException ioe) {
+			} catch (Throwable ioe) {
 				LaunchingPlugin.log(ioe);
 			} finally {
 				if (p != null) {
@@ -849,4 +857,38 @@
 
 	}
 
+	/*
+	 * Logs an error if the process is not yet done, or if the process exited with an error code.
+	 */
+	private static void checkProcessResult(IProcess process) throws DebugException {
+		boolean isTerminated = process.isTerminated();
+		if (!isTerminated) {
+			String output = getOutput(process);
+			Object[] errorInfo = { process.getAttribute(IProcess.ATTR_CMDLINE), output };
+			String errorMessage = NLS.bind("Process not finished.\n Command line arguments: {0}\nOutput: {1}", errorInfo); //$NON-NLS-1$
+			IllegalStateException exception = new IllegalStateException(errorMessage);
+			LaunchingPlugin.log(exception);
+		} else {
+			int exitCode = process.getExitValue();
+			if (exitCode != 0) {
+				String output = getOutput(process);
+				Object[] errorInfo = { Integer.valueOf(exitCode), process.getAttribute(IProcess.ATTR_CMDLINE), output };
+				String errorMessage = NLS.bind("Process returned with error code \"{0}\".\nCommand line arguments: {1}\nOutput: {2}", errorInfo); //$NON-NLS-1$
+				IllegalStateException exception = new IllegalStateException(errorMessage);
+				LaunchingPlugin.log(exception);
+			}
+		}
+	}
+
+	private static String getOutput(IProcess process) {
+		IStreamsProxy streamsProxy = process.getStreamsProxy();
+		String output = "IProcess.getStreamsProxy() returned null"; //$NON-NLS-1$
+		if (streamsProxy != null) {
+			String[] lines = { "Standard output:", //$NON-NLS-1$
+					streamsProxy.getOutputStreamMonitor().getContents(), "Standard error:", //$NON-NLS-1$
+					streamsProxy.getErrorStreamMonitor().getContents() };
+			output = String.join(System.lineSeparator(), Arrays.asList(lines));
+		}
+		return output;
+	}
 }
diff --git a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/sourcelookup/advanced/WorkspaceProjectSourceContainers.java b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/sourcelookup/advanced/WorkspaceProjectSourceContainers.java
index 3bfd7f9..6569edc 100644
--- a/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/sourcelookup/advanced/WorkspaceProjectSourceContainers.java
+++ b/org.eclipse.jdt.launching/launching/org/eclipse/jdt/internal/launching/sourcelookup/advanced/WorkspaceProjectSourceContainers.java
@@ -44,6 +44,7 @@
 import org.eclipse.jdt.core.IJavaProject;
 import org.eclipse.jdt.core.IPackageFragmentRoot;
 import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.core.JavaModelException;
 import org.eclipse.jdt.internal.launching.sourcelookup.advanced.FileHashing.Hasher;
 import org.eclipse.jdt.launching.sourcelookup.advanced.IWorkspaceProjectDescriber;
 import org.eclipse.jdt.launching.sourcelookup.advanced.IWorkspaceProjectDescriber.IJavaProjectSourceDescription;
@@ -255,7 +256,7 @@
 
 	/**
 	 * Creates and returns new source container for the workspace project classpath entry identified by the given project and entry locations. Returns
-	 * {@code null} if there is no such project classpath entry.
+	 * {@code null} if there is no such project classpath entry or if the classpath entry does not have associated sources.
 	 */
 	public ISourceContainer createClasspathEntryContainer(File projectLocation, File entryLocation) {
 		Hasher hasher = FileHashing.hasher(); // use long-lived hasher
@@ -273,7 +274,11 @@
 			}
 		}
 
-		if (dependency == null) {
+		try {
+			if (dependency == null || (dependency.getKind() == IPackageFragmentRoot.K_BINARY && dependency.getSourceAttachmentPath() == null)) {
+				return null;
+			}
+		} catch (JavaModelException e) {
 			return null;
 		}