Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Provide fix for #81093 - "Mono does not emit ProcessExit event on SIG…
…TERM"

* src/mono/mono/mini/mini-posix.c
  - Add signal handler for SIGTERM

* src/mono/mono/mini/mini-windows.c
  - Add signal handler for SIGTERM
  - Use the correct signal for handler

* src/mono/mono/mini/mini-runtime.c
  - Add mono_sigterm_signal_handler to process SIGTERM that will set a global variable
    to be monitored by the GC finalizer thread
  - Set a default exit code before setting the term_signaled variable that gets checked in gc

* src/mono/mono/mini/mini-runtime.h
  - Define prototype for mono_sigterm_signal_handler()

* src/mono/mono/metadata/gc.c
  - Monitor for sigterm and kick off the shutdown process when encountered by calling mono_runtime_try_shutdown().
  - Exit with either the user set exitcode (System.Environment.ExitCode) or SIGTERM + 128.
  - Simplify use of exit code now that a default is being set
  - Rename term_signaled to match mono style
  - Remove volatile attribute
  - Move testing of shutdown until after the sem wait

* src/libraries/System.Runtime/tests/System/ExitCodeTests.Unix.cs
  - Re-enable ExitCodeTests for mono

* src/mono/mono/mini/exceptions-amd64.c
  src/mono/mono/mini/exceptions-x86.c
  - Add control event handling for windows
  • Loading branch information
nealef committed Mar 21, 2024
commit 63d16ca1fb18b07389e2c8de8fb9295f561c1ae3
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public class ExitCodeTests
private static extern int kill(int pid, int sig);

[ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/31656", TestRuntimes.Mono)]
[InlineData(null)]
[InlineData(0)]
[InlineData(42)]
Expand Down
10 changes: 10 additions & 0 deletions src/mono/mono/metadata/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <mono/metadata/class-internals.h>
#include <mono/metadata/metadata-internals.h>
#include <mono/metadata/threads-types.h>
#include <mono/metadata/runtime.h>
#include <mono/sgen/sgen-conf.h>
#include <mono/sgen/sgen-gc.h>
#include <mono/utils/mono-logger-internals.h>
Expand Down Expand Up @@ -63,6 +64,8 @@ static gboolean gc_disabled;

static gboolean finalizing_root_domain;

extern gboolean mono_term_signaled;

gboolean mono_log_finalizers;
gboolean mono_do_not_finalize;
static volatile gboolean suspend_finalizers;
Expand Down Expand Up @@ -852,6 +855,7 @@ finalizer_thread (gpointer unused)
mono_hazard_pointer_install_free_queue_size_callback (hazard_free_queue_is_too_big);

while (!finished) {

/* Wait to be notified that there's at least one
* finaliser to run
*/
Expand All @@ -865,6 +869,12 @@ finalizer_thread (gpointer unused)
}
wait = TRUE;

/* Just in case we've received a SIGTERM */
if (mono_term_signaled) {
mono_runtime_try_shutdown();
exit(mono_environment_exitcode_get());
}

mono_thread_info_set_flags (MONO_THREAD_INFO_FLAGS_NONE);

/* The Finalizer thread doesn't initialize during creation because base managed
Expand Down
34 changes: 34 additions & 0 deletions src/mono/mono/mini/exceptions-amd64.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,14 @@
#include "mono/utils/mono-tls-inline.h"

#ifdef TARGET_WIN32
#include <windows.h>
static void (*restore_stack) (void);
static MonoW32ExceptionHandler fpe_handler;
static MonoW32ExceptionHandler ill_handler;
static MonoW32ExceptionHandler segv_handler;
static MonoW32ExceptionHandler term_handler = NULL;

extern gboolean mono_term_signaled;

LPTOP_LEVEL_EXCEPTION_FILTER mono_old_win_toplevel_exception_filter;
void *mono_win_vectored_exception_handle;
Expand Down Expand Up @@ -214,6 +218,31 @@ void win32_seh_cleanup(void)
g_assert (ret);
}

BOOL WINAPI mono_win_ctrl_handler(DWORD fdwCtrlType)
{
switch (fdwCtrlType) {
case CTRL_C_EVENT:
if (term_handler != NULL)
term_handler(0, NULL, NULL);
return TRUE;
break;
case CTRL_CLOSE_EVENT:
return TRUE;
break;
case CTRL_BREAK_EVENT:
return FALSE;
break;
case CTRL_LOGOFF_EVENT:
return FALSE;
break;
case CTRL_SHUTDOWN_EVENT:
return FALSE;
break;
default:
return FALSE;
}
}

void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
{
switch (type) {
Expand All @@ -226,6 +255,11 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
case SIGSEGV:
segv_handler = handler;
break;
case SIGTERM:
term_handler = handler;
if (!SetConsoleCtrlHandler(mono_win_ctrl_handler, TRUE))
fprintf(stderr,"Cannot set control handler\n");
break;
default:
break;
}
Expand Down
31 changes: 31 additions & 0 deletions src/mono/mono/mini/exceptions-x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ static void (*restore_stack) (void *);
static MonoW32ExceptionHandler fpe_handler;
static MonoW32ExceptionHandler ill_handler;
static MonoW32ExceptionHandler segv_handler;
static MonoW32ExceptionHandler term_handler = NULL;

LPTOP_LEVEL_EXCEPTION_FILTER mono_old_win_toplevel_exception_filter;
gpointer mono_win_vectored_exception_handle;
Expand Down Expand Up @@ -260,6 +261,31 @@ void win32_seh_cleanup(void)
RemoveVectoredExceptionHandler (mono_win_vectored_exception_handle);
}

BOOL WINAPI mono_win_ctrl_handler(DWORD fdwCtrlType)
{
switch (fdwCtrlType) {
case CTRL_C_EVENT:
if (term_handler != NULL)
term_handler(0, NULL, NULL);
return TRUE;
break;
case CTRL_CLOSE_EVENT:
return TRUE;
break;
case CTRL_BREAK_EVENT:
return FALSE;
break;
case CTRL_LOGOFF_EVENT:
return FALSE;
break;
case CTRL_SHUTDOWN_EVENT:
return FALSE;
break;
default:
return FALSE;
}
}

void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
{
switch (type) {
Expand All @@ -272,6 +298,11 @@ void win32_seh_set_handler(int type, MonoW32ExceptionHandler handler)
case SIGSEGV:
segv_handler = handler;
break;
case SIGTERM:
term_handler = handler;
if (!SetConsoleCtrlHandler(mono_win_ctrl_handler, TRUE))
Copy link
Member

@kg kg Jun 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds a new handler, so if win32_seh_set_handler was previously called to install a different term_handler, shouldn't we uninstall the old one first?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually, i misread, but i think this would add a copy of our handler each time you set a term handler, so we might end up with 3 copies of the same one installed unless the kernel removes duplicates. the docs don't say whether it does

if an application calls AllocConsole or AttachConsole this handler will get uninstalled, but that's probably fine to consider as a 'don't do that' problem

fprintf(stderr,"Cannot set control handler\n");
break;
default:
break;
}
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/mini/mini-posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ mono_runtime_posix_install_handlers (void)
sigaddset (&signal_set, SIGFPE);
add_signal_handler (SIGQUIT, sigquit_signal_handler, SA_RESTART);
sigaddset (&signal_set, SIGQUIT);
add_signal_handler (SIGTERM, mono_sigterm_signal_handler, SA_RESTART);
sigaddset (&signal_set, SIGTERM);
add_signal_handler (SIGILL, mono_crashing_signal_handler, 0);
sigaddset (&signal_set, SIGILL);
add_signal_handler (SIGBUS, mono_sigsegv_signal_handler, 0);
Expand Down
12 changes: 12 additions & 0 deletions src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const char *mono_build_date;
gboolean mono_do_signal_chaining;
gboolean mono_do_crash_chaining;
int mini_verbose = 0;
gboolean mono_term_signaled = FALSE;

/*
* This flag controls whenever the runtime uses LLVM for JIT compilation, and whenever
Expand Down Expand Up @@ -3758,6 +3759,17 @@ MONO_SIG_HANDLER_FUNC (, mono_crashing_signal_handler)
}
}

MONO_SIG_HANDLER_FUNC (, mono_sigterm_signal_handler)
{
mono_environment_exitcode_set(128+SIGTERM); /* Set default exit code */

mono_term_signaled = TRUE;

mono_gc_finalize_notify ();

mono_chain_signal (MONO_SIG_HANDLER_PARAMS);
}

#if defined(MONO_ARCH_USE_SIGACTION) || defined(HOST_WIN32)

#define HAVE_SIG_INFO
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/mini-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,7 @@ void MONO_SIG_HANDLER_SIGNATURE (mono_sigfpe_signal_handler) ;
void MONO_SIG_HANDLER_SIGNATURE (mono_crashing_signal_handler) ;
void MONO_SIG_HANDLER_SIGNATURE (mono_sigsegv_signal_handler);
void MONO_SIG_HANDLER_SIGNATURE (mono_sigint_signal_handler) ;
void MONO_SIG_HANDLER_SIGNATURE (mono_sigterm_signal_handler) ;
gboolean MONO_SIG_HANDLER_SIGNATURE (mono_chain_signal);

#if defined (HOST_WASM)
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/mini-windows.c
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ mono_runtime_install_handlers (void)
win32_seh_set_handler(SIGFPE, mono_sigfpe_signal_handler);
win32_seh_set_handler(SIGILL, mono_crashing_signal_handler);
win32_seh_set_handler(SIGSEGV, mono_sigsegv_signal_handler);
win32_seh_set_handler(SIGTERM, mono_sigterm_signal_handler);
if (mini_debug_options.handle_sigint)
win32_seh_set_handler(SIGINT, mono_sigint_signal_handler);
#endif
Expand Down