1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-24 13:57:43 +03:00

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 <asn@samba.org>
This commit is contained in:
Simo Sorce 2011-05-19 23:56:02 -04:00 committed by Andreas Schneider
parent d36a8dc896
commit 1155280a48
3 changed files with 94 additions and 52 deletions

View File

@ -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 ==== */

View File

@ -21,6 +21,8 @@
#include "system/network.h"
#include <tevent.h>
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 ==== */
/**

View File

@ -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;