From: Timo Sirainen Date: Thu, 3 Feb 2022 22:14:27 +0000 (+0100) Subject: lib-master: Add master_service_get_kill_time() X-Git-Tag: 2.4.0~4382 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b6473a4367d29eca9f7ff4fa4ae6a12d0f78f137;p=thirdparty%2Fdovecot%2Fcore.git lib-master: Add master_service_get_kill_time() --- diff --git a/src/lib-master/master-service-private.h b/src/lib-master/master-service-private.h index 39065583aa..638eb9800c 100644 --- a/src/lib-master/master-service-private.h +++ b/src/lib-master/master-service-private.h @@ -77,6 +77,7 @@ struct master_service { char *last_kick_signal_user; volatile sig_atomic_t last_kick_signal_user_accessed; volatile sig_atomic_t killed_signal; + volatile struct timeval killed_time; struct stats_client *stats_client; struct master_service_haproxy_conn *haproxy_conns; diff --git a/src/lib-master/master-service.c b/src/lib-master/master-service.c index 2202eec918..6650e4a1a1 100644 --- a/src/lib-master/master-service.c +++ b/src/lib-master/master-service.c @@ -231,14 +231,38 @@ static bool sig_term_try_kick(struct master_service *service) return TRUE; } +static void sig_die_delayed(struct master_service *service, const siginfo_t *si) +{ + /* WARNING: We are in a (non-delayed) signal handler context. + Be VERY careful what functions you call. */ + if (service->killed_time.tv_sec == 0) { +#ifdef HAVE_CLOCK_GETTIME + struct timespec ts; + if (clock_gettime(CLOCK_REALTIME, &ts) < 0) { + lib_signals_syscall_error("clock_gettime() failed: "); + service->killed_time.tv_sec = time(NULL); + service->killed_time.tv_usec = 0; + } else { + service->killed_time.tv_sec = ts.tv_sec; + service->killed_time.tv_usec = ts.tv_nsec/1000; + } +#else + service->killed_time.tv_sec = time(NULL); + service->killed_time.tv_usec = 0; +#endif + } + /* set killed_signal after killed_time */ + service->killed_signal = si->si_signo; + lib_signal_delayed(si); +} + static void sig_standalone_die(const siginfo_t *si, void *context) { /* WARNING: We are in a (non-delayed) signal handler context. Be VERY careful what functions you call. */ struct master_service *service = context; - service->killed_signal = si->si_signo; - lib_signal_delayed(si); + sig_die_delayed(service, si); } static void sig_term(const siginfo_t *si, void *context) @@ -263,10 +287,8 @@ static void sig_term(const siginfo_t *si, void *context) lib_signals_syscall_error("SIGTERM: sigprocmask(SIG_SETMASK) failed: "); } - if (call_delayed) { - service->killed_signal = si->si_signo; - lib_signal_delayed(si); - } + if (call_delayed) + sig_die_delayed(service, si); errno = saved_errno; } @@ -1106,6 +1128,21 @@ int master_service_get_kill_signal(struct master_service *service) return service->killed_signal; } +void master_service_get_kill_time(struct master_service *service, + struct timeval *tv_r) +{ + /* block the signal to avoid races accessing killed_time */ + sigset_t oldmask; + bool sigterm_blocked = block_sigterm(&oldmask) == 0; + + *tv_r = service->killed_time; + + if (sigterm_blocked) { + if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) + i_error("sigprocmask(SIG_SETMASK) failed: %m"); + } +} + bool master_service_is_master_stopped(struct master_service *service) { return service->io_status_error == NULL && diff --git a/src/lib-master/master-service.h b/src/lib-master/master-service.h index 35aa0345d9..ee22430480 100644 --- a/src/lib-master/master-service.h +++ b/src/lib-master/master-service.h @@ -235,6 +235,9 @@ void master_service_stop_new_connections(struct master_service *service); bool master_service_is_killed(struct master_service *service); /* Returns the signal that caused service to stop. */ int master_service_get_kill_signal(struct master_service *service); +/* Returns the timestamp when the stop signal was received. */ +void master_service_get_kill_time(struct master_service *service, + struct timeval *tv_r); /* Returns TRUE if our master process is already stopped. This process may or may not be dying itself. Returns FALSE always if the process was started standalone. */