s3-prefork: Set up a SIGCHLD handler by default
authorSimo Sorce <idra@samba.org>
Fri, 20 May 2011 03:56:02 +0000 (23:56 -0400)
committerAndreas Schneider <asn@samba.org>
Wed, 10 Aug 2011 16:14:04 +0000 (18:14 +0200)
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>
source3/lib/server_prefork.c
source3/lib/server_prefork.h
source3/printing/spoolssd.c

index ef76a55486fd36d9e2aab383a0948e1f2a85d54d..26288f70fd4e42c6d08783703251d98c665c71de 100644 (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 ==== */
 
index f4d03ccca167aba643320bf48296813c35cf3f73..c45b96975ab758d0e68ea51e9f6bb71376d33601 100644 (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 ==== */
 
 /**
index eb7b5e9b8302abb674a80472166d1a8d05c73554..107ae58fe43d133dafb3bd956739375c768d39cb 100644 (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;