diff --git a/docs/config.md b/docs/config.md index 32076165..427c2a38 100644 --- a/docs/config.md +++ b/docs/config.md @@ -236,7 +236,9 @@ Syntax allow the process to shut down gracefully. If the process has not been collected within 3 seconds, Finit sends `SIGKILL`. To halt the process using a different signal, use the option `halt:SIGNAL`, e.g., - `halt:SIGPWR`. + `halt:SIGPWR`. To change the delay between your halt signal and KILL, + use the option `kill:SEC`, e.g., `kill:10` to wait 10 seconds before + sending `SIGKILL`. * `inetd service/proto[@iflist] [LVLS] /path/to/daemon args` Launch a daemon when a client initiates a connection on an Internet diff --git a/src/service.c b/src/service.c index 1331f8ee..6ab801eb 100644 --- a/src/service.c +++ b/src/service.c @@ -656,6 +656,21 @@ static void parse_sighalt(svc_t *svc, char *arg) svc->sighalt = signo; } +static void parse_killdelay(svc_t *svc, char *delay) +{ + const char *errstr; + long long sec; + + sec = strtonum(delay, 1, 60, &errstr); + if (errstr) { + _e("%s: killdelay %s is %s (1-60)", svc->cmd, delay, errstr); + return; + } + + /* convert to msec */ + svc->killdelay = (int)(sec * 1000); +} + /* * name: */ @@ -769,7 +784,7 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) char *username = NULL, *log = NULL, *pid = NULL; char *service = NULL, *proto = NULL, *ifaces = NULL; char *cmd, *desc, *runlevels = NULL, *cond = NULL; - char *name = NULL, *halt = NULL; + char *name = NULL, *halt = NULL, *delay = NULL; svc_t *svc; plugin_t *plugin = NULL; @@ -833,6 +848,8 @@ int service_register(int type, char *cfg, struct rlimit rlimit[], char *file) manual = 1; else if (!strncasecmp(cmd, "halt:", 5)) halt = &cmd[5]; + else if (!strncasecmp(cmd, "kill:", 5)) + delay = &cmd[5]; else if (cmd[0] != '/' && strchr(cmd, '/')) service = cmd; /* inetd service/proto */ else @@ -961,6 +978,8 @@ recreate: parse_name(svc, name); if (halt) parse_sighalt(svc, halt); + if (delay) + parse_killdelay(svc, delay); if (log) parse_log(svc, log); if (desc) @@ -1149,8 +1168,10 @@ static void svc_set_state(svc_t *svc, svc_state_t new) /* if PID isn't collected within SVC_TERM_TIMEOUT msec, kill it! */ if ((*state == SVC_STOPPING_STATE) && !svc_is_inetd(svc)) { + _d("%s is stopping, wait %d sec before sending SIGKILL ...", + svc->cmd, svc->killdelay / 1000); service_timeout_cancel(svc); - service_timeout_after(svc, SVC_TERM_TIMEOUT, service_kill); + service_timeout_after(svc, svc->killdelay, service_kill); } } @@ -1196,6 +1217,7 @@ restart: case SVC_STOPPING_STATE: if (!svc->pid) { /* PID was collected normally, no need to kill it */ + _d("%s: Stopped normally, no need to send SIGKILL :)", svc->cmd); service_timeout_cancel(svc); switch (svc->type) { diff --git a/src/svc.c b/src/svc.c index 551921fd..04ec3a1d 100644 --- a/src/svc.c +++ b/src/svc.c @@ -107,6 +107,9 @@ svc_t *svc_new(char *cmd, char *id, int type) /* Default HALT signal to send */ svc->sighalt = SIGTERM; + /* Default delay between SIGTERM and SIGKILL */ + svc->killdelay = SVC_TERM_TIMEOUT; + TAILQ_INSERT_TAIL(&svc_list, svc, link); return svc; diff --git a/src/svc.h b/src/svc.h index a1c49ee8..fa922589 100644 --- a/src/svc.h +++ b/src/svc.h @@ -75,7 +75,7 @@ typedef enum { #define MAX_NUM_FDS 64 /* Max number of I/O plugins */ #define MAX_NUM_SVC_ARGS 32 -/* Time after SIGTERM (svc->sighalt) that we SIGKILL stopping processes */ +/* Default kill delay (msec) after SIGTERM (svc->sighalt) that we SIGKILL processes */ #define SVC_TERM_TIMEOUT 3000 /* @@ -96,7 +96,8 @@ typedef struct svc { /* Service details */ int sighalt; /* Signal to stop prorcess, default: SIGTERM */ - pid_t pid; + int killdelay; /* Delay in msec before sending SIGKILL */ + pid_t pid; char pidfile[256]; long start_time; /* Start time, as seconds since boot, from sysinfo() */ int started; /* Set for run/task/sysv to track if started */