From 6a2c2cf6f3b4f03e18a0118f62f1ebc762ad35a3 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Wed, 29 Oct 2008 12:04:45 +0000 Subject: [PATCH] runsvdir: fx a recent vda's buglet (was pausing even if not signaled). stop spawning children immediately if signaled. Kill one global. --- runit/runsvdir.c | 76 ++++++++++++++++++++++++++---------------------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/runit/runsvdir.c b/runit/runsvdir.c index 29e747fc1..e7f8d5ac9 100644 --- a/runit/runsvdir.c +++ b/runit/runsvdir.c @@ -58,7 +58,6 @@ struct globals { struct pollfd pfd[1]; unsigned stamplog; #endif - smallint need_rescan; /* = 1; */ smallint set_pgrp; }; #define G (*(struct globals*)&bb_common_bufsiz1) @@ -70,10 +69,8 @@ struct globals { #define logpipe (G.logpipe ) #define pfd (G.pfd ) #define stamplog (G.stamplog ) -#define need_rescan (G.need_rescan ) #define set_pgrp (G.set_pgrp ) #define INIT_G() do { \ - need_rescan = 1; \ } while (0) static void fatal2_cannot(const char *m1, const char *m2) @@ -96,21 +93,27 @@ static void warnx(const char *m1) } #endif -static void runsv(int no, const char *name) +/* inlining + vfork -> bigger code */ +static NOINLINE pid_t runsv(const char *name) { - pid_t pid = vfork(); + pid_t pid; + /* If we got signaled, stop spawning children at once! */ + if (bb_got_signal) + return 0; + + pid = vfork(); if (pid == -1) { warn2_cannot("vfork", ""); - return; + return 0; } if (pid == 0) { /* child */ if (set_pgrp) setsid(); /* man execv: - * Signals set to be caught by the calling process image - * shall be set to the default action in the new process image. + * "Signals set to be caught by the calling process image + * shall be set to the default action in the new process image." * Therefore, we do not need this: */ #if 0 bb_signals(0 @@ -121,20 +124,22 @@ static void runsv(int no, const char *name) execlp("runsv", "runsv", name, NULL); fatal2_cannot("start runsv ", name); } - sv[no].pid = pid; + return pid; } -static void do_rescan(void) +/* gcc 4.3.0 does better with NOINLINE */ +static NOINLINE int do_rescan(void) { DIR *dir; direntry *d; int i; struct stat s; + int need_rescan = 0; dir = opendir("."); if (!dir) { warn2_cannot("open directory ", svdir); - return; + return 1; /* need to rescan again soon */ } for (i = 0; i < svnum; i++) sv[i].isgone = 1; @@ -152,47 +157,47 @@ static void do_rescan(void) } if (!S_ISDIR(s.st_mode)) continue; + /* Do we have this service listed already? */ for (i = 0; i < svnum; i++) { if ((sv[i].ino == s.st_ino) #if CHECK_DEVNO_TOO && (sv[i].dev == s.st_dev) #endif ) { - sv[i].isgone = 0; - if (!sv[i].pid) - runsv(i, d->d_name); - break; + if (sv[i].pid == 0) /* restart if it has died */ + goto run_ith_sv; + sv[i].isgone = 0; /* "we still see you" */ + goto next_dentry; } } - if (i == svnum) { - /* new service */ + { /* Not found, make new service */ struct service *svnew = realloc(sv, (i+1) * sizeof(*sv)); if (!svnew) { warn2_cannot("start runsv ", d->d_name); + need_rescan = 1; continue; } sv = svnew; svnum++; - memset(&sv[i], 0, sizeof(sv[i])); - sv[i].ino = s.st_ino; #if CHECK_DEVNO_TOO sv[i].dev = s.st_dev; #endif - /*sv[i].pid = 0;*/ - /*sv[i].isgone = 0;*/ - runsv(i, d->d_name); - need_rescan = 1; + sv[i].ino = s.st_ino; + run_ith_sv: + sv[i].pid = runsv(d->d_name); + sv[i].isgone = 0; } + next_dentry: ; } i = errno; closedir(dir); - if (i) { + if (i) { /* readdir failed */ warn2_cannot("read directory ", svdir); - need_rescan = 1; - return; + return 1; /* need to rescan again soon */ } - /* Send SIGTERM to runsv whose directories were not found (removed) */ + /* Send SIGTERM to runsv whose directories + * were no longer found (-> must have been removed) */ for (i = 0; i < svnum; i++) { if (!sv[i].isgone) continue; @@ -201,8 +206,8 @@ static void do_rescan(void) svnum--; sv[i] = sv[svnum]; i--; /* so that we don't skip new sv[i] (bug was here!) */ - need_rescan = 1; } + return need_rescan; } int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -219,6 +224,7 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) unsigned now; unsigned stampcheck; int i; + int need_rescan = 1; INIT_G(); @@ -284,10 +290,9 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) break; for (i = 0; i < svnum; i++) { if (pid == sv[i].pid) { - /* runsv has gone */ + /* runsv has died */ sv[i].pid = 0; need_rescan = 1; - break; } } } @@ -306,19 +311,20 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) last_mtime = s.st_mtime; last_dev = s.st_dev; last_ino = s.st_ino; - need_rescan = 0; //if (now <= mtime) // sleep(1); - do_rescan(); + need_rescan = do_rescan(); while (fchdir(curdir) == -1) { warn2_cannot("change directory, pausing", ""); sleep(5); } - } else + } else { warn2_cannot("change directory to ", svdir); + } } - } else + } else { warn2_cannot("stat ", svdir); + } } #if ENABLE_FEATURE_RUNSVDIR_LOG @@ -354,6 +360,8 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) } #endif switch (bb_got_signal) { + case 0: /* we are not signaled, business as usual */ + break; case SIGHUP: for (i = 0; i < svnum; i++) if (sv[i].pid)