From 1ce9e59dfd7098327bbaf55a985c2a643ff52861 Mon Sep 17 00:00:00 2001 From: Davy Landman Date: Wed, 11 Sep 2024 10:02:33 +0200 Subject: [PATCH] Fixing race in exit code after a process has already completed --- src/org/rascalmpl/library/util/ShellExec.java | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/org/rascalmpl/library/util/ShellExec.java b/src/org/rascalmpl/library/util/ShellExec.java index 92dd0e5d25a..f19014c116a 100644 --- a/src/org/rascalmpl/library/util/ShellExec.java +++ b/src/org/rascalmpl/library/util/ShellExec.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import org.rascalmpl.exceptions.RuntimeExceptionFactory; import org.rascalmpl.uri.URIResolverRegistry; @@ -34,7 +35,8 @@ import io.usethesource.vallang.IValueFactory; public class ShellExec { - private static Map runningProcesses = new HashMap<>(); + private static Map runningProcesses = new ConcurrentHashMap<>(); + private static Map processExitCodes = new ConcurrentHashMap<>(); private static Map processInputStreams = new HashMap<>(); private static Map processErrorStreams = new HashMap<>(); private static Map processOutputStreams = new HashMap<>(); @@ -107,16 +109,18 @@ public IInteger exitCode(IInteger pid) { Process p = runningProcesses.get(pid); if (p == null) { - throw RuntimeExceptionFactory.illegalArgument(pid, "unknown process"); + IInteger storedExitCode = processExitCodes.get(pid); + if (storedExitCode == null) { + throw RuntimeExceptionFactory.illegalArgument(pid, "unknown process"); + } + return storedExitCode; } - while (true) { - try { - return vf.integer(p.waitFor()); - } - catch (InterruptedException e) { - continue; - } + try { + return vf.integer(p.waitFor()); + } + catch (InterruptedException e) { + throw RuntimeExceptionFactory.javaException(e, null, null); } } @@ -228,12 +232,13 @@ public synchronized void killProcess(IInteger processId, IBool force) { runningProcess.destroy(); } } - - new Thread("zombie process clean up") { + + Thread waitForCleared = new Thread("zombie process clean up") { public void run() { while (true) { try { runningProcess.waitFor(); + processExitCodes.put(processId, vf.integer(runningProcess.exitValue())); runningProcesses.remove(processId); return; } @@ -244,8 +249,9 @@ public void run() { } } }; - }.start(); - + }; + waitForCleared.setDaemon(true); + waitForCleared.start(); return; }