aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2008-11-21 16:26:19 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2008-11-21 16:26:19 +0000
commitf4625d1d73214d46e3594b28247ea7d26411aca7 (patch)
tree56923058a8b9d7d313dea27a83d9b965508d08d9
parentab854f93828c3c2f9797e3d458ec7a6f2b0961ec (diff)
downloadpies-f4625d1d73214d46e3594b28247ea7d26411aca7.tar.gz
pies-f4625d1d73214d46e3594b28247ea7d26411aca7.tar.bz2
Pies: ensure all prereqs are started in right order before starting a dependency.
* pies/pies.c (component_cfg_param): New statement settle-timeout. * pies/progman.c (recompute_alarm): New static; (prog_start): Start the component only if all of its prerequisites are running. (progman_recompute_alarm): New function. (progman_start): Reset recompute_alarm to 0. (check_stopping): New function. (progman_wake_sleeping): Handle also status_stopping and status_enabled. Recompute alarm before leaving. (prog_start_prerequisites): Return 0 or 1 depending on whether all prerequisites have been started. (prog_stop): Raise recompute_alarm for stopping components. (progman_cleanup): Force status_enabled before attepmting to start a component. (progman_cleanup): Add a \n after debugging message. Run progman_wake_sleeping unlsess expect_term is set. * pies/meta1gram.y (translate_node_list): Force settle-timeout = 1. * pies/pies.h (struct component.settle_timeout): New member.
-rw-r--r--pies/meta1gram.y3
-rw-r--r--pies/pies.c3
-rw-r--r--pies/pies.h35
-rw-r--r--pies/progman.c208
4 files changed, 186 insertions, 63 deletions
diff --git a/pies/meta1gram.y b/pies/meta1gram.y
index 334cb61..7ab93a7 100644
--- a/pies/meta1gram.y
+++ b/pies/meta1gram.y
@@ -415,6 +415,9 @@ translate_node_list (mu_cfg_node_t *src, const char *name)
tail->next = node;
tail = node;
+ node = create_string_node ("settle-timeout", "1", locus);
+ tail->next = node;
+ tail = node;
}
return head;
}
diff --git a/pies/pies.c b/pies/pies.c
index f39f1d4..836ea9c 100644
--- a/pies/pies.c
+++ b/pies/pies.c
@@ -598,6 +598,9 @@ struct mu_cfg_param component_cfg_param[] = {
{ "disable", mu_cfg_bool, NULL,
mu_offsetof (struct component, disabled), NULL,
N_("Disable this entry.") },
+ { "settle-timeout", mu_cfg_uint, NULL,
+ mu_offsetof (struct component, settle_timeout), NULL,
+ N_("Time to wait before starting this component.") },
{ "precious", mu_cfg_bool, NULL,
mu_offsetof (struct component, precious), NULL,
N_("Mark this entry as precious.") },
diff --git a/pies/pies.h b/pies/pies.h
index 1b6f07e..2591ea0 100644
--- a/pies/pies.h
+++ b/pies/pies.h
@@ -111,22 +111,25 @@ enum pies_comp_mode
struct component
{
enum pies_comp_mode mode;
- char *tag; /* Entry tag (for diagnostics purposes) */
- char *program; /* Program name */
- char **argv; /* Program command line */
- char **env; /* Program environment */
- char *dir; /* Working directory */
- mu_list_t prereq; /* Prerequisites */
- mu_list_t depend; /* Dependency targets */
- /* FIXME: disabled and precios can be encoded as bits in mode */
- int disabled; /* The componenet is disabled */
- int precious; /* The component is precious (cannot be disabled) */
- char *rmfile; /* Try to remove this file before starting */
- struct mf_privs privs; /* UID/GIDS+groups to run under */
- mode_t umask; /* Umask to install before starting */
- limits_record_t limits;/* System limits */
- mu_url_t socket_url; /* Socket to listen on (if mode != pies_comp_exec) */
- char *pass_fd_socket; /* Socket to pass fd on
+ char *tag; /* Entry tag (for diagnostics purposes) */
+ char *program; /* Program name */
+ char **argv; /* Program command line */
+ char **env; /* Program environment */
+ char *dir; /* Working directory */
+ mu_list_t prereq; /* Prerequisites */
+ mu_list_t depend; /* Dependency targets */
+ unsigned settle_timeout; /* Time needed for started prerequisites to
+ settle */
+ /* FIXME: disabled and precious can be encoded as bits in mode */
+ int disabled; /* The componenet is disabled */
+ int precious; /* The component is precious (cannot be disabled) */
+ char *rmfile; /* Try to remove this file before starting */
+ struct mf_privs privs; /* UID/GIDS+groups to run under */
+ mode_t umask; /* Umask to install before starting */
+ limits_record_t limits; /* System limits */
+ mu_url_t socket_url; /* Socket to listen on
+ (if mode != pies_comp_exec) */
+ char *pass_fd_socket; /* Socket to pass fd on
(if mode == pies_comp_pass_fd) */
mu_acl_t acl;
/* Retranslators: */
diff --git a/pies/progman.c b/pies/progman.c
index 29db153..9a5b0c5 100644
--- a/pies/progman.c
+++ b/pies/progman.c
@@ -64,6 +64,7 @@ struct prog
static int numprog;
static struct prog *proghead, *progtail;
static pies_depmap_t depmap;
+static int recompute_alarm;
static struct prog *
prog_lookup_by_pid (pid_t pid)
@@ -118,7 +119,7 @@ prog_lookup_by_idx (unsigned idx)
}
static void prog_stop (struct prog *prog, int sig);
-void prog_start_prerequisites (struct prog *prog);
+static int prog_start_prerequisites (struct prog *prog);
void
link_prog (struct prog *pp, int prepend)
@@ -573,6 +574,38 @@ prog_start (struct prog *prog)
if (prog->pid > 0 || !IS_PROG (prog))
return;
+
+ /* This call returns 1 in two cases: Either prog is marked as disabled,
+ in which case there's nothing more to do, or one or more of its
+ prerequisites are in status_stopping. In the latter case either the
+ components in question will exit or a SIGALRM will get delivered. In
+ both cases, it will cause further processing of `prog'. */
+ if (prog_start_prerequisites (prog))
+ return;
+
+ time (&now);
+
+ if (prog->v.p.timestamp + TESTTIME > now)
+ prog->v.p.count++;
+ else
+ {
+ prog->v.p.count = 0;
+ prog->v.p.timestamp = now;
+ }
+
+ if (prog->v.p.count > MAXSPAWN)
+ {
+ mu_error (ngettext (
+ "%s is respawning too fast, disabled for %d minute",
+ "%s is respawning too fast, disabled for %d minutes",
+ SLEEPTIME / 60),
+ prog->tag, SLEEPTIME / 60);
+ prog->v.p.timestamp = now;
+ prog->v.p.status = status_sleeping;
+ recompute_alarm = 1;
+ return;
+ }
+
switch (prog->v.p.comp->mode)
{
case pies_comp_exec:
@@ -602,6 +635,7 @@ prog_start (struct prog *prog)
{
mu_error ("listen: %s", mu_strerror (errno));
close (prog->v.p.socket);
+ prog->v.p.socket = -1;
prog->v.p.status = status_disabled;
return;
}
@@ -613,38 +647,6 @@ prog_start (struct prog *prog)
return;
}
- time (&now);
-
- if (prog->v.p.timestamp + TESTTIME > now)
- prog->v.p.count++;
- else
- {
- prog->v.p.count = 0;
- prog->v.p.timestamp = now;
- }
-
- if (prog->v.p.count > MAXSPAWN)
- {
- int old_alarm;
-
- mu_error (ngettext (
- "%s is respawning too fast, disabled for %d minute",
- "%s is respawning too fast, disabled for %d minutes",
- SLEEPTIME / 60),
- prog->tag, SLEEPTIME / 60);
- prog->v.p.timestamp = now;
- prog->v.p.status = status_sleeping;
-
- old_alarm = alarm (0);
- if (old_alarm > SLEEPTIME || old_alarm <= 0)
- old_alarm = SLEEPTIME;
- alarm (old_alarm);
- return;
- }
-
- prog_start_prerequisites (prog);
- if (prog->v.p.status == status_disabled)
- return; /* FIXME: other statuses */
MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, _("starting %s\n"), prog->tag);
if (prog->v.p.comp->rmfile)
@@ -721,6 +723,7 @@ prog_start (struct prog *prog)
dup2 (prog->v.p.socket, 0);
dup2 (prog->v.p.socket, 1);
close (prog->v.p.socket);
+ prog->v.p.socket = -1;
break;
}
@@ -1058,10 +1061,49 @@ progman_create_sockets ()
void
+progman_recompute_alarm ()
+{
+ struct prog *prog;
+ time_t now = time (NULL);
+ time_t alarm_time = 0, x;
+
+ recompute_alarm = 0;
+ MU_DEBUG (pies_debug, MU_DEBUG_TRACE2, "Recomputing alarm settings\n");
+ for (prog = proghead; prog; prog = prog->next)
+ if (IS_PROG (prog))
+ {
+ switch (prog->v.p.status)
+ {
+ case status_sleeping:
+ x = SLEEPTIME - (now - prog->v.p.timestamp);
+ if (alarm_time == 0 || x < alarm_time)
+ alarm_time = x;
+ break;
+
+ case status_stopping:
+ x = shutdown_timeout - (now - prog->v.p.timestamp);
+ if (alarm_time == 0 || x < alarm_time)
+ alarm_time = x;
+ break;
+
+ default:
+ break;
+ }
+ }
+ MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "alarm=%lu\n",
+ (unsigned long)alarm_time);
+ if (alarm_time)
+ alarm (alarm_time);
+}
+
+
+
+void
progman_start ()
{
struct prog *prog;
+ recompute_alarm = 0;
MU_DEBUG (pies_debug, MU_DEBUG_TRACE1, "Starting components\n");
for (prog = proghead; prog; prog = prog->next)
if (IS_PROG (prog)
@@ -1070,30 +1112,74 @@ progman_start ()
prog_start (prog);
}
+static void
+check_stopping (struct prog *prog, time_t now)
+{
+ if (now - prog->v.p.timestamp >= shutdown_timeout)
+ {
+ if (prog->pid == 0)
+ mu_error (_("INTERNAL ERROR: attempting to kill unexisting process %s"),
+ prog->tag);
+ else
+ kill (prog->pid, SIGKILL);
+ }
+ else
+ recompute_alarm = 1;
+}
+
void
progman_wake_sleeping ()
{
struct prog *prog;
+ time_t now = time (NULL);
+
+ MU_DEBUG (pies_debug, MU_DEBUG_TRACE1,
+ "Managing sleeping/stopping components\n");
for (prog = proghead; prog; prog = prog->next)
- if (IS_PROG (prog) && prog->v.p.status == status_sleeping)
+ if (IS_PROG (prog))
{
- prog->v.p.status = status_enabled;
- prog->v.p.count = 0;
- prog->v.p.timestamp = 0;
- prog_start (prog);
+ switch (prog->v.p.status)
+ {
+ case status_sleeping:
+ if (now - prog->v.p.timestamp >= SLEEPTIME)
+ {
+ prog->v.p.status = status_enabled;
+ prog->v.p.count = 0;
+ prog->v.p.timestamp = 0;
+ prog_start (prog);
+ }
+ break;
+
+ case status_stopping:
+ check_stopping (prog, now);
+ break;
+
+ case status_enabled:
+ if (prog->pid == 0)
+ prog_start (prog);
+ break;
+
+ default:
+ break;
+ }
}
+ if (recompute_alarm)
+ progman_recompute_alarm ();
}
-void
+static int
prog_start_prerequisites (struct prog *prog)
{
int i;
-
+ int ret;
+ unsigned settle_timeout = 0;
+
if (!prog->prereq)
- return;
+ return 0; /* Ok to startup */
MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, "Starting prerequisites of %s\n",
prog->tag);
+ ret = 0;
for (i = 0; prog->prereq[i]; i++)
{
struct prog *dp = prog_lookup_by_tag (prog->prereq[i]);
@@ -1103,17 +1189,36 @@ prog_start_prerequisites (struct prog *prog)
continue;
switch (dp->v.p.status)
{
+ case status_enabled:
+ if (prog->pid != 0)
+ continue;
+ break;
+
case status_disabled:
prog->v.p.status = status_disabled;
- return;
+ return 1;
+
case status_listener:
- return;
- default:
- /* FIXME: other states */
+ continue;
+
+ case status_sleeping:
+ /* FIXME: What to do in this case? */
break;
+
+ case status_stopping:
+ check_stopping (dp, time (NULL));
+ ret = 1;
+ continue;
}
prog_start (prog_lookup_by_tag (prog->prereq[i]));
+ if (!(dp->v.p.status == status_enabled && dp->pid))
+ ret = 1;
+ else
+ settle_timeout = prog->v.p.comp->settle_timeout;
}
+ if (ret == 0 && settle_timeout)
+ sleep (settle_timeout);
+ return ret;
}
void
@@ -1160,7 +1265,11 @@ prog_stop (struct prog *prog, int sig)
if (prog->type == TYPE_COMPONENT)
{
if (prog->v.p.status == status_enabled)
- prog->v.p.status = status_stopping;
+ {
+ prog->v.p.status = status_stopping;
+ prog->v.p.timestamp = time (NULL);
+ recompute_alarm = 1;
+ }
}
MU_DEBUG2 (pies_debug, MU_DEBUG_TRACE1,
"Stopping %s (%lu)\n",
@@ -1378,6 +1487,7 @@ progman_cleanup (int expect_term)
}
else
{
+ prog->v.p.status = status_enabled;
prog_stop_dependents (prog);
if (!expect_term)
{
@@ -1415,10 +1525,14 @@ progman_cleanup (int expect_term)
{
/* It was a retranslator of an already finished inetd process. */
MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1,
- _("removing inetd retranslator %s"), prog->tag);
+ _("removing inetd retranslator %s\n"), prog->tag);
destroy_prog (&prog);
}
}
+
+ if (!expect_term)
+ /* This will also recompute alarm settings, if necessary */
+ progman_wake_sleeping ();
}
void

Return to:

Send suggestions and report system problems to the System administrator.