diff --git a/man/rules/meson.build b/man/rules/meson.build index 7f4a42b139..4a497d59c4 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -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 index 0000000000..e5e675beec --- /dev/null +++ b/man/sd_event_set_signal_exit.xml @@ -0,0 +1,101 @@ + + + + + + + + sd_event_set_signal_exit + systemd + + + + sd_event_set_signal_exit + 3 + + + + sd_event_set_signal_exit + + Automatically leave event loop on SIGINT and SIGTERM + + + + + #include <systemd/sd-event.h> + + + int sd_event_set_signal_exit + sd_event *event + int b + + + + + + + Description + + sd_event_set_signal_exit() may be used to ensure the event loop terminates + once a SIGINT or SIGTERM signal is received. It is a + convencience wrapper around invocations of + sd_event_add_signal3 + 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). + + If the parameter b is specified as true, the event loop will terminate on + SIGINT and SIGTERM. 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. + + 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. + + + + Return Value + + sd_event_set_signal_exit() 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. + + + Errors + + Returned errors may indicate the following problems: + + + + + -ECHILD + + The event loop has been created in a different process. + + + + -EINVAL + + The passed event loop object was invalid. + + + + + + + + + + See Also + + + systemd1, + sd-event3, + sd_event_new3, + sd_event_add_signal3 + + + + diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 992a79fcc4..3b72320f0c 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -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; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 890b62b1f9..778070a5fb 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -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; +} diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index d2886b8038..cae4c8672a 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -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);