Changes with Apache 2.3.12
+ *) Add child_status hook for tracking creation/termination of MPM child
+ processes. Add end_generation hook for notification when the last
+ MPM child of a generation exits. [Jeff Trawick]
+
*) mod_ldap: Make LDAPSharedCacheSize 0 create a non-shared-memory cache per
process as opposed to disabling caching completely. This allows to use
the non-shared-memory cache as a workaround for the shared memory cache
* 20110329.1 (2.3.12-dev) Add ap_reserve_module_slots()/ap_reserve_module_slots_directive()
* change AP_CORE_DECLARE to AP_DECLARE: ap_create_request_config()
* change AP_DECLARE to AP_CORE_DECLARE: ap_register_log_hooks()
+ * 20110329.2 (2.3.12-dev) Add child_status and end_generation hooks.
*/
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
#ifndef MODULE_MAGIC_NUMBER_MAJOR
#define MODULE_MAGIC_NUMBER_MAJOR 20110329
#endif
-#define MODULE_MAGIC_NUMBER_MINOR 1 /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 2 /* 0...n */
/**
* Determine if the server's current MODULE_MAGIC_NUMBER is at least a
#include "apr_thread_proc.h"
#include "httpd.h"
+#include "scoreboard.h"
#ifdef __cplusplus
extern "C" {
AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t,
ap_mpm_callback_fn_t *cbfn,
void *baton);
-
+
+typedef enum mpm_child_status {
+ MPM_CHILD_STARTED,
+ MPM_CHILD_EXITED,
+ MPM_CHILD_LOST_SLOT
+} mpm_child_status;
+
+/**
+ * Allow a module to remain aware of MPM child process state changes,
+ * along with the generation and scoreboard slot of the process changing
+ * state.
+ *
+ * With some MPMs (event and worker), an active MPM child process may lose
+ * its scoreboard slot if the child process is exiting and the scoreboard
+ * slot is needed by other processes. When this occurs, the hook will be
+ * called with the MPM_CHILD_LOST_SLOT state.
+ *
+ * @param s The main server_rec.
+ * @param pid The id of the MPM child process.
+ * @param gen The server generation of that child process.
+ * @param slot The scoreboard slot number, or -1. It will be -1 when an
+ * MPM child process exits, and that child had previously lost its
+ * scoreboard slot.
+ * @param state One of the mpm_child_status values. Modules should ignore
+ * unrecognized values.
+ */
+AP_DECLARE_HOOK(void,child_status,(server_rec *s, pid_t pid, ap_generation_t gen,
+ int slot, mpm_child_status state))
+
+/**
+ * Allow a module to be notified when the last child process of a generation
+ * exits.
+ *
+ * @param s The main server_rec.
+ * @param gen The server generation which is now completely finished.
+ */
+AP_DECLARE_HOOK(void,end_generation,(server_rec *s, ap_generation_t gen))
+
/* Defining GPROF when compiling uses the moncontrol() function to
* disable gprof profiling in the parent, and enable it only for
* request processing in children (or in one_process mode). It's
#include "ap_config.h"
#include "ap_mpm.h"
+#include "scoreboard.h"
#if APR_HAVE_NETINET_TCP_H
#include <netinet/tcp.h> /* for TCP_NODELAY */
* ap_relieve_child_processes(). The callback function will be
* called for each terminated child process.
*/
-typedef void ap_reclaim_callback_fn_t(int childnum);
+typedef void ap_reclaim_callback_fn_t(int childnum, pid_t pid,
+ ap_generation_t gen);
/**
* Make sure all child processes that have been spawned by the parent process
* an MPM child process which has no entry in the scoreboard.
* @param pid The process id of an MPM child process which should be
* reclaimed when ap_reclaim_child_processes() is called.
+ * @param gen The generation of this MPM child process.
*
* @note If an extra MPM child process terminates prior to calling
* ap_reclaim_child_processes(), remove it from the list of such processes
* by calling ap_unregister_extra_mpm_process().
*/
-void ap_register_extra_mpm_process(pid_t pid);
+void ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen);
/**
* Unregister an MPM child process which was previously registered by a
* call to ap_register_extra_mpm_process().
* @param pid The process id of an MPM child process which no longer needs to
* be reclaimed.
+ * @param old_gen Set to the server generation of the process, if found.
* @return 1 if the process was found and removed, 0 otherwise
*/
-int ap_unregister_extra_mpm_process(pid_t pid);
+int ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *old_gen);
/**
* Safely signal an MPM child process, if the process is in the
extern apr_status_t ap_fatal_signal_setup(server_rec *s, apr_pool_t *pconf);
extern apr_status_t ap_fatal_signal_child_setup(server_rec *s);
+/* core's implementation of child_status hook */
+extern void ap_core_child_status(server_rec *s, pid_t pid, ap_generation_t gen,
+ int slot, mpm_child_status status);
+
#if AP_ENABLE_EXCEPTION_HOOK
extern const char *ap_mpm_set_exception_hook(cmd_parms *cmd, void *dummy,
const char *arg);
APR_OPTIONAL_HOOK(proxy, create_req, core_create_proxy_req, NULL, NULL,
APR_HOOK_MIDDLE);
ap_hook_pre_mpm(ap_create_scoreboard, NULL, NULL, APR_HOOK_MIDDLE);
+ ap_hook_child_status(ap_core_child_status, NULL, NULL, APR_HOOK_MIDDLE);
/* register the core's insert_filter hook and register core-provided
* filters
return OK;
}
-static void event_note_child_killed(int childnum)
+static void event_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
{
- ap_scoreboard_image->parent[childnum].pid = 0;
+ if (childnum != -1) { /* child had a scoreboard slot? */
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[childnum].pid,
+ ap_scoreboard_image->parent[childnum].generation,
+ childnum, MPM_CHILD_EXITED);
+ ap_scoreboard_image->parent[childnum].pid = 0;
+ }
+ else {
+ ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED);
+ }
+}
+
+static void event_note_child_started(int slot, pid_t pid)
+{
+ ap_scoreboard_image->parent[slot].pid = pid;
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ retained->my_generation, slot, MPM_CHILD_STARTED);
+}
+
+static void event_note_child_lost_slot(int slot, pid_t newpid)
+{
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
+ "pid %" APR_PID_T_FMT " taking over scoreboard slot from "
+ "%" APR_PID_T_FMT "%s",
+ newpid,
+ ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].quiescing ?
+ " (quiescing)" : "");
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].generation,
+ slot, MPM_CHILD_LOST_SLOT);
+ /* Don't forget about this exiting child process, or we
+ * won't be able to kill it if it doesn't exit by the
+ * time the server is shut down.
+ */
+ ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].generation);
}
static const char *event_get_name(void)
if (pchild) {
apr_pool_destroy(pchild);
}
+
+ if (one_process) {
+ event_note_child_killed(/* slot */ 0, 0, 0);
+ }
+
exit(code);
}
if (one_process) {
set_signals();
- ap_scoreboard_image->parent[slot].pid = getpid();
+ event_note_child_started(slot, getpid());
child_main(slot);
/* NOTREACHED */
}
/* This new child process is squatting on the scoreboard
* entry owned by an exiting child process, which cannot
* exit until all active requests complete.
- * Don't forget about this exiting child process, or we
- * won't be able to kill it if it doesn't exit by the
- * time the server is shut down.
*/
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
- "taking over scoreboard slot from %" APR_PID_T_FMT "%s",
- ap_scoreboard_image->parent[slot].pid,
- ap_scoreboard_image->parent[slot].quiescing ?
- " (quiescing)" : "");
- ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid);
+ event_note_child_lost_slot(slot, pid);
}
ap_scoreboard_image->parent[slot].quiescing = 0;
- ap_scoreboard_image->parent[slot].pid = pid;
+ event_note_child_started(slot, pid);
return 0;
}
static void server_main_loop(int remaining_children_to_start)
{
+ ap_generation_t old_gen;
int child_slot;
apr_exit_why_e exitwhy;
int status, processed_status;
SERVER_DEAD,
(request_rec *) NULL);
- ap_scoreboard_image->parent[child_slot].pid = 0;
+ event_note_child_killed(child_slot, 0, 0);
ap_scoreboard_image->parent[child_slot].quiescing = 0;
if (processed_status == APEXIT_CHILDSICK) {
/* resource shortage, minimize the fork rate */
--remaining_children_to_start;
}
}
- else if (ap_unregister_extra_mpm_process(pid.pid) == 1) {
- /* handled */
+ else if (ap_unregister_extra_mpm_process(pid.pid, &old_gen) == 1) {
+
+ event_note_child_killed(-1, /* already out of the scoreboard */
+ pid.pid, old_gen);
#if APR_HAS_OTHER_CHILD
}
else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH,
/* Only set slot 0 since that is all NetWare will ever have. */
ap_scoreboard_image->parent[0].pid = getpid();
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[0].pid,
+ ap_my_generation,
+ 0,
+ MPM_CHILD_STARTED);
set_signals();
}
mpm_state = AP_MPMQ_STOPPING;
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[0].pid,
+ ap_my_generation,
+ 0,
+ MPM_CHILD_EXITED);
/* Shutdown the listen sockets so that we don't get stuck in a blocking call.
shutdown_listeners();*/
#define chdir_for_gprof()
#endif
+static void prefork_note_child_killed(int childnum, pid_t pid,
+ ap_generation_t gen)
+{
+ AP_DEBUG_ASSERT(childnum != -1); /* no scoreboard squatting with this MPM */
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[childnum].pid,
+ ap_scoreboard_image->parent[childnum].generation,
+ childnum, MPM_CHILD_EXITED);
+ ap_scoreboard_image->parent[childnum].pid = 0;
+}
+
+static void prefork_note_child_started(int slot, pid_t pid)
+{
+ ap_scoreboard_image->parent[slot].pid = pid;
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ retained->my_generation, slot, MPM_CHILD_STARTED);
+}
+
/* a clean exit from a child with proper cleanup */
static void clean_child_exit(int code) __attribute__ ((noreturn));
static void clean_child_exit(int code)
if (pchild) {
apr_pool_destroy(pchild);
}
+
+ if (one_process) {
+ prefork_note_child_killed(/* slot */ 0, 0, 0);
+ }
+
ap_mpm_pod_close(pod);
chdir_for_gprof();
exit(code);
return OK;
}
-static void prefork_note_child_killed(int childnum)
-{
- ap_scoreboard_image->parent[childnum].pid = 0;
-}
-
static const char *prefork_get_name(void)
{
return "prefork";
apr_signal(SIGQUIT, SIG_DFL);
#endif
apr_signal(SIGTERM, sig_term);
- ap_scoreboard_image->parent[slot].pid = getpid();
+ prefork_note_child_started(slot, getpid());
child_main(slot);
/* NOTREACHED */
}
child_main(slot);
}
- ap_scoreboard_image->parent[slot].pid = pid;
+ prefork_note_child_started(slot, pid);
return 0;
}
if (child_slot >= 0) {
(void) ap_update_child_status_from_indexes(child_slot, 0, SERVER_DEAD,
(request_rec *) NULL);
+ prefork_note_child_killed(child_slot, 0, 0);
if (processed_status == APEXIT_CHILDSICK) {
/* child detected a resource shortage (E[NM]FILE, ENOBUFS, etc)
* cut the fork rate to the minimum
{ NULL }
};
+static void winnt_note_child_started(int slot, pid_t pid)
+{
+ ap_scoreboard_image->parent[slot].pid = pid;
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ my_generation, slot, MPM_CHILD_STARTED);
+}
+
+static void winnt_note_child_killed(int slot)
+{
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].generation,
+ slot, MPM_CHILD_EXITED);
+ ap_scoreboard_image->parent[slot].pid = 0;
+}
/*
* Signalling Apache on NT.
* child at once.
*/
ap_scoreboard_image->parent[0].quiescing = 0;
- ap_scoreboard_image->parent[0].pid = child_pid;
+ winnt_note_child_started(/* slot */ 0, child_pid);
/* Wait for shutdown or restart events or for child death */
winnt_mpm_state = AP_MPMQ_RUNNING;
CloseHandle(event_handles[CHILD_HANDLE]);
event_handles[CHILD_HANDLE] = NULL;
}
+
+ winnt_note_child_killed(/* slot */ 0);
+
if (restart_pending) {
++my_generation;
ap_scoreboard_image->global->running_generation = my_generation;
return OK;
}
-static void worker_note_child_killed(int childnum)
+static void worker_note_child_killed(int childnum, pid_t pid, ap_generation_t gen)
{
- ap_scoreboard_image->parent[childnum].pid = 0;
+ if (childnum != -1) { /* child had a scoreboard slot? */
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[childnum].pid,
+ ap_scoreboard_image->parent[childnum].generation,
+ childnum, MPM_CHILD_EXITED);
+ ap_scoreboard_image->parent[childnum].pid = 0;
+ }
+ else {
+ ap_run_child_status(ap_server_conf, pid, gen, -1, MPM_CHILD_EXITED);
+ }
+}
+
+static void worker_note_child_started(int slot, pid_t pid)
+{
+ ap_scoreboard_image->parent[slot].pid = pid;
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ retained->my_generation, slot, MPM_CHILD_STARTED);
+}
+
+static void worker_note_child_lost_slot(int slot, pid_t newpid)
+{
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
+ "pid %" APR_PID_T_FMT " taking over scoreboard slot from "
+ "%" APR_PID_T_FMT "%s",
+ newpid,
+ ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].quiescing ?
+ " (quiescing)" : "");
+ ap_run_child_status(ap_server_conf,
+ ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].generation,
+ slot, MPM_CHILD_LOST_SLOT);
+ /* Don't forget about this exiting child process, or we
+ * won't be able to kill it if it doesn't exit by the
+ * time the server is shut down.
+ */
+ ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid,
+ ap_scoreboard_image->parent[slot].generation);
}
static const char *worker_get_name(void)
if (pchild) {
apr_pool_destroy(pchild);
}
+
+ if (one_process) {
+ worker_note_child_killed(/* slot */ 0, 0, 0);
+ }
+
exit(code);
}
if (one_process) {
set_signals();
- ap_scoreboard_image->parent[slot].pid = getpid();
+ worker_note_child_started(slot, getpid());
child_main(slot);
/* NOTREACHED */
}
/* This new child process is squatting on the scoreboard
* entry owned by an exiting child process, which cannot
* exit until all active requests complete.
- * Don't forget about this exiting child process, or we
- * won't be able to kill it if it doesn't exit by the
- * time the server is shut down.
*/
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, ap_server_conf,
- "taking over scoreboard slot from %" APR_PID_T_FMT "%s",
- ap_scoreboard_image->parent[slot].pid,
- ap_scoreboard_image->parent[slot].quiescing ?
- " (quiescing)" : "");
- ap_register_extra_mpm_process(ap_scoreboard_image->parent[slot].pid);
+ worker_note_child_lost_slot(slot, pid);
}
ap_scoreboard_image->parent[slot].quiescing = 0;
- ap_scoreboard_image->parent[slot].pid = pid;
+ worker_note_child_started(slot, pid);
return 0;
}
static void server_main_loop(int remaining_children_to_start)
{
+ ap_generation_t old_gen;
int child_slot;
apr_exit_why_e exitwhy;
int status, processed_status;
ap_update_child_status_from_indexes(child_slot, i, SERVER_DEAD,
(request_rec *) NULL);
- ap_scoreboard_image->parent[child_slot].pid = 0;
+ worker_note_child_killed(child_slot, 0, 0);
ap_scoreboard_image->parent[child_slot].quiescing = 0;
if (processed_status == APEXIT_CHILDSICK) {
/* resource shortage, minimize the fork rate */
--remaining_children_to_start;
}
}
- else if (ap_unregister_extra_mpm_process(pid.pid) == 1) {
- /* handled */
+ else if (ap_unregister_extra_mpm_process(pid.pid, &old_gen) == 1) {
+ worker_note_child_killed(-1, /* already out of the scoreboard */
+ pid.pid, old_gen);
#if APR_HAS_OTHER_CHILD
}
else if (apr_proc_other_child_alert(&pid, APR_OC_REASON_DEATH,
APR_HOOK_LINK(mpm_query)
APR_HOOK_LINK(mpm_register_timed_callback)
APR_HOOK_LINK(mpm_get_name)
+ APR_HOOK_LINK(end_generation)
+ APR_HOOK_LINK(child_status)
)
AP_IMPLEMENT_HOOK_RUN_ALL(int, fatal_exception,
(ap_exception_info_t *ei), (ei), OK, DECLINED)
APR_HOOK_LINK(mpm_query)
APR_HOOK_LINK(mpm_register_timed_callback)
APR_HOOK_LINK(mpm_get_name)
+ APR_HOOK_LINK(end_generation)
+ APR_HOOK_LINK(child_status)
)
#endif
AP_IMPLEMENT_HOOK_RUN_ALL(int, monitor,
AP_IMPLEMENT_HOOK_RUN_FIRST(const char *, mpm_get_name,
(void),
(), NULL)
+AP_IMPLEMENT_HOOK_VOID(end_generation,
+ (server_rec *s, ap_generation_t gen),
+ (s, gen))
+AP_IMPLEMENT_HOOK_VOID(child_status,
+ (server_rec *s, pid_t pid, ap_generation_t gen, int slot, mpm_child_status status),
+ (s,pid,gen,slot,status))
+
+typedef struct mpm_gen_info_t {
+ APR_RING_ENTRY(mpm_gen_info_t) link;
+ int gen; /* which gen? */
+ int active; /* number of active processes */
+} mpm_gen_info_t;
+
+APR_RING_HEAD(mpm_gen_info_head_t, mpm_gen_info_t);
+static struct mpm_gen_info_head_t geninfo, unused_geninfo;
+static int gen_head_init; /* yuck */
/* variables representing config directives implemented here */
const char *ap_pid_fname;
return rv;
}
+/* core's child-status hook
+ * tracks number of remaining children per generation and
+ * runs the end-generation hook when a generation finishes
+ */
+void ap_core_child_status(server_rec *s, pid_t pid,
+ ap_generation_t gen, int slot,
+ mpm_child_status status)
+{
+ mpm_gen_info_t *cur;
+ const char *status_msg = "unknown status";
+
+ if (!gen_head_init) { /* where to run this? */
+ gen_head_init = 1;
+ APR_RING_INIT(&geninfo, mpm_gen_info_t, link);
+ APR_RING_INIT(&unused_geninfo, mpm_gen_info_t, link);
+ }
+
+ cur = APR_RING_FIRST(&geninfo);
+ while (cur != APR_RING_SENTINEL(&geninfo, mpm_gen_info_t, link) &&
+ cur->gen != gen) {
+ cur = APR_RING_NEXT(cur, link);
+ }
+
+ switch(status) {
+ case MPM_CHILD_STARTED:
+ status_msg = "started";
+ if (cur == APR_RING_SENTINEL(&geninfo, mpm_gen_info_t, link)) {
+ /* first child for this generation */
+ if (!APR_RING_EMPTY(&unused_geninfo, mpm_gen_info_t, link)) {
+ cur = APR_RING_FIRST(&unused_geninfo);
+ APR_RING_REMOVE(cur, link);
+ }
+ else {
+ cur = apr_pcalloc(s->process->pool, sizeof *cur);
+ }
+ cur->gen = gen;
+ APR_RING_ELEM_INIT(cur, link);
+ APR_RING_INSERT_HEAD(&geninfo, cur, mpm_gen_info_t, link);
+ }
+ ++cur->active;
+ break;
+ case MPM_CHILD_EXITED:
+ status_msg = "exited";
+ if (cur == APR_RING_SENTINEL(&geninfo, mpm_gen_info_t, link)) {
+ ap_log_error(APLOG_MARK, APLOG_ERR, 0, s,
+ "no record of generation %d of exiting child %" APR_PID_T_FMT,
+ gen, pid);
+ }
+ else {
+ --cur->active;
+ if (!cur->active) {
+ ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, ap_server_conf,
+ "end of generation %d", gen);
+ ap_run_end_generation(ap_server_conf, gen);
+ APR_RING_REMOVE(cur, link);
+ APR_RING_INSERT_HEAD(&unused_geninfo, cur, mpm_gen_info_t, link);
+ }
+ }
+ break;
+ case MPM_CHILD_LOST_SLOT:
+ status_msg = "lost slot";
+ /* we don't track by slot, so it doesn't matter */
+ break;
+ }
+ ap_log_error(APLOG_MARK, APLOG_TRACE4, 0, s,
+ "mpm child %" APR_PID_T_FMT " (gen %d/slot %d) %s",
+ pid, gen, slot, status_msg);
+}
+
AP_DECLARE(apr_status_t) ap_mpm_register_timed_callback(apr_time_t t, ap_mpm_callback_fn_t *cbfn, void *baton)
{
return ap_run_mpm_register_timed_callback(t, cbfn, baton);
typedef struct extra_process_t {
struct extra_process_t *next;
pid_t pid;
+ ap_generation_t gen;
} extra_process_t;
static extra_process_t *extras;
-void ap_register_extra_mpm_process(pid_t pid)
+void ap_register_extra_mpm_process(pid_t pid, ap_generation_t gen)
{
extra_process_t *p = (extra_process_t *)malloc(sizeof(extra_process_t));
p->next = extras;
p->pid = pid;
+ p->gen = gen;
extras = p;
}
-int ap_unregister_extra_mpm_process(pid_t pid)
+int ap_unregister_extra_mpm_process(pid_t pid, ap_generation_t *gen)
{
extra_process_t *cur = extras;
extra_process_t *prev = NULL;
else {
extras = cur->next;
}
+ *gen = cur->gen;
free(cur);
return 1; /* found */
}
}
if (reclaim_one_pid(pid, action_table[cur_action].action)) {
- mpm_callback(i);
+ mpm_callback(i, 0, 0);
}
else {
++not_dead_yet;
cur_extra = extras;
while (cur_extra) {
+ ap_generation_t old_gen;
extra_process_t *next = cur_extra->next;
if (reclaim_one_pid(cur_extra->pid, action_table[cur_action].action)) {
- AP_DEBUG_ASSERT(1 == ap_unregister_extra_mpm_process(cur_extra->pid));
+ AP_DEBUG_ASSERT(1 == ap_unregister_extra_mpm_process(cur_extra->pid, &old_gen));
+ mpm_callback(-1, cur_extra->pid, old_gen);
}
else {
++not_dead_yet;
}
if (reclaim_one_pid(pid, DO_NOTHING)) {
- mpm_callback(i);
+ mpm_callback(i, 0, 0);
}
}
cur_extra = extras;
while (cur_extra) {
+ ap_generation_t old_gen;
extra_process_t *next = cur_extra->next;
if (reclaim_one_pid(cur_extra->pid, DO_NOTHING)) {
- AP_DEBUG_ASSERT(1 == ap_unregister_extra_mpm_process(cur_extra->pid));
+ AP_DEBUG_ASSERT(1 == ap_unregister_extra_mpm_process(cur_extra->pid, &old_gen));
+ mpm_callback(-1, cur_extra->pid, old_gen);
}
cur_extra = next;
}