exit(0);
}
+static void prefork_restart_fn(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv,
+ void *private_data);
+
/*
* Restarts a child process if it exits unexpectedly
*/
-static void prefork_restart(struct tevent_context *ev,
+static bool prefork_restart(struct tevent_context *ev,
struct restart_context *rc)
+{
+ struct tevent_timer *te = NULL;
+
+ if (rc->restart_delay > 0) {
+ DBG_ERR("Restarting [%s] pre-fork %s in (%d) seconds\n",
+ rc->service_name,
+ (rc->master == NULL) ? "worker" : "master",
+ rc->restart_delay);
+ }
+
+ /*
+ * Always use an async timer event. If
+ * rc->restart_delay is zero this is the
+ * same as an immediate event and will be
+ * called immediately we go back into the
+ * event loop.
+ */
+ te = tevent_add_timer(ev,
+ ev,
+ tevent_timeval_current_ofs(rc->restart_delay, 0),
+ prefork_restart_fn,
+ rc);
+ if (te == NULL) {
+ DBG_ERR("tevent_add_timer fail [%s] pre-fork event %s\n",
+ rc->service_name,
+ (rc->master == NULL) ? "worker" : "master");
+ /* Caller needs to free rc. */
+ return false;
+ }
+ /* Caller must not free rc - it's in use. */
+ return true;
+}
+
+static void prefork_restart_fn(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval tv,
+ void *private_data)
{
unsigned max_backoff = 0;
unsigned backoff = 0;
- unsigned restart_delay = rc->restart_delay;
unsigned default_value = 0;
+ struct restart_context *rc = talloc_get_type(private_data,
+ struct restart_context);
+ unsigned restart_delay = rc->restart_delay;
+
+ TALLOC_FREE(te);
/*
* If the child process is constantly exiting, then restarting it can
rc->service_name,
default_value);
- if (restart_delay > 0) {
- DBG_ERR("Restarting [%s] pre-fork %s in (%d) seconds\n",
- rc->service_name,
- (rc->master == NULL) ? "worker" : "master",
- restart_delay);
- sleep(restart_delay);
- }
restart_delay += backoff;
restart_delay = min(restart_delay, max_backoff);
restart_delay,
&pd);
}
+ /* tfork allocates tfork structures with malloc */
+ tfork_destroy(&rc->t);
+ free(rc->t);
+ TALLOC_FREE(rc);
}
/*
struct restart_context *rc = NULL;
int status = 0;
pid_t pid = 0;
+ bool rc_inuse = false;
/* free the fde which removes the event and stops it firing again */
TALLOC_FREE(fde);
DBG_ERR("Parent %d, Child %d terminated, "
"unable to get status code from tfork\n",
getpid(), pid);
- prefork_restart(ev, rc);
+ rc_inuse = prefork_restart(ev, rc);
} else if (WIFEXITED(status)) {
status = WEXITSTATUS(status);
DBG_ERR("Parent %d, Child %d exited with status %d\n",
getpid(), pid, status);
if (status != 0) {
- prefork_restart(ev, rc);
+ rc_inuse = prefork_restart(ev, rc);
}
} else if (WIFSIGNALED(status)) {
status = WTERMSIG(status);
status == SIGILL || status == SIGSYS || status == SIGSEGV ||
status == SIGKILL) {
- prefork_restart(ev, rc);
+ rc_inuse = prefork_restart(ev, rc);
}
}
- /* tfork allocates tfork structures with malloc */
- tfork_destroy(&rc->t);
- free(rc->t);
- TALLOC_FREE(rc);
+ if (!rc_inuse) {
+ /* tfork allocates tfork structures with malloc */
+ tfork_destroy(&rc->t);
+ free(rc->t);
+ TALLOC_FREE(rc);
+ }
return;
}