Bug 579064 - Thread names for Process Monitors with PID

and launch config name.

Change-Id: I9f1fb52024be04982c21373e9ad258267bd2ded4
Signed-off-by: Joerg Kubitz <jkubitz-eclipse@gmx.de>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.debug/+/190971
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Sarika Sinha <sarika.sinha@in.ibm.com>
diff --git a/org.eclipse.debug.core/META-INF/MANIFEST.MF b/org.eclipse.debug.core/META-INF/MANIFEST.MF
index 9c1ea44..60eb6d1 100644
--- a/org.eclipse.debug.core/META-INF/MANIFEST.MF
+++ b/org.eclipse.debug.core/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.debug.core; singleton:=true
-Bundle-Version: 3.19.0.qualifier
+Bundle-Version: 3.19.100.qualifier
 Bundle-ClassPath: .
 Bundle-Activator: org.eclipse.debug.core.DebugPlugin
 Bundle-Vendor: %providerName
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/core/model/RuntimeProcess.java b/org.eclipse.debug.core/core/org/eclipse/debug/core/model/RuntimeProcess.java
index 193458f..62a4e6c 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/core/model/RuntimeProcess.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/core/model/RuntimeProcess.java
@@ -107,6 +107,8 @@
 	 */
 	private boolean fTerminateDescendants = true;
 
+	private final String fThreadNameSuffix;
+
 	/**
 	 * Constructs a RuntimeProcess on the given system process
 	 * with the given name, adding this process to the given
@@ -146,14 +148,26 @@
 		} catch (CoreException e) {
 			DebugPlugin.log(e);
 		}
+		fThreadNameSuffix = getPidInfo(process, launch);
 
 		fStreamsProxy = createStreamsProxy();
-		fMonitor = new ProcessMonitorThread();
+		fMonitor = new ProcessMonitorThread(fThreadNameSuffix);
 		fMonitor.start();
 		launch.addProcess(this);
 		fireCreationEvent();
 	}
 
+	private static String getPidInfo(Process process, ILaunch launch) {
+		String pid;
+		ILaunchConfiguration lc = launch == null ? null : launch.getLaunchConfiguration();
+		String name = lc == null ? "" : " " + lc.getName(); //$NON-NLS-1$ //$NON-NLS-2$
+		try {
+			pid = " for PID " + process.pid(); //$NON-NLS-1$
+		} catch (Exception e) {
+			pid = ""; //$NON-NLS-1$
+		}
+		return pid + name;
+	}
 	/**
 	 * Initialize the attributes of this process to those in the given map.
 	 *
@@ -355,7 +369,7 @@
 				DebugPlugin.log(e);
 			}
 		}
-		return new StreamsProxy(getSystemProcess(), charset);
+		return new StreamsProxy(getSystemProcess(), charset, fThreadNameSuffix);
 	}
 
 	/**
@@ -488,9 +502,11 @@
 		/**
 		 * Creates a new process monitor and starts monitoring the process for
 		 * termination.
+		 *
+		 * @param suffix Thread name suffix
 		 */
-		private ProcessMonitorThread() {
-			super(DebugCoreMessages.ProcessMonitorJob_0);
+		private ProcessMonitorThread(String suffix) {
+			super(DebugCoreMessages.ProcessMonitorJob_0 + suffix);
 			setDaemon(true);
 		}
 
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java
index d38a64f..d17d3fc 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.java
@@ -89,7 +89,6 @@
 	public static String LogicalStructureProvider_1;
 	public static String LogicalStructureType_1;
 	public static String SystemPropertyResolver_0;
-	public static String InputStreamMonitor_label;
 	public static String Launch_terminate_failed;
 	public static String LaunchConfiguration_Failed_to_delete_launch_configuration__1;
 	public static String LaunchConfigurationDelegate_6;
@@ -115,7 +114,6 @@
 	public static String LaunchManager_invalid_config_name_char;
 	public static String LaunchManager_Source_locator_does_not_exist___0__13;
 	public static String LogicalStructureType_0;
-	public static String OutputStreamMonitor_label;
 	public static String ProcessMonitorJob_0;
 	public static String RuntimeProcess_terminate_failed;
 	public static String RuntimeProcess_Exit_value_not_available_until_process_terminates__1;
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties
index eae7e6d..70ee71c 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/DebugCoreMessages.properties
@@ -44,7 +44,6 @@
 GroupLaunchElement_inherit_launch_mode_label=Inherit
 GroupLaunchElement_outputRegexp=Wait for console output (regexp)
 SystemPropertyResolver_0=System property not specified
-InputStreamMonitor_label=Input Stream Monitor
 Launch_terminate_failed=Terminate failed
 LaunchConfiguration_Failed_to_delete_launch_configuration__1=Failed to delete launch configuration.
 LaunchConfiguration_9=Preparing launch delegate...
@@ -114,7 +113,6 @@
 LogicalStructureType_1=Required attribute {0} missing for logicalStructureType extension.
 LogicalStructureProvider_0=Required attribute modelIdentifier missing for logicalStructureType extension.
 LogicalStructureProvider_1=Required attribute class missing for logicalStructureType extension.
-OutputStreamMonitor_label=Output Stream Monitor
 ProcessMonitorJob_0=Process monitor
 RuntimeProcess_terminate_failed=Terminate failed
 RuntimeProcess_Exit_value_not_available_until_process_terminates__1=Exit value not available until process terminates.
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/InputStreamMonitor.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/InputStreamMonitor.java
index d0525f6..eacd9e3 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/InputStreamMonitor.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/InputStreamMonitor.java
@@ -127,13 +127,19 @@
 		}
 	}
 
+	public void startMonitoring() {
+		startMonitoring("Input Stream Monitor"); //$NON-NLS-1$
+	}
+
 	/**
 	 * Starts a thread which writes the stream.
+	 *
+	 * @param threadName Thread name
 	 */
-	public void startMonitoring() {
+	public void startMonitoring(String threadName) {
 		synchronized (this) {
 			if (fThread == null) {
-				fThread = new Thread((Runnable) this::write, DebugCoreMessages.InputStreamMonitor_label);
+				fThread = new Thread((Runnable) this::write, threadName);
 				fThread.setDaemon(true);
 				fThread.start();
 			}
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java
index 3a6f1a4..fb09bc6 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/OutputStreamMonitor.java
@@ -308,12 +308,14 @@
 
 	/**
 	 * Starts a thread which reads from the stream
+	 *
+	 * @param name Thread name
 	 */
-	protected void startMonitoring() {
+	protected void startMonitoring(String name) {
 		synchronized (this) {
 			if (fThread == null) {
 				fDone.set(false);
-				fThread = new Thread((Runnable) this::read, DebugCoreMessages.OutputStreamMonitor_label);
+				fThread = new Thread((Runnable) this::read, name);
 				fThread.setDaemon(true);
 				fThread.setPriority(Thread.MIN_PRIORITY);
 				fThread.start();
diff --git a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamsProxy.java b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamsProxy.java
index 0f14b7d..3996d95 100644
--- a/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamsProxy.java
+++ b/org.eclipse.debug.core/core/org/eclipse/debug/internal/core/StreamsProxy.java
@@ -55,18 +55,19 @@
 	 *
 	 * @param process system process to create a streams proxy on
 	 * @param charset the process's charset or <code>null</code> if default
+	 * @param suffix Thread name suffix
 	 */
 	@SuppressWarnings("resource")
-	public StreamsProxy(Process process, Charset charset) {
+	public StreamsProxy(Process process, Charset charset, String suffix) {
 		if (process == null) {
 			return;
 		}
 		fOutputMonitor = new OutputStreamMonitor(process.getInputStream(), charset);
 		fErrorMonitor = new OutputStreamMonitor(process.getErrorStream(), charset);
 		fInputMonitor = new InputStreamMonitor(process.getOutputStream(), charset);
-		fOutputMonitor.startMonitoring();
-		fErrorMonitor.startMonitoring();
-		fInputMonitor.startMonitoring();
+		fOutputMonitor.startMonitoring("Output Stream Monitor" + suffix); //$NON-NLS-1$
+		fErrorMonitor.startMonitoring("Error Stream Monitor" + suffix); //$NON-NLS-1$
+		fInputMonitor.startMonitoring("Input Stream Monitor" + suffix); //$NON-NLS-1$
 	}
 
 	/**
@@ -83,7 +84,7 @@
 		// but Bug 562653 brought up a client which use this internal class via
 		// reflection and breaks without this constructor. So we restored the
 		// old constructor for the time being.
-		this(process, Charset.forName(encoding));
+		this(process, Charset.forName(encoding), ""); //$NON-NLS-1$
 	}
 
 	/**
diff --git a/org.eclipse.debug.tests/META-INF/MANIFEST.MF b/org.eclipse.debug.tests/META-INF/MANIFEST.MF
index 659b8de..1dffc2b 100644
--- a/org.eclipse.debug.tests/META-INF/MANIFEST.MF
+++ b/org.eclipse.debug.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.debug.tests;singleton:=true
-Bundle-Version: 3.12.600.qualifier
+Bundle-Version: 3.12.700.qualifier
 Bundle-Activator: org.eclipse.debug.tests.TestsPlugin
 Bundle-Localization: plugin
 Require-Bundle: org.eclipse.ui;bundle-version="[3.6.0,4.0.0)",
diff --git a/org.eclipse.debug.tests/pom.xml b/org.eclipse.debug.tests/pom.xml
index 02eb2f0..c55bdbc 100644
--- a/org.eclipse.debug.tests/pom.xml
+++ b/org.eclipse.debug.tests/pom.xml
@@ -18,7 +18,7 @@
   </parent>
   <groupId>org.eclipse.debug</groupId>
   <artifactId>org.eclipse.debug.tests</artifactId>
-  <version>3.12.600-SNAPSHOT</version>
+  <version>3.12.700-SNAPSHOT</version>
   <packaging>eclipse-test-plugin</packaging>
   <properties>
     <code.ignoredWarnings>${tests.ignoredWarnings}</code.ignoredWarnings>
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/InputStreamMonitorTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/InputStreamMonitorTests.java
index 361995c..45f7756 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/InputStreamMonitorTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/InputStreamMonitorTests.java
@@ -25,7 +25,6 @@
 import java.util.function.Supplier;
 
 import org.eclipse.core.runtime.Platform;
-import org.eclipse.debug.internal.core.DebugCoreMessages;
 import org.eclipse.debug.internal.core.InputStreamMonitor;
 import org.eclipse.debug.tests.AbstractDebugTest;
 import org.eclipse.debug.tests.TestUtil;
@@ -96,9 +95,10 @@
 	@Test
 	@SuppressWarnings("resource")
 	public void testClose() throws Exception {
+		String threadName = "MAGICtestClose";
 		Supplier<Long> getInputStreamMonitorThreads = () -> {
 			Set<Thread> allThreads = Thread.getAllStackTraces().keySet();
-			long numMonitorThreads = allThreads.stream().filter(t -> DebugCoreMessages.InputStreamMonitor_label.equals(t.getName())).count();
+			long numMonitorThreads = allThreads.stream().filter(t -> t.getName().contains(threadName)).count();
 			return numMonitorThreads;
 		};
 		long alreadyLeakedThreads = getInputStreamMonitorThreads.get();
@@ -117,7 +117,7 @@
 		{
 			ClosableTestOutputStream testStream = new ClosableTestOutputStream();
 			InputStreamMonitor monitor = new InputStreamMonitor(testStream);
-			monitor.startMonitoring();
+			monitor.startMonitoring(threadName);
 			assertEquals("Stream closed to early.", 0, testStream.numClosed);
 			monitor.close();
 			TestUtil.waitWhile(() -> testStream.numClosed == 0, 200);
@@ -126,7 +126,7 @@
 		{
 			ClosableTestOutputStream testStream = new ClosableTestOutputStream();
 			InputStreamMonitor monitor = new InputStreamMonitor(testStream);
-			monitor.startMonitoring();
+			monitor.startMonitoring(threadName);
 			assertEquals("Stream closed to early.", 0, testStream.numClosed);
 			monitor.closeInputStream();
 			monitor.close();
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/OutputStreamMonitorTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/OutputStreamMonitorTests.java
index 0d36102..523192a 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/OutputStreamMonitorTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/OutputStreamMonitorTests.java
@@ -195,9 +195,8 @@
 			super(stream, charset);
 		}
 
-		@Override
 		public void startMonitoring() {
-			super.startMonitoring();
+			super.startMonitoring("");
 		}
 
 		@Override
diff --git a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/StreamsProxyTests.java b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/StreamsProxyTests.java
index 7156914..571da15 100644
--- a/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/StreamsProxyTests.java
+++ b/org.eclipse.debug.tests/src/org/eclipse/debug/tests/console/StreamsProxyTests.java
@@ -66,7 +66,7 @@
 		final String s = prefix + String.join("", Collections.nCopies(numTwoByteCharacters, "\u00F8"));
 		final ByteArrayInputStream stdout = new ByteArrayInputStream(s.getBytes(StandardCharsets.UTF_8));
 		final Process mockProcess = new MockProcess(stdout, null, 0);
-		final StreamsProxy streamProxy = new StreamsProxy(mockProcess, StandardCharsets.UTF_8);
+		final StreamsProxy streamProxy = new StreamsProxy(mockProcess, StandardCharsets.UTF_8, "");
 		streamProxy.close();
 		final String readContent = streamProxy.getOutputStreamMonitor().getContents();
 		assertEquals("Process output got corrupted.", s, readContent);