]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-event: add helper for exiting event loop on SIGTERM/SIGINT
authorLennart Poettering <lennart@poettering.net>
Wed, 28 Sep 2022 09:42:05 +0000 (11:42 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 30 Sep 2022 12:18:43 +0000 (14:18 +0200)
In many (most?) of our event loops we want to exit once SIGTERM/SIGINT
is seen. Add a common helper for that, that does the right things in a
single call.

man/rules/meson.build
man/sd_event_set_signal_exit.xml [new file with mode: 0644]
src/libsystemd/libsystemd.sym
src/libsystemd/sd-event/sd-event.c
src/systemd/sd-event.h

index 7f4a42b1396ad51c7218e64cb953e30152ffc5db..4a497d59c4baf9da0fcac75b1026a9292b9b5c61 100644 (file)
@@ -583,6 +583,7 @@ manpages = [
   ''],
  ['sd_event_now', '3', [], ''],
  ['sd_event_run', '3', ['sd_event_loop'], ''],
+ ['sd_event_set_signal_exit', '3', [], ''],
  ['sd_event_set_watchdog', '3', ['sd_event_get_watchdog'], ''],
  ['sd_event_source_get_event', '3', [], ''],
  ['sd_event_source_get_pending', '3', [], ''],
diff --git a/man/sd_event_set_signal_exit.xml b/man/sd_event_set_signal_exit.xml
new file mode 100644 (file)
index 0000000..e5e675b
--- /dev/null
@@ -0,0 +1,101 @@
+<?xml version='1.0'?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1-or-later -->
+
+<refentry id="sd_event_set_signal_exit" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+  <refentryinfo>
+    <title>sd_event_set_signal_exit</title>
+    <productname>systemd</productname>
+  </refentryinfo>
+
+  <refmeta>
+    <refentrytitle>sd_event_set_signal_exit</refentrytitle>
+    <manvolnum>3</manvolnum>
+  </refmeta>
+
+  <refnamediv>
+    <refname>sd_event_set_signal_exit</refname>
+
+    <refpurpose>Automatically leave event loop on <constant>SIGINT</constant> and <constant>SIGTERM</constant></refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcsynopsisinfo>#include &lt;systemd/sd-event.h&gt;</funcsynopsisinfo>
+
+      <funcprototype>
+        <funcdef>int <function>sd_event_set_signal_exit</function></funcdef>
+        <paramdef>sd_event *<parameter>event</parameter></paramdef>
+        <paramdef>int b</paramdef>
+      </funcprototype>
+
+    </funcsynopsis>
+  </refsynopsisdiv>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para><function>sd_event_set_signal_exit()</function> may be used to ensure the event loop terminates
+    once a <constant>SIGINT</constant> or <constant>SIGTERM</constant> signal is received. It is a
+    convencience wrapper around invocations of
+    <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    for both signals. The two signals are automatically added to the calling thread's signal mask (if a
+    program is multi-threaded care should be taken to either invoke this function before the first thread is
+    started or to manually block the two signals process-wide first).</para>
+
+    <para>If the parameter <parameter>b</parameter> is specified as true, the event loop will terminate on
+    <constant>SIGINT</constant> and <constant>SIGTERM</constant>. If specified as false, it will no
+    longer. When this functionality is turned off the calling thread's signal mask is restored to match the
+    state before it was turned on, for the two signals. By default the two signals are not handled by the
+    event loop, and Linux' default signal handling for them is in effect.</para>
+
+    <para>It's customary for UNIX programs to exit on either of these two signals, hence it's typically a
+    good idea to enable this functionality for the main event loop of a program.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Return Value</title>
+
+    <para><function>sd_event_set_signal_exit()</function> returns a positive non-zero value when the setting
+    was successfully changed. It returns a zero when the specified setting was already in effect. On failure,
+    it returns a negative errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
+
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>The passed event loop object was invalid.</para></listitem>
+        </varlistentry>
+
+      </variablelist>
+    </refsect2>
+  </refsect1>
+
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
+  <refsect1>
+    <title>See Also</title>
+
+    <para>
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    </para>
+  </refsect1>
+
+</refentry>
index 992a79fcc48c78d4071586f371d334992f4fc548..3b72320f0cde32efafef879c19f604160d7248bb 100644 (file)
@@ -790,6 +790,8 @@ global:
         sd_device_monitor_set_description;
         sd_device_monitor_get_description;
 
+        sd_event_set_signal_exit;
+
         sd_id128_string_equal;
 
         sd_hwdb_new_from_path;
index 890b62b1f962a59d7277a3d7f12ddb9fae3cb079..778070a5fb7896ba6296d894c4f2ac538c2e3ee3 100644 (file)
@@ -153,6 +153,8 @@ struct sd_event {
 
         LIST_HEAD(sd_event_source, sources);
 
+        sd_event_source *sigint_event_source, *sigterm_event_source;
+
         usec_t last_run_usec, last_log_usec;
         unsigned delays[sizeof(usec_t) * 8];
 };
@@ -323,6 +325,9 @@ static sd_event *event_free(sd_event *e) {
 
         assert(e);
 
+        e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source);
+        e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
+
         while ((s = e->sources)) {
                 assert(s->floating);
                 source_disconnect(s);
@@ -4613,3 +4618,55 @@ _public_ int sd_event_source_is_ratelimited(sd_event_source *s) {
 
         return s->ratelimited;
 }
+
+_public_ int sd_event_set_signal_exit(sd_event *e, int b) {
+        bool change = false;
+        int r;
+
+        assert_return(e, -EINVAL);
+
+        if (b) {
+                /* We want to maintain pointers to these event sources, so that we can destroy them when told
+                 * so. But we also don't want them to pin the event loop itself. Hence we mark them as
+                 * floating after creation (and undo this before deleting them again). */
+
+                if (!e->sigint_event_source) {
+                        r = sd_event_add_signal(e, &e->sigint_event_source, SIGINT | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL);
+                        if (r < 0)
+                                return r;
+
+                        assert(sd_event_source_set_floating(e->sigint_event_source, true) >= 0);
+                        change = true;
+                }
+
+                if (!e->sigterm_event_source) {
+                        r = sd_event_add_signal(e, &e->sigterm_event_source, SIGTERM | SD_EVENT_SIGNAL_PROCMASK, NULL, NULL);
+                        if (r < 0) {
+                                if (change) {
+                                        assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0);
+                                        e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
+                                }
+
+                                return r;
+                        }
+
+                        assert(sd_event_source_set_floating(e->sigterm_event_source, true) >= 0);
+                        change = true;
+                }
+
+        } else {
+                if (e->sigint_event_source) {
+                        assert(sd_event_source_set_floating(e->sigint_event_source, false) >= 0);
+                        e->sigint_event_source = sd_event_source_unref(e->sigint_event_source);
+                        change = true;
+                }
+
+                if (e->sigterm_event_source) {
+                        assert(sd_event_source_set_floating(e->sigterm_event_source, false) >= 0);
+                        e->sigterm_event_source = sd_event_source_unref(e->sigterm_event_source);
+                        change = true;
+                }
+        }
+
+        return change;
+}
index d2886b8038505dd639b816172d2b45c77ec0a353..cae4c8672a79a848c6f74b4050ffe20a7b4395ca 100644 (file)
@@ -116,6 +116,7 @@ int sd_event_get_exit_code(sd_event *e, int *code);
 int sd_event_set_watchdog(sd_event *e, int b);
 int sd_event_get_watchdog(sd_event *e);
 int sd_event_get_iteration(sd_event *e, uint64_t *ret);
+int sd_event_set_signal_exit(sd_event *e, int b);
 
 sd_event_source* sd_event_source_ref(sd_event_source *s);
 sd_event_source* sd_event_source_unref(sd_event_source *s);