summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorGuillem Jover <guillem@debian.org>2010-10-31 21:30:49 +0100
committerGuillem Jover <guillem@debian.org>2010-11-19 05:21:14 +0100
commit9209010455812b6e51cd907aab3d50779ea8e35b (patch)
treeaf60a4300b6e7560d044b3d94fb4f0a7dc228fca /utils
parent141b8a46fae0a80313ca1968f55f45124ce70428 (diff)
downloaddpkg-9209010455812b6e51cd907aab3d50779ea8e35b.tar.gz
s-s-d: Refactor sched_timeout code out into new do_stop_timeout()
Diffstat (limited to 'utils')
-rw-r--r--utils/start-stop-daemon.c132
1 files changed, 71 insertions, 61 deletions
diff --git a/utils/start-stop-daemon.c b/utils/start-stop-daemon.c
index 547c1c04c..899b39316 100644
--- a/utils/start-stop-daemon.c
+++ b/utils/start-stop-daemon.c
@@ -1324,12 +1324,77 @@ set_what_stop(const char *str)
what_stop[sizeof(what_stop) - 1] = '\0';
}
+/*
+ * We want to keep polling for the processes, to see if they've exited, or
+ * until the timeout expires.
+ *
+ * This is a somewhat complicated algorithm to try to ensure that we notice
+ * reasonably quickly when all the processes have exited, but don't spend
+ * too much CPU time polling. In particular, on a fast machine with
+ * quick-exiting daemons we don't want to delay system shutdown too much,
+ * whereas on a slow one, or where processes are taking some time to exit,
+ * we want to increase the polling interval.
+ *
+ * The algorithm is as follows: we measure the elapsed time it takes to do
+ * one poll(), and wait a multiple of this time for the next poll. However,
+ * if that would put us past the end of the timeout period we wait only as
+ * long as the timeout period, but in any case we always wait at least
+ * MIN_POLL_INTERVAL (20ms). The multiple (‘ratio’) starts out as 2, and
+ * increases by 1 for each poll to a maximum of 10; so we use up to between
+ * 30% and 10% of the machine's resources (assuming a few reasonable things
+ * about system performance).
+ */
+static bool
+do_stop_timeout(int timeout, int *n_killed, int *n_notkilled)
+{
+ struct timeval stopat, before, after, interval, maxinterval;
+ int r, ratio;
+
+ xgettimeofday(&stopat);
+ stopat.tv_sec += timeout;
+ ratio = 1;
+ for (;;) {
+ xgettimeofday(&before);
+ if (timercmp(&before, &stopat, >))
+ return false;
+
+ do_stop(0, 1, n_killed, n_notkilled, 0);
+ if (!*n_killed)
+ return true;
+
+ xgettimeofday(&after);
+
+ if (!timercmp(&after, &stopat, <))
+ return false;
+
+ if (ratio < 10)
+ ratio++;
+
+ timersub(&stopat, &after, &maxinterval);
+ timersub(&after, &before, &interval);
+ tmul(&interval, ratio);
+
+ if (interval.tv_sec < 0 || interval.tv_usec < 0)
+ interval.tv_sec = interval.tv_usec = 0;
+
+ if (timercmp(&interval, &maxinterval, >))
+ interval = maxinterval;
+
+ if (interval.tv_sec == 0 &&
+ interval.tv_usec <= MIN_POLL_INTERVAL)
+ interval.tv_usec = MIN_POLL_INTERVAL;
+
+ r = select(0, NULL, NULL, NULL, &interval);
+ if (r < 0 && errno != EINTR)
+ fatal("select() failed for pause");
+ }
+}
+
static int
run_stop_schedule(void)
{
- int r, position, n_killed, n_notkilled, value, ratio, retry_nr;
+ int position, n_killed, n_notkilled, value, retry_nr;
bool anykilled;
- struct timeval stopat, before, after, interval, maxinterval;
if (testmode) {
if (schedule != NULL) {
@@ -1378,65 +1443,10 @@ run_stop_schedule(void)
anykilled = true;
goto next_item;
case sched_timeout:
- /* We want to keep polling for the processes, to see if they've exited,
- * or until the timeout expires.
- *
- * This is a somewhat complicated algorithm to try to ensure that we
- * notice reasonably quickly when all the processes have exited, but
- * don't spend too much CPU time polling. In particular, on a fast
- * machine with quick-exiting daemons we don't want to delay system
- * shutdown too much, whereas on a slow one, or where processes are
- * taking some time to exit, we want to increase the polling
- * interval.
- *
- * The algorithm is as follows: we measure the elapsed time it takes
- * to do one poll(), and wait a multiple of this time for the next
- * poll. However, if that would put us past the end of the timeout
- * period we wait only as long as the timeout period, but in any case
- * we always wait at least MIN_POLL_INTERVAL (20ms). The multiple
- * (‘ratio’) starts out as 2, and increases by 1 for each poll to a
- * maximum of 10; so we use up to between 30% and 10% of the
- * machine's resources (assuming a few reasonable things about system
- * performance).
- */
- xgettimeofday(&stopat);
- stopat.tv_sec += value;
- ratio = 1;
- for (;;) {
- xgettimeofday(&before);
- if (timercmp(&before, &stopat, >))
- goto next_item;
-
- do_stop(0, 1, &n_killed, &n_notkilled, 0);
- if (!n_killed)
- goto x_finished;
-
- xgettimeofday(&after);
-
- if (!timercmp(&after, &stopat, <))
- goto next_item;
-
- if (ratio < 10)
- ratio++;
-
- timersub(&stopat, &after, &maxinterval);
- timersub(&after, &before, &interval);
- tmul(&interval, ratio);
-
- if (interval.tv_sec < 0 || interval.tv_usec < 0)
- interval.tv_sec = interval.tv_usec = 0;
-
- if (timercmp(&interval, &maxinterval, >))
- interval = maxinterval;
-
- if (interval.tv_sec == 0 &&
- interval.tv_usec <= MIN_POLL_INTERVAL)
- interval.tv_usec = MIN_POLL_INTERVAL;
-
- r = select(0, NULL, NULL, NULL, &interval);
- if (r < 0 && errno != EINTR)
- fatal("select() failed for pause");
- }
+ if (do_stop_timeout(value, &n_killed, &n_notkilled))
+ goto x_finished;
+ else
+ goto next_item;
default:
assert(!"schedule[].type value must be valid");
}