summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimo Sorce <idra@samba.org>2011-05-19 23:56:02 -0400
committerAndreas Schneider <asn@samba.org>2011-08-10 18:14:04 +0200
commit1155280a483e2a84e8baa27556c6ea066dbe6c8a (patch)
tree39c58cbdcb491651b4129233010154fe6e11842a
parentd36a8dc896d2a814dd18f127593a8382e4004213 (diff)
downloadsamba-1155280a483e2a84e8baa27556c6ea066dbe6c8a.tar.gz
samba-1155280a483e2a84e8baa27556c6ea066dbe6c8a.tar.bz2
samba-1155280a483e2a84e8baa27556c6ea066dbe6c8a.zip
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>
-rw-r--r--source3/lib/server_prefork.c60
-rw-r--r--source3/lib/server_prefork.h33
-rw-r--r--source3/printing/spoolssd.c53
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 <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 ==== */
@@ -162,14 +172,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
* are trying to connect. It will allow each child to handle more than
@@ -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;