Skip to content

OpenJDK: Do not block signals - #19

Merged
guillerodriguez merged 1 commit into
masterfrom
fix/openjdk-blocked-signals
Aug 12, 2026
Merged

OpenJDK: Do not block signals#19
guillerodriguez merged 1 commit into
masterfrom
fix/openjdk-blocked-signals

Conversation

@guillerodriguez

Copy link
Copy Markdown
Contributor

JamVM blocks SIGQUIT, SIGINT and SIGPIPE in all threads. In the GNU Classpath port, a dedicated signal thread consumes SIGQUIT and SIGINT via sigwait(). SIGPIPE is blocked so that writes to broken pipes fail with EPIPE.

The OpenJDK backend uses asynchronous signal handlers: JamVM itself handles SIGQUIT for thread dumps, while SIGHUP, SIGINT and SIGTERM are registered by the class library through sun.misc.Signal. Because SIGQUIT and SIGINT are blocked, their handlers are never invoked. As a result, Ctrl-C neither terminates the VM nor runs shutdown hooks, and SIGQUIT does not produce a thread dump.

The signal mask also survives exec() and is inherited by processes launched through Runtime.exec() or ProcessBuilder. OpenJDK did not reset it in the posix_spawn() path until OpenJDK 20 (JDK-8234262).

Make the signal-mask policy class-library specific:

  • GNU Classpath keeps blocking SIGQUIT, SIGINT and SIGPIPE as before.
  • OpenJDK instead ensures that SIGQUIT, SIGHUP, SIGINT, SIGTERM and SIGPIPE are unblocked, and installs a no-op handler for SIGPIPE so that writes to broken pipes remain nonfatal. Unlike a blocked or ignored signal, the SIGPIPE handler is reset to the default across exec() and therefore does not leak into spawned children.

JamVM blocks SIGQUIT, SIGINT and SIGPIPE in all threads. In the GNU
Classpath port, a dedicated signal thread consumes SIGQUIT and SIGINT
via sigwait(). SIGPIPE is blocked so that writes to broken pipes fail
with EPIPE.

The OpenJDK backend uses asynchronous signal handlers: JamVM itself
handles SIGQUIT for thread dumps, while SIGHUP, SIGINT and SIGTERM
are registered by the class library through sun.misc.Signal. Because
SIGQUIT and SIGINT are blocked, their handlers are never invoked.
As a result, Ctrl-C neither terminates the VM nor runs shutdown hooks,
and SIGQUIT does not produce a thread dump.

The signal mask also survives exec() and is inherited by processes
launched through Runtime.exec() or ProcessBuilder. OpenJDK did not
reset it in the posix_spawn() path until OpenJDK 20 (JDK-8234262).

Make the signal-mask policy class-library specific:

- GNU Classpath keeps blocking SIGQUIT, SIGINT and SIGPIPE as before.
- OpenJDK instead ensures that SIGQUIT, SIGHUP, SIGINT, SIGTERM and
  SIGPIPE are unblocked, and installs a no-op handler for SIGPIPE so
  that writes to broken pipes remain nonfatal. Unlike a blocked or
  ignored signal, the SIGPIPE handler is reset to the default across
  exec() and therefore does not leak into spawned children.

Signed-off-by: Guillermo Rodríguez <grodriguez@ingelabs.com>
@guillerodriguez
guillerodriguez requested a review from phvega August 11, 2026 16:22
@guillerodriguez guillerodriguez linked an issue Aug 11, 2026 that may be closed by this pull request
@guillerodriguez
guillerodriguez merged commit 089a6a0 into master Aug 12, 2026
5 checks passed
@guillerodriguez
guillerodriguez deleted the fix/openjdk-blocked-signals branch August 12, 2026 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Do not block signals when using OpenJDK

2 participants