service descriptions: Implement the stop-timeout setting.
authorDavin McCall <davmac@davmac.org>
Tue, 27 Jun 2017 16:29:11 +0000 (17:29 +0100)
committerDavin McCall <davmac@davmac.org>
Tue, 27 Jun 2017 18:25:11 +0000 (19:25 +0100)
README
doc/manpages/dinit.8
src/load_service.cc
src/service.h

diff --git a/README b/README
index e78d2f91237af8efe2cbaefc01bcc66ecc67b1e5..89925c4e22b0e7f0f2302e355c0b8dbbbeeaa265 100644 (file)
--- a/README
+++ b/README
@@ -181,6 +181,13 @@ restart-limit-count = NNN
        restart over the interval specified by restart-limit-interval (default of
        10 seconds). Specify a value of 0 to disable the restart limit.
 
+stop-timeout = XXX.YYYY
+    Specifies the time in seconds allowed for the service to stop. If the
+    service takes longer than this, its process group is sent a SIGKILL signal
+    which should cause it to terminate immediately. The timeout period begins
+    only when all dependent services have already stopped. The default stop
+    timeout is 10 seconds.
+
 pid-file = (path to file)
    For "bgprocess" type services only; specifies the path of the file where
    daemon will write its process ID before detaching.
index fff23eab4d864ddbcfa0b23029c367ab32f609cb..e54a46a7310facc4474754918b281206d893cc7b 100644 (file)
@@ -146,6 +146,13 @@ Specifies the maximum number of times that a service can automatically restart
 over the interval specified by \fBrestart-limit-interval\fR. Specify a value
 of 0 to disable the restart limit.
 .TP
+\fBstop-timeout\fR = \fIXXX.YYY\fR
+Specifies the time in seconds allowed for the service to stop. If the
+service takes longer than this, its process group is sent a SIGKILL signal
+which should cause it to terminate immediately. The timeout period begins
+only when all dependent services have already stopped. The default
+timeout is 10 seconds. Specify a value of 0 to allow unlimited stop time.
+.TP
 \fBpid-file\fR = \fIpath-to-file\fR
 For \fBbgprocess\fR type services only; specifies the path of the file where
 daemon will write its process ID before detaching. Dinit will read the
index b1f1227468d5e7a27e59483ecedc9adaad371262..9a6b1d28b11939007f1a1df79beed86e9ff7e62a 100644 (file)
@@ -402,6 +402,7 @@ service_record * dirload_service_set::load_service(const char * name)
     timespec restart_interval = { .tv_sec = 10, .tv_nsec = 0 };
     int max_restarts = 3;
     timespec restart_delay = { .tv_sec = 0, .tv_nsec = 200000000 };
+    timespec stop_timeout = { .tv_sec = 10, .tv_nsec = 0 };
     
     string line;
     ifstream service_file;
@@ -562,6 +563,10 @@ service_record * dirload_service_set::load_service(const char * name)
                     string limit_str = read_setting_value(i, end, nullptr);
                     max_restarts = parse_unum_param(limit_str, name, std::numeric_limits<int>::max());
                 }
+                else if (setting == "stop-timeout") {
+                    string stoptimeout_str = read_setting_value(i, end, nullptr);
+                    parse_timespec(stoptimeout_str, name, "stop-timeout", stop_timeout);
+                }
                 else {
                     throw service_description_exc(name, "Unknown setting: " + setting);
                 }
@@ -586,6 +591,7 @@ service_record * dirload_service_set::load_service(const char * name)
                             command_offsets, std::move(depends_on), depends_soft);
                     rvalps->set_restart_interval(restart_interval, max_restarts);
                     rvalps->set_restart_delay(restart_delay);
+                    rvalps->set_stop_timeout(stop_timeout);
                     rval = rvalps;
                 }
                 else if (service_type == service_type::BGPROCESS) {
@@ -594,12 +600,15 @@ service_record * dirload_service_set::load_service(const char * name)
                     rvalps->set_pid_file(std::move(pid_file));
                     rvalps->set_restart_interval(restart_interval, max_restarts);
                     rvalps->set_restart_delay(restart_delay);
+                    rvalps->set_stop_timeout(stop_timeout);
                     rval = rvalps;
                 }
                 else if (service_type == service_type::SCRIPTED) {
-                    rval = new scripted_service(this, string(name), std::move(command),
+                    auto rvalps = new scripted_service(this, string(name), std::move(command),
                             command_offsets, std::move(depends_on), depends_soft);
-                    rval->setStopCommand(stop_command, stop_command_offsets);
+                    rvalps->setStopCommand(stop_command, stop_command_offsets);
+                    rvalps->set_stop_timeout(stop_timeout);
+                    rval = rvalps;
                 }
                 else {
                     rval = new service_record(this, string(name), service_type,
index 3075bb2284771f9172807265fcf5580de43f2e21..b76b1bbc88cc9a0197cb8105fbc548f90e43e836 100644 (file)
@@ -585,8 +585,8 @@ class service_record
 
 class base_process_service;
 
-// A timer for process restarting. Used to ensure a minimum delay between
-// process restarts.
+// A timer for process restarting. Used to ensure a minimum delay between process restarts (and
+// also for timing service stop before the SIGKILL hammer is used).
 class process_restart_timer : public eventloop_t::timer_impl<process_restart_timer>
 {
     public:
@@ -672,6 +672,11 @@ class base_process_service : public service_record
     {
         restart_delay = delay;
     }
+
+    void set_stop_timeout(timespec timeout) noexcept
+    {
+        stop_timeout = timeout;
+    }
 };
 
 class process_service : public base_process_service