From 4a8e2aeee74f1c952c52d621ad13c781384a0172 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Bj=C3=B6rn-Egil=20Dahlberg?= <egil@erlang.org>
Date: Tue, 6 Dec 2016 15:01:31 +0100
Subject: erts: Add SIGTERM signal handler

A received SIGTERM signal to beam will generate a {'stop','stop'} message
to the init process and terminate the beam nicely.
---
 erts/emulator/sys/unix/sys.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

(limited to 'erts/emulator/sys/unix')

diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 99e0aea4b5..4362029608 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -409,6 +409,7 @@ erts_sys_pre_init(void)
 #ifdef ERTS_THR_HAVE_SIG_FUNCS
     sigemptyset(&thr_create_sigmask);
     sigaddset(&thr_create_sigmask, SIGINT);   /* block interrupt */
+    sigaddset(&thr_create_sigmask, SIGTERM);  /* block terminate signal */
     sigaddset(&thr_create_sigmask, SIGUSR1);  /* block user defined signal */
 #endif
 
@@ -653,6 +654,40 @@ static RETSIGTYPE request_break(int signum)
 #endif
 }
 
+static void stop_requested(void) {
+    Process* p = NULL;
+    Eterm msg, *hp;
+    ErtsProcLocks locks = 0;
+    ErlOffHeap *ohp;
+    Eterm id = erts_whereis_name_to_id(NULL, am_init);
+
+    if ((p = (erts_pid2proc_opt(NULL, 0, id, 0, ERTS_P2P_FLG_INC_REFC))) != NULL) {
+        ErtsMessage *msgp = erts_alloc_message_heap(p, &locks, 3, &hp, &ohp);
+
+        /* init ! {stop,stop} */
+        msg = TUPLE2(hp, am_stop, am_stop);
+        erts_queue_message(p, locks, msgp, msg, am_system);
+
+        if (locks)
+            erts_smp_proc_unlock(p, locks);
+        erts_proc_dec_refc(p);
+    }
+}
+
+#if (defined(SIG_SIGSET) || defined(SIG_SIGNAL))
+static RETSIGTYPE request_stop(void)
+#else
+static RETSIGTYPE request_stop(int signum)
+#endif
+{
+#ifdef ERTS_SMP
+    smp_sig_notify('S');
+#else
+    stop_requested();
+#endif
+}
+
+
 static ERTS_INLINE void
 sigusr1_exit(void)
 {
@@ -749,6 +784,7 @@ static RETSIGTYPE do_quit(int signum)
 /* Disable break */
 void erts_set_ignore_break(void) {
     sys_signal(SIGINT,  SIG_IGN);
+    sys_signal(SIGTERM, SIG_IGN);
     sys_signal(SIGQUIT, SIG_IGN);
     sys_signal(SIGTSTP, SIG_IGN);
 }
@@ -774,6 +810,7 @@ void erts_replace_intr(void) {
 void init_break_handler(void)
 {
    sys_signal(SIGINT, request_break);
+   sys_signal(SIGTERM, request_stop);
 #ifndef ETHR_UNUSABLE_SIGUSRX
    sys_signal(SIGUSR1, user_signal1);
 #endif /* #ifndef ETHR_UNUSABLE_SIGUSRX */
@@ -1287,6 +1324,9 @@ signal_dispatcher_thread_func(void *unused)
 	    switch (buf[i]) {
 	    case 0: /* Emulator initialized */
                 break;
+	    case 'S': /* SIGTERM */
+		stop_requested();
+		break;
 	    case 'I': /* SIGINT */
 		break_requested();
 		break;
-- 
cgit v1.2.3