]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-master: Add master_service_get_kill_time()
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 3 Feb 2022 22:14:27 +0000 (23:14 +0100)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Tue, 22 Feb 2022 09:28:55 +0000 (09:28 +0000)
src/lib-master/master-service-private.h
src/lib-master/master-service.c
src/lib-master/master-service.h

index 39065583aa7f5bdf0de73e00e8fd18e6ca7d9add..638eb9800c0100179da8b81e1525f8b15f803d06 100644 (file)
@@ -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;
index 2202eec9181a04809c4790a88f6e71d8b24fc69f..6650e4a1a1b209534b01e9f551e9a95729c12d6f 100644 (file)
@@ -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 &&
index 35aa0345d9e50e8fc6a836e3bb6974b015d5f242..ee22430480f565b0ddf46d5b2e2822323620327e 100644 (file)
@@ -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. */