]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
shared: add a common SIGRTMIN-18 handler
authorLennart Poettering <lennart@poettering.net>
Tue, 14 Feb 2023 15:37:05 +0000 (16:37 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 1 Mar 2023 08:43:23 +0000 (09:43 +0100)
src/shared/common-signal.c [new file with mode: 0644]
src/shared/common-signal.h [new file with mode: 0644]
src/shared/meson.build

diff --git a/src/shared/common-signal.c b/src/shared/common-signal.c
new file mode 100644 (file)
index 0000000..1896443
--- /dev/null
@@ -0,0 +1,94 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "common-signal.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "process-util.h"
+#include "signal-util.h"
+
+int sigrtmin18_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
+        struct sigrtmin18_info *info = userdata;
+        _cleanup_free_ char *comm = NULL;
+        int r;
+
+        assert(s);
+        assert(si);
+
+        (void) get_process_comm(si->ssi_pid, &comm);
+
+        if (si->ssi_code != SI_QUEUE) {
+                log_notice("Received control signal %s from process " PID_FMT " (%s) without command value, ignoring.",
+                           signal_to_string(si->ssi_signo),
+                           (pid_t) si->ssi_pid,
+                           strna(comm));
+                return 0;
+        }
+
+        log_debug("Received control signal %s from process " PID_FMT " (%s) with command 0x%08x.",
+                  signal_to_string(si->ssi_signo),
+                  (pid_t) si->ssi_pid,
+                  strna(comm),
+                  (unsigned) si->ssi_int);
+
+        switch (si->ssi_int) {
+
+        case _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE..._COMMON_SIGNAL_COMMAND_LOG_LEVEL_END:
+                log_set_max_level(si->ssi_int - _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE);
+                break;
+
+        case COMMON_SIGNAL_COMMAND_CONSOLE:
+                log_set_target_and_open(LOG_TARGET_CONSOLE);
+                break;
+        case COMMON_SIGNAL_COMMAND_JOURNAL:
+                log_set_target_and_open(LOG_TARGET_JOURNAL);
+                break;
+        case COMMON_SIGNAL_COMMAND_KMSG:
+                log_set_target_and_open(LOG_TARGET_KMSG);
+                break;
+        case COMMON_SIGNAL_COMMAND_NULL:
+                log_set_target_and_open(LOG_TARGET_NULL);
+                break;
+
+        case COMMON_SIGNAL_COMMAND_MEMORY_PRESSURE:
+                if (info && info->memory_pressure_handler)
+                        return info->memory_pressure_handler(s, info->memory_pressure_userdata);
+
+                sd_event_trim_memory();
+                break;
+
+        case COMMON_SIGNAL_COMMAND_MALLOC_INFO: {
+                _cleanup_free_ char *data = NULL;
+                _cleanup_fclose_ FILE *f = NULL;
+                size_t sz;
+
+                f = open_memstream_unlocked(&data, &sz);
+                if (!f) {
+                        log_oom();
+                        break;
+                }
+
+                if (malloc_info(0, f) < 0) {
+                        log_error_errno(errno, "Failed to invoke malloc_info(): %m");
+                        break;
+                }
+
+                fputc(0, f);
+
+                r = fflush_and_check(f);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to flush malloc_info() buffer: %m");
+                        break;
+                }
+
+                log_dump(LOG_INFO, data);
+                break;
+        }
+
+        default:
+                log_notice("Received control signal %s with unknown command 0x%08x, ignoring.",
+                           signal_to_string(si->ssi_signo), (unsigned) si->ssi_int);
+                break;
+        }
+
+        return 0;
+}
diff --git a/src/shared/common-signal.h b/src/shared/common-signal.h
new file mode 100644 (file)
index 0000000..7d2ab28
--- /dev/null
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <syslog.h>
+
+#include <sd-event.h>
+
+/* All our long-running services should implement a SIGRTMIN+18 handler that can be used to trigger certain
+ * actions that affect service runtime. The specific action is indicated via the "value integer" you can pass
+ * along realtime signals. This is mostly intended for debugging purposes and is entirely asynchronous in
+ * nature. Specifically, these are the commands:
+ *
+ * Currently available operations:
+ *
+ *         • Change maximum log level
+ *         • Change log target
+ *         • Invoke memory trimming, like under memory pressure
+ *         • Write glibc malloc() allocation info to logs
+ *
+ * How to use this? Via a command like the following:
+ *
+ *         /usr/bin/kill -s RTMIN+18 -q 768 1
+ *
+ *         (This will tell PID 1 to trim its memory use.)
+ *
+ * or:
+ *
+ *         systemctl kill --kill-value=0x300 -s RTMIN+18 systemd-journald
+ *
+ *         (This will tell journald to trim its memory use.)
+ */
+
+enum {
+        _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE = 0x100,
+        COMMON_SIGNAL_COMMAND_LOG_EMERG       = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_EMERG,
+        COMMON_SIGNAL_COMMAND_LOG_ALERT       = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_ALERT,
+        COMMON_SIGNAL_COMMAND_LOG_CRIT        = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_CRIT,
+        COMMON_SIGNAL_COMMAND_LOG_ERR         = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_ERR,
+        COMMON_SIGNAL_COMMAND_LOG_WARNING     = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_WARNING,
+        COMMON_SIGNAL_COMMAND_LOG_NOTICE      = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_NOTICE,
+        COMMON_SIGNAL_COMMAND_LOG_INFO        = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_INFO,
+        COMMON_SIGNAL_COMMAND_LOG_DEBUG       = _COMMON_SIGNAL_COMMAND_LOG_LEVEL_BASE + LOG_DEBUG,
+        _COMMON_SIGNAL_COMMAND_LOG_LEVEL_END  = COMMON_SIGNAL_COMMAND_LOG_DEBUG,
+
+        COMMON_SIGNAL_COMMAND_CONSOLE         = 0x200,
+        COMMON_SIGNAL_COMMAND_JOURNAL,
+        COMMON_SIGNAL_COMMAND_KMSG,
+        COMMON_SIGNAL_COMMAND_NULL,
+
+        COMMON_SIGNAL_COMMAND_MEMORY_PRESSURE = 0x300,
+        COMMON_SIGNAL_COMMAND_MALLOC_INFO,
+};
+
+struct sigrtmin18_info {
+        sd_event_handler_t memory_pressure_handler;
+        void *memory_pressure_userdata;
+};
+
+int sigrtmin18_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
index d8a688b2754a822ff0410a0b06b0924e0eaba49b..82fd206d69280dcad571150516079f1242c31eab 100644 (file)
@@ -35,6 +35,7 @@ shared_sources = files(
         'chown-recursive.c',
         'clean-ipc.c',
         'clock-util.c',
+        'common-signal.c',
         'compare-operator.c',
         'condition.c',
         'conf-parser.c',