s4:process: add method called before entering the tevent_loop_wait
authorJule Anger <janger@samba.org>
Wed, 1 Mar 2023 09:48:18 +0000 (09:48 +0000)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 25 Jul 2023 20:04:29 +0000 (20:04 +0000)
This gives the service a chance to register messaging and/or event handlers
on the correct contexts.

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>

Signed-off-by: Jule Anger <janger@samba.org>
Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
source4/samba/process_prefork.c
source4/samba/process_single.c
source4/samba/process_standard.c
source4/samba/service.h

index a8dee8204580b3543e22142d9ead5168939c6f62..1bad15ee8932b678d3fb9bec1b1841b91e6c0576 100644 (file)
@@ -315,6 +315,9 @@ static void prefork_fork_master(
                if (task != NULL && service_details->post_fork != NULL) {
                        service_details->post_fork(task, &pd);
                }
+               if (task != NULL && service_details->before_loop != NULL) {
+                       service_details->before_loop(task);
+               }
                tevent_loop_wait(ev);
                TALLOC_FREE(ev);
                exit(0);
@@ -398,6 +401,21 @@ static void prefork_fork_master(
                smb_set_close_on_exec(control_pipe[1]);
        }
 
+       /*
+        * Note, we call this before the first
+        * prefork_fork_worker() in order to have
+        * a stable order of:
+        *  task_init(master) -> before_loop(master)
+        *  -> post_fork(worker) -> before_loop(worker)
+        *
+        * Otherwise we would have different behaviors
+        * between the first prefork_fork_worker() loop
+        * and restarting of died workers
+        */
+       if (task != NULL && service_details->before_loop != NULL) {
+               service_details->before_loop(task);
+       }
+
        /*
         * We are now free to spawn some worker processes
         */
@@ -784,6 +802,9 @@ static void prefork_fork_worker(struct task_server *task,
                        irpc_add_name(task->msg_ctx, name);
                        TALLOC_FREE(ctx);
                }
+               if (service_details->before_loop != NULL) {
+                       service_details->before_loop(task);
+               }
                tevent_loop_wait(ev2);
                imessaging_dgm_unref_ev(ev2);
                talloc_free(ev2);
index c2ff460f640ff9a5d9c0c2c5ca39ac1728bffdbf..df4df1c0f25720a89fb01eb6229c7763b045ec3a 100644 (file)
@@ -117,6 +117,9 @@ static void single_new_task(struct tevent_context *ev,
                struct process_details pd = initial_process_details;
                service_details->post_fork(task, &pd);
        }
+       if (task != NULL && service_details->before_loop != NULL) {
+               service_details->before_loop(task);
+       }
 }
 
 /*
index 33b11a61df49ae2c14407e5bb98c42a0f448bda1..fba24ff5e7f69f8b4db71a9f9f88af9642a2b2e2 100644 (file)
@@ -533,6 +533,9 @@ static void standard_new_task(struct tevent_context *ev,
                service_details->post_fork(task, &pd);
        }
 
+       if (task != NULL && service_details->before_loop != NULL) {
+               service_details->before_loop(task);
+       }
 
        /* we can't return to the top level here, as that event context is gone,
           so we now process events in the new event context until there are no
index 7649101b97b077d2ea4c1431b1d032065d4e317a..35e3f519154c718d26fdd765901bf3a5187e9c52 100644 (file)
@@ -73,6 +73,35 @@ struct service_details {
         *   immediately after the task_init.
         */
        void (*post_fork) (struct task_server *, struct process_details *);
+       /*
+        * This is called before entering the tevent_loop_wait():
+        *
+        * Note that task_server->msg_ctx, task_server->event_ctx
+        * and maybe other fields might have changed compared to
+        * task_init()/post_fork(). The struct task_server pointer
+        * may also change!
+        *
+        * before loop processing this is called in this order:
+        *   - standard process model
+        *     task_init() -> post_fork() -> before_loop()
+        *
+        *   - single process model
+        *     task_init() -> post_fork() -> before_loop()
+        *
+        *   - prefork process model, inhibit_pre_fork = true
+        *     task_init() -> post_fork() -> before_loop()
+        *
+        *   - prefork process model, inhibit_pre_fork = false
+        *     In the service master process:
+        *      task_init(master) -> before_loop(master)
+        *
+        *     After each service worker has forked:
+        *      post_fork(worker) -> before_loop(worker)
+        *
+        * This gives the service a chance to register messaging
+        * and/or event handlers on the correct contexts.
+        */
+       void (*before_loop) (struct task_server *);
 };
 
 NTSTATUS samba_service_init(void);