-
Notifications
You must be signed in to change notification settings - Fork 361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support shutdown hooks with signals #3821
Changes from all commits
85ddaa4
1e6d445
4d33a60
e3f75f1
b67a679
c0c2870
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ package java.lang | |
import java.io.File | ||
import java.util.{Set => juSet} | ||
import java.util.Comparator | ||
import scala.scalanative.libc.signal | ||
import scala.scalanative.libc.stdlib | ||
import scala.scalanative.posix.unistd._ | ||
import scala.scalanative.windows.SysInfoApi._ | ||
|
@@ -18,6 +19,20 @@ class Runtime private () { | |
lazy val setupAtExitHandler = { | ||
stdlib.atexit(() => Runtime.getRuntime().runHooks()) | ||
} | ||
|
||
// https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html | ||
// Currently, we use C lib signals so SIGHUP is not covered for POSIX platforms. | ||
|
||
lazy val setupSignalHandler = { | ||
signal.signal(signal.SIGINT, handleSignal(_)) | ||
signal.signal(signal.SIGTERM, handleSignal(_)) | ||
} | ||
|
||
private def handleSignal(sig: CInt): Unit = { | ||
Runtime.getRuntime().runHooks() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it won't work when we'll have multiple threads running. Starting |
||
exit(128 + sig) | ||
} | ||
|
||
private def ensureCanModify(hook: Thread): Unit = if (shutdownStarted) { | ||
throw new IllegalStateException( | ||
s"Shutdown sequence started, cannot add/remove hook $hook" | ||
|
@@ -28,6 +43,7 @@ class Runtime private () { | |
ensureCanModify(thread) | ||
hooks.add(thread) | ||
setupAtExitHandler | ||
setupSignalHandler | ||
} | ||
|
||
def removeShutdownHook(thread: Thread): Boolean = hooks.synchronized { | ||
|
@@ -41,7 +57,7 @@ class Runtime private () { | |
.asInstanceOf[Array[Thread]] | ||
.sorted(Ordering.by[Thread, Int](-_.getPriority())) | ||
hooks.foreach { t => | ||
t.setUncaughtExceptionHandler(ShutdownHookUncoughExceptionHandler) | ||
t.setUncaughtExceptionHandler(ShutdownHookUncaughtExceptionHandler) | ||
} | ||
// JDK specifies that hooks might run in any order. | ||
// However, for Scala Native it might be beneficial to support partial ordering | ||
|
@@ -70,16 +86,18 @@ class Runtime private () { | |
try t.run() | ||
catch { | ||
case ex: Throwable => | ||
ShutdownHookUncoughExceptionHandler.uncaughtException(t, ex) | ||
ShutdownHookUncaughtExceptionHandler.uncaughtException(t, ex) | ||
} | ||
} | ||
} | ||
private def runHooks() = { | ||
import scala.scalanative.meta.LinktimeInfo.isMultithreadingEnabled | ||
hooks.synchronized { | ||
shutdownStarted = true | ||
if (isMultithreadingEnabled) runHooksConcurrent() | ||
else runHooksSequential() | ||
if (!shutdownStarted) { | ||
shutdownStarted = true | ||
if (isMultithreadingEnabled) runHooksConcurrent() | ||
else runHooksSequential() | ||
} | ||
} | ||
} | ||
|
||
|
@@ -108,7 +126,7 @@ class Runtime private () { | |
exec(Array(cmd), envp, dir) | ||
} | ||
|
||
private object ShutdownHookUncoughExceptionHandler | ||
private object ShutdownHookUncaughtExceptionHandler | ||
extends Thread.UncaughtExceptionHandler { | ||
def uncaughtException(t: Thread, e: Throwable): Unit = { | ||
System.err.println(s"Shutdown hook $t failed, reason: $e") | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's add a few more expected reason to quit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I understand "The JVM runs shutdown hooks only in case of normal terminations." - what this seems to mean is Ctrl-C
SIGINT
andSIGTERM
. This is also in the current Test comments.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://docs.oracle.com/en/java/javase/21/docs/specs/man/java.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll add
SIGHUP
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On second thought, we need to try and get this to work properly this way first as we are using
clib
andSIGHUP
is not a member. I second pass could useposixlib
and something special for Windows to make it JVM compliant.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keep in mind that
SIGHUP
is a signal which is send when SSH connection is hand up due network issue.Without it, shutdown hook at CLI utilite won't work on this case and it's show stoper for real life use case I guess.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No problem but we have nothing now and to make it cross platform is more complex so it might be better to have something now.