1
0
mirror of https://github.com/systemd/systemd.git synced 2025-03-19 22:50:17 +03:00

Merge pull request #22861 from poettering/journald-sigterm

journald: don't let SIGTERM starve indefinitely
This commit is contained in:
Yu Watanabe 2022-03-26 00:27:47 +09:00 committed by GitHub
commit dd2396f20d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 3 deletions

View File

@ -1474,12 +1474,82 @@ static int dispatch_sigusr2(sd_event_source *es, const struct signalfd_siginfo *
}
static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
_cleanup_(sd_event_source_disable_unrefp) sd_event_source *news = NULL;
Server *s = userdata;
int r;
assert(s);
log_received_signal(LOG_INFO, si);
(void) sd_event_source_set_enabled(es, false); /* Make sure this handler is called at most once */
/* So on one hand we want to ensure that SIGTERMs are definitely handled in appropriate, bounded
* time. On the other hand we want that everything pending is first comprehensively processed and
* written to disk. These goals are incompatible, hence we try to find a middle ground: we'll process
* SIGTERM with high priority, but from the handler (this one right here) we'll install two new event
* sources: one low priority idle one that will issue the exit once everything else is processed (and
* which is hopefully the regular, clean codepath); and one high priority timer that acts as safety
* net: if our idle handler isn't run within 10s, we'll exit anyway.
*
* TLDR: we'll exit either when everything is processed, or after 10s max, depending on what happens
* first.
*
* Note that exiting before the idle event is hit doesn't typically mean that we lose any data, as
* messages will remain queued in the sockets they came in from, and thus can be processed when we
* start up next unless we are going down for the final system shutdown, in which case everything
* is lost. */
r = sd_event_add_defer(s->event, &news, NULL, NULL); /* NULL handler means → exit when triggered */
if (r < 0) {
log_error_errno(r, "Failed to allocate exit idle event handler: %m");
goto fail;
}
(void) sd_event_source_set_description(news, "exit-idle");
/* Run everything relevant before this. */
r = sd_event_source_set_priority(news, SD_EVENT_PRIORITY_NORMAL+20);
if (r < 0) {
log_error_errno(r, "Failed to adjust priority of exit idle event handler: %m");
goto fail;
}
/* Give up ownership, so that this event source is freed automatically when the event loop is freed. */
r = sd_event_source_set_floating(news, true);
if (r < 0) {
log_error_errno(r, "Failed to make exit idle event handler floating: %m");
goto fail;
}
news = sd_event_source_unref(news);
r = sd_event_add_time_relative(s->event, &news, CLOCK_MONOTONIC, 10 * USEC_PER_SEC, 0, NULL, NULL);
if (r < 0) {
log_error_errno(r, "Failed to allocate exit timeout event handler: %m");
goto fail;
}
(void) sd_event_source_set_description(news, "exit-timeout");
r = sd_event_source_set_priority(news, SD_EVENT_PRIORITY_IMPORTANT-20); /* This is a safety net, with highest priority */
if (r < 0) {
log_error_errno(r, "Failed to adjust priority of exit timeout event handler: %m");
goto fail;
}
r = sd_event_source_set_floating(news, true);
if (r < 0) {
log_error_errno(r, "Failed to make exit timeout event handler floating: %m");
goto fail;
}
news = sd_event_source_unref(news);
log_debug("Exit event sources are now pending.");
return 0;
fail:
sd_event_exit(s->event, 0);
return 0;
}
@ -1531,8 +1601,8 @@ static int setup_signals(Server *s) {
if (r < 0)
return r;
/* Let's process SIGTERM late, so that we flush all queued messages to disk before we exit */
r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20);
/* Let's process SIGTERM early, so that we definitely react to it */
r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
if (r < 0)
return r;
@ -1542,7 +1612,7 @@ static int setup_signals(Server *s) {
if (r < 0)
return r;
r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_NORMAL+20);
r = sd_event_source_set_priority(s->sigint_event_source, SD_EVENT_PRIORITY_IMPORTANT-10);
if (r < 0)
return r;

View File

@ -1931,11 +1931,18 @@ static int post_change_thunk(sd_event_source *timer, uint64_t usec, void *userda
}
static void schedule_post_change(JournalFile *f) {
sd_event *e;
int r;
assert(f);
assert(f->post_change_timer);
assert_se(e = sd_event_source_get_event(f->post_change_timer));
/* If we are aleady going down, post the change immediately. */
if (IN_SET(sd_event_get_state(e), SD_EVENT_EXITING, SD_EVENT_FINISHED))
goto fail;
r = sd_event_source_get_enabled(f->post_change_timer, NULL);
if (r < 0) {
log_debug_errno(r, "Failed to get ftruncate timer state: %m");