diff --git a/src/main/java/org/cobbzilla/util/daemon/TerminationRequestResult.java b/src/main/java/org/cobbzilla/util/daemon/TerminationRequestResult.java new file mode 100644 index 0000000..625d17b --- /dev/null +++ b/src/main/java/org/cobbzilla/util/daemon/TerminationRequestResult.java @@ -0,0 +1,7 @@ +package org.cobbzilla.util.daemon; + +public enum TerminationRequestResult { + + alive, interrupted, terminated; + +} diff --git a/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java b/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java index ec8d156..32c0d73 100644 --- a/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java +++ b/src/main/java/org/cobbzilla/util/daemon/ZillaRuntime.java @@ -54,28 +54,49 @@ public class ZillaRuntime { public static String getJava() { return System.getProperty("java.home") + "/bin/java"; } - public static boolean terminateQuietly(Thread thread, long timeout) { + public static TerminationRequestResult terminateQuietly(Thread thread, long timeout) { return terminate(thread, timeout, false); } - public static boolean terminate(Thread thread, long timeout) { + public static TerminationRequestResult terminate(Thread thread, long timeout) { return terminate(thread, timeout, true); } - public static boolean terminate(Thread thread, long timeout, boolean verbose) { - if (thread == null || !thread.isAlive()) return true; + public static TerminationRequestResult terminate(Thread thread, long timeout, boolean verbose) { + return terminate(thread, timeout, null, verbose); + } + + public static TerminationRequestResult terminate(Thread thread, long timeout, Function onlyIf) { + return terminate(thread, timeout, onlyIf, true); + } + + public static TerminationRequestResult terminateQuietly(Thread thread, long timeout, Function onlyIf) { + return terminate(thread, timeout, onlyIf, false); + } + + public static TerminationRequestResult terminate(Thread thread, long timeout, Function onlyIf, boolean verbose) { + if (thread == null || !thread.isAlive()) return TerminationRequestResult.alive; + if (onlyIf != null && !onlyIf.apply(thread)) { + if (log.isWarnEnabled()) log.warn("terminate: thread is alive but onlyIf function returned false, not interrupting: " + thread + (verbose ? " with stack " + stacktrace(thread) + "\nfrom: " + stacktrace() : "")); + return TerminationRequestResult.alive; + } thread.interrupt(); final long start = realNow(); while (thread.isAlive() && realNow() - start < timeout) { sleep(100, "terminate: waiting for thread to exit: "+thread); } if (thread.isAlive()) { - if (verbose && log.isWarnEnabled()) log.warn("terminate: thread did not respond to interrupt, killing: "+thread+" with stack "+stacktrace(thread)+"\nfrom: "+stacktrace()); - thread.stop(); - return false; + if (onlyIf != null && onlyIf.apply(thread)) { + if (log.isWarnEnabled()) log.warn("terminate: thread did not respond to interrupt, killing: " + thread + (verbose ? " with stack " + stacktrace(thread) + "\nfrom: " + stacktrace() : "")); + thread.stop(); + return TerminationRequestResult.terminated; + } else { + if (log.isWarnEnabled()) log.warn("terminate: thread did not respond to interrupt, but onlyIf function returned false, not killing: " + thread + (verbose ? " with stack " + stacktrace(thread) + "\nfrom: " + stacktrace() : "")); + return TerminationRequestResult.interrupted; + } } else { - if (verbose && log.isWarnEnabled()) log.warn("terminate: thread exited after interrupt: "+thread); - return true; + if (log.isWarnEnabled()) log.warn("terminate: thread exited after interrupt: "+thread); + return TerminationRequestResult.interrupted; } } diff --git a/src/main/java/org/cobbzilla/util/io/multi/MultiUnderflowHandlerMonitor.java b/src/main/java/org/cobbzilla/util/io/multi/MultiUnderflowHandlerMonitor.java index fbcbd65..f6f3fa4 100644 --- a/src/main/java/org/cobbzilla/util/io/multi/MultiUnderflowHandlerMonitor.java +++ b/src/main/java/org/cobbzilla/util/io/multi/MultiUnderflowHandlerMonitor.java @@ -45,7 +45,7 @@ public class MultiUnderflowHandlerMonitor extends SimpleDaemon { iter.remove(); if (terminateThreadFunc == null || terminateThreadFunc.apply(underflow.getThread())) { if (log.isErrorEnabled()) log.error(prefix+"underflow timed out, terminating: name=" + underflow.getHandlerName() + " thread=" + underflow.getThread()); - terminate(underflow.getThread(), TERMINATE_TIMEOUT); + terminate(underflow.getThread(), TERMINATE_TIMEOUT, terminateThreadFunc); } else { if (log.isErrorEnabled()) log.error(prefix+"underflow timed out, removing but NOT terminating: name=" + underflow.getHandlerName() + " thread=" + underflow.getThread()); }