From a578df175d929e7451aca8c11c1d6fca51e21c9a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 09:23:34 +0000 Subject: [PATCH 1/2] Replace Thread.stop with interrupt-based shutdown Agent-Logs-Url: https://github.com/ashr123/beast-mcmc/sessions/e776e08a-5ccc-4a73-a047-8b3ef94db330 Co-authored-by: ashr123 <26481657+ashr123@users.noreply.github.com> --- src/dr/app/beast/BeastMain.java | 10 ++------- src/dr/xml/XMLParser.java | 39 +++++++++++++++++++++++++++++---- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/dr/app/beast/BeastMain.java b/src/dr/app/beast/BeastMain.java index 3bec257252..5b6e02fbed 100644 --- a/src/dr/app/beast/BeastMain.java +++ b/src/dr/app/beast/BeastMain.java @@ -49,7 +49,6 @@ import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.logging.*; @@ -80,11 +79,8 @@ public BeastConsoleApp(String nameString, String titleString, String aboutString } public void doStop() { - Iterator iter = parser.getThreads(); - while (iter.hasNext()) { - Thread thread = (Thread) iter.next(); - //noinspection removal - thread.stop(); // http://java.sun.com/j2se/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html + if (parser != null) { + parser.interruptThreads(); } } @@ -1039,5 +1035,3 @@ public void uncaughtException(Thread t, Throwable e) { } } } - - diff --git a/src/dr/xml/XMLParser.java b/src/dr/xml/XMLParser.java index e252c3acec..2ffaa19289 100644 --- a/src/dr/xml/XMLParser.java +++ b/src/dr/xml/XMLParser.java @@ -40,6 +40,8 @@ import org.xml.sax.helpers.DefaultHandler; import java.io.*; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.*; public class XMLParser { @@ -108,6 +110,13 @@ public Iterator getThreads() { return threads.iterator(); } + public void interruptThreads() { + for (Thread thread : threads) { + requestThreadStop(thread); + thread.interrupt(); + } + } + public void storeObject(String name, Object object) { XMLObject xo = new XMLObject(null, null /*, objectStore*/); @@ -370,9 +379,11 @@ private Object convert(Element e, Class target, XMLObject parent, boolean run, b for (int i = 0; i < xo.getChildCount(); i++) { Object child = xo.getChild(i); if (child instanceof Runnable) { - Thread thread = new Thread((Runnable) child); + Runnable runnable = (Runnable) child; + Thread thread = new Thread(runnable); thread.start(); threads.add(thread); + threadTasks.put(thread, runnable); } else throw new XMLParseException("Concurrent element children must be runnable!"); } concurrent = false; @@ -387,13 +398,16 @@ private Object convert(Element e, Class target, XMLObject parent, boolean run, b if (obj instanceof Spawnable && !((Spawnable) obj).getSpawnable()) { ((Spawnable) obj).run(); } else { - Thread thread = new Thread((Runnable) obj); + Runnable runnable = (Runnable) obj; + Thread thread = new Thread(runnable); thread.start(); threads.add(thread); + threadTasks.put(thread, runnable); waitForThread(thread); } } threads.removeAllElements(); + threadTasks.clear(); } return xo; @@ -551,11 +565,28 @@ private void waitForThread(Thread thread) { try { thread.join(); } catch (InterruptedException ie) { - // DO NOTHING + interruptThreads(); + Thread.currentThread().interrupt(); + return; } } } + private void requestThreadStop(Thread thread) { + Runnable runnable = threadTasks.get(thread); + if (runnable == null) { + return; + } + try { + Method method = runnable.getClass().getMethod("pleaseStop"); + method.invoke(runnable); + } catch (NoSuchMethodException ignored) { + // Runnable does not support cooperative stopping. + } catch (IllegalAccessException | InvocationTargetException ignored) { + // Fall back to interruption. + } + } + // //anonymous object store class // private final ObjectStore objectStore = new ObjectStore() { // public Object getObjectById(Object uid) throws ObjectNotFoundException { @@ -612,6 +643,7 @@ public void addCitable(Citable citable) { private final Map parserStore = new TreeMap(new ParserComparator()); private final Map objectStore = new LinkedHashMap(); private final Map, List> citationStore = new LinkedHashMap, List>(); + private final Map threadTasks = new HashMap(); private boolean concurrent = false; private XMLObject root = null; @@ -657,4 +689,3 @@ public int compare(String o1, String o2) { } - From 135dc9d027718f783155e32957480ecd0a5d162b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 3 May 2026 09:51:16 +0000 Subject: [PATCH 2/2] Refine parser interrupt-based cooperative shutdown handling Agent-Logs-Url: https://github.com/ashr123/beast-mcmc/sessions/e776e08a-5ccc-4a73-a047-8b3ef94db330 Co-authored-by: ashr123 <26481657+ashr123@users.noreply.github.com> --- src/dr/xml/XMLParser.java | 67 +++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 14 deletions(-) diff --git a/src/dr/xml/XMLParser.java b/src/dr/xml/XMLParser.java index 2ffaa19289..b1010c8ab4 100644 --- a/src/dr/xml/XMLParser.java +++ b/src/dr/xml/XMLParser.java @@ -43,9 +43,12 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; +import java.util.logging.Logger; public class XMLParser { + private static final Logger LOGGER = Logger.getLogger(XMLParser.class.getName()); + public static final String ID = XMLObject.ID; public static final String IDREF = "idref"; public static final String CONCURRENT = "concurrent"; @@ -107,11 +110,21 @@ public Iterator getParsers() { } public Iterator getThreads() { - return threads.iterator(); + synchronized (threadLock) { + return new ArrayList(threads).iterator(); + } } public void interruptThreads() { - for (Thread thread : threads) { + List currentThreads; + synchronized (threadLock) { + if (interruptRequested) { + return; + } + interruptRequested = true; + currentThreads = new ArrayList(threads); + } + for (Thread thread : currentThreads) { requestThreadStop(thread); thread.interrupt(); } @@ -382,8 +395,10 @@ private Object convert(Element e, Class target, XMLObject parent, boolean run, b Runnable runnable = (Runnable) child; Thread thread = new Thread(runnable); thread.start(); - threads.add(thread); - threadTasks.put(thread, runnable); + synchronized (threadLock) { + threads.add(thread); + threadTasks.put(thread, runnable); + } } else throw new XMLParseException("Concurrent element children must be runnable!"); } concurrent = false; @@ -401,13 +416,18 @@ private Object convert(Element e, Class target, XMLObject parent, boolean run, b Runnable runnable = (Runnable) obj; Thread thread = new Thread(runnable); thread.start(); - threads.add(thread); - threadTasks.put(thread, runnable); + synchronized (threadLock) { + threads.add(thread); + threadTasks.put(thread, runnable); + } waitForThread(thread); } } - threads.removeAllElements(); - threadTasks.clear(); + synchronized (threadLock) { + threadTasks.clear(); + threads.removeAllElements(); + interruptRequested = false; + } } return xo; @@ -565,15 +585,21 @@ private void waitForThread(Thread thread) { try { thread.join(); } catch (InterruptedException ie) { - interruptThreads(); + // Preserve interrupt status for callers that manage parser shutdown. Thread.currentThread().interrupt(); + requestThreadStop(thread); + removeThreadTracking(thread); return; } } + removeThreadTracking(thread); } private void requestThreadStop(Thread thread) { - Runnable runnable = threadTasks.get(thread); + Runnable runnable; + synchronized (threadLock) { + runnable = threadTasks.get(thread); + } if (runnable == null) { return; } @@ -581,9 +607,21 @@ private void requestThreadStop(Thread thread) { Method method = runnable.getClass().getMethod("pleaseStop"); method.invoke(runnable); } catch (NoSuchMethodException ignored) { - // Runnable does not support cooperative stopping. - } catch (IllegalAccessException | InvocationTargetException ignored) { - // Fall back to interruption. + // Expected: runnable does not implement pleaseStop(). + } catch (IllegalAccessException e) { + LOGGER.warning("Error while accessing pleaseStop() on " + + runnable.getClass().getName() + ": " + e.getMessage()); + } catch (InvocationTargetException e) { + Throwable cause = e.getCause(); + LOGGER.warning("Error while invoking pleaseStop() on " + + runnable.getClass().getName() + ": " + (cause == null ? e.getMessage() : cause.getMessage())); + } + } + + private void removeThreadTracking(Thread thread) { + synchronized (threadLock) { + threadTasks.remove(thread); + threads.remove(thread); } } @@ -644,7 +682,9 @@ public void addCitable(Citable citable) { private final Map objectStore = new LinkedHashMap(); private final Map, List> citationStore = new LinkedHashMap, List>(); private final Map threadTasks = new HashMap(); + private final Object threadLock = new Object(); private boolean concurrent = false; + private boolean interruptRequested = false; private XMLObject root = null; private boolean verbose = false; @@ -688,4 +728,3 @@ public int compare(String o1, String o2) { } } -