From 1155280a483e2a84e8baa27556c6ea066dbe6c8a Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Thu, 19 May 2011 23:56:02 -0400 Subject: s3-prefork: Set up a SIGCHLD handler by default We need to properly handle preforked children so it is better to just do that automatically. If the parent needs/wants to intercept SIGCHLD events it can set a callback that will be called by the prefork code once the internal cleanup function that checks all prefork children has been executed. Signed-off-by: Andreas Schneider --- source3/lib/server_prefork.c | 60 +++++++++++++++++++++++++++++++++++++++++--- source3/lib/server_prefork.h | 33 ++++++++++++++++-------- source3/printing/spoolssd.c | 53 +++++++++++--------------------------- 3 files changed, 94 insertions(+), 52 deletions(-) diff --git a/source3/lib/server_prefork.c b/source3/lib/server_prefork.c index ef76a55486..26288f70fd 100644 --- a/source3/lib/server_prefork.c +++ b/source3/lib/server_prefork.c @@ -40,9 +40,15 @@ struct prefork_pool { struct pf_worker_data *pool; int allowed_clients; + + prefork_sigchld_fn_t *sigchld_fn; + void *sigchld_data; }; -int prefork_pool_destructor(struct prefork_pool *pfp) +static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx, + struct prefork_pool *pfp); + +static int prefork_pool_destructor(struct prefork_pool *pfp) { munmap(pfp->pool, pfp->pool_size * sizeof(struct pf_worker_data)); return 0; @@ -60,8 +66,9 @@ bool prefork_create_pool(struct tevent_context *ev_ctx, TALLOC_CTX *mem_ctx, size_t data_size; int ret; int i; + bool ok; - pfp = talloc(mem_ctx, struct prefork_pool); + pfp = talloc_zero(mem_ctx, struct prefork_pool); if (!pfp) { DEBUG(1, ("Out of memory!\n")); return false; @@ -124,6 +131,13 @@ bool prefork_create_pool(struct tevent_context *ev_ctx, TALLOC_CTX *mem_ctx, } } + ok = prefork_setup_sigchld_handler(ev_ctx, pfp); + if (!ok) { + DEBUG(1, ("Failed to setup SIGCHLD Handler!\n")); + talloc_free(pfp); + return false; + } + *pf_pool = pfp; return true; } @@ -291,7 +305,7 @@ int prefork_count_active_children(struct prefork_pool *pfp, int *total) return a; } -void prefork_cleanup_loop(struct prefork_pool *pfp) +static void prefork_cleanup_loop(struct prefork_pool *pfp) { int status; pid_t pid; @@ -361,6 +375,46 @@ void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num) } } +static void prefork_sigchld_handler(struct tevent_context *ev_ctx, + struct tevent_signal *se, + int signum, int count, + void *siginfo, void *pvt) +{ + struct prefork_pool *pfp; + + pfp = talloc_get_type_abort(pvt, struct prefork_pool); + + /* run the cleanup function to make sure all dead children are + * properly and timely retired. */ + prefork_cleanup_loop(pfp); + + if (pfp->sigchld_fn) { + pfp->sigchld_fn(ev_ctx, pfp, pfp->sigchld_data); + } +} + +static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx, + struct prefork_pool *pfp) +{ + struct tevent_signal *se; + + se = tevent_add_signal(ev_ctx, pfp, SIGCHLD, 0, + prefork_sigchld_handler, pfp); + if (!se) { + DEBUG(0, ("Failed to setup SIGCHLD handler!\n")); + return false; + } + + return true; +} + +void prefork_set_sigchld_callback(struct prefork_pool *pfp, + prefork_sigchld_fn_t *sigchld_fn, + void *private_data) +{ + pfp->sigchld_fn = sigchld_fn; + pfp->sigchld_data = private_data; +} /* ==== Functions used by children ==== */ diff --git a/source3/lib/server_prefork.h b/source3/lib/server_prefork.h index f4d03ccca1..c45b96975a 100644 --- a/source3/lib/server_prefork.h +++ b/source3/lib/server_prefork.h @@ -21,6 +21,8 @@ #include "system/network.h" #include +struct prefork_pool; + enum pf_worker_status { PF_WORKER_NONE = 0, PF_WORKER_IDLE, @@ -76,8 +78,16 @@ typedef int (prefork_main_fn_t)(struct tevent_context *ev, int lock_fd, void *private_data); -struct prefork_pool; - +/** +* @brief Callback function for parents that also want to be called on sigchld +* +* @param ev_ctx The event context +* @param pool The pool handler +* @param private_data Data private to the parent +*/ +typedef void (prefork_sigchld_fn_t)(struct tevent_context *ev_ctx, + struct prefork_pool *pool, + void *private_data); /* ==== Functions used by controlling process ==== */ @@ -161,14 +171,6 @@ int prefork_retire_children(struct prefork_pool *pfp, */ int prefork_count_active_children(struct prefork_pool *pfp, int *total); -/** -* @brief Perform cleanups, like waiting (WNOHANG) dead children. -* MUST be called regularly from the parent main loop. -* -* @param pfp The pool. -*/ -void prefork_cleanup_loop(struct prefork_pool *pfp); - /** * @brief Inform all children that they are allowed to accept 'max' clients * now. Use this when all children are already busy and more clients @@ -200,6 +202,17 @@ void prefork_reset_allowed_clients(struct prefork_pool *pfp); */ void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num); +/** +* @brief Sets the SIGCHLD callback +* +* @param pfp The pool handler. +* @param sigchld_fn The callback function (pass NULL to unset). +* @param private_data Private data for the callback function. +*/ +void prefork_set_sigchld_callback(struct prefork_pool *pfp, + prefork_sigchld_fn_t *sigchld_fn, + void *private_data); + /* ==== Functions used by children ==== */ /** diff --git a/source3/printing/spoolssd.c b/source3/printing/spoolssd.c index eb7b5e9b83..107ae58fe4 100644 --- a/source3/printing/spoolssd.c +++ b/source3/printing/spoolssd.c @@ -228,7 +228,7 @@ static bool spoolss_shutdown_cb(void *ptr) return true; } -/* Childrens */ +/* Children */ struct spoolss_chld_sig_hup_ctx { struct messaging_context *msg_ctx; @@ -537,21 +537,21 @@ static void check_updater_child(void) } } -static void spoolssd_sig_chld_handler(struct tevent_context *ev_ctx, - struct tevent_signal *se, - int signum, int count, - void *siginfo, void *pvt) +static bool spoolssd_schedule_check(struct tevent_context *ev_ctx, + struct prefork_pool *pfp, + struct timeval current_time); +static void spoolssd_check_children(struct tevent_context *ev_ctx, + struct tevent_timer *te, + struct timeval current_time, + void *pvt); + +static void spoolssd_sigchld_handler(struct tevent_context *ev_ctx, + struct prefork_pool *pfp, + void *private_data) { - struct prefork_pool *pfp; int active, total; int n, r; - pfp = talloc_get_type_abort(pvt, struct prefork_pool); - - /* run the cleanup function to make sure all dead children are - * properly and timely retired. */ - prefork_cleanup_loop(pfp); - /* now check we do not descend below the minimum */ active = prefork_count_active_children(pfp, &total); @@ -574,38 +574,13 @@ static void spoolssd_sig_chld_handler(struct tevent_context *ev_ctx, check_updater_child(); } -static bool spoolssd_setup_sig_chld_handler(struct tevent_context *ev_ctx, - struct prefork_pool *pfp) -{ - struct tevent_signal *se; - - se = tevent_add_signal(ev_ctx, ev_ctx, SIGCHLD, 0, - spoolssd_sig_chld_handler, pfp); - if (!se) { - DEBUG(0, ("Failed to setup SIGCHLD handler!\n")); - return false; - } - - return true; -} - -static bool spoolssd_schedule_check(struct tevent_context *ev_ctx, - struct prefork_pool *pfp, - struct timeval current_time); -static void spoolssd_check_children(struct tevent_context *ev_ctx, - struct tevent_timer *te, - struct timeval current_time, - void *pvt); - static bool spoolssd_setup_children_monitor(struct tevent_context *ev_ctx, struct prefork_pool *pfp) { bool ok; - ok = spoolssd_setup_sig_chld_handler(ev_ctx, pfp); - if (!ok) { - return false; - } + /* add our oun sigchld callback */ + prefork_set_sigchld_callback(pfp, spoolssd_sigchld_handler, NULL); ok = spoolssd_schedule_check(ev_ctx, pfp, tevent_timeval_current()); return ok; -- cgit