From 6240d57e7d7106b213389524802c4f47af1fa71a Mon Sep 17 00:00:00 2001
From: obarun <eric@obarun.org>
Date: Wed, 16 Mar 2022 20:18:53 +1100
Subject: [PATCH] wait for dependencies to be really up

---
 src/lib66/exec/ssexec_all.c | 231 +++++++++++++++++++++---------------
 1 file changed, 135 insertions(+), 96 deletions(-)

diff --git a/src/lib66/exec/ssexec_all.c b/src/lib66/exec/ssexec_all.c
index 6ce109e6..08169b1f 100644
--- a/src/lib66/exec/ssexec_all.c
+++ b/src/lib66/exec/ssexec_all.c
@@ -46,7 +46,6 @@
 
 #include <s6-rc/s6rc-servicedir.h>
 
-
 #define FLAGS_STARTING 1 // starting not really up
 #define FLAGS_STOPPING 2 // stopping not really down
 #define FLAGS_UP 3 // really up
@@ -56,7 +55,6 @@
 #define FLAGS_FATAL 7 // process crashed
 #define FLAGS_EXITED 8 // process exited
 
-
 /** return 1 if set, else 0*/
 #define FLAGS_ISSET(has, want) \
         ((~(has) & (want)) == 0)
@@ -65,14 +63,14 @@ typedef struct pidvertex_s pidvertex_t, *pidvertex_t_ref ;
 struct pidvertex_s
 {
     pid_t pid ;
+    int pipe[2] ;
     unsigned int vertex ; // id at graph_hash_t struct
     uint8_t state ;
     int nedge ;
     unsigned int *edge ; // array of id at graph_hash_t struct
 } ;
-#define PIDINDEX_ZERO { 0, 0, 0, 0, 0 }
+#define PIDINDEX_ZERO { 0, { 0, 0 }, 0, 0, 0, 0 }
 
-//static pidvertex_t *apidvertex ;
 static pidvertex_t *apidvertex ;
 static unsigned int napid = 0 ;
 static unsigned int npid = 0 ;
@@ -133,7 +131,6 @@ static void all_redir_fd(void)
     umask(022) ;
 }
 
-
 static int doit(ssexec_t *info, char const *treename, unsigned int what)
 {
     log_flow() ;
@@ -342,6 +339,16 @@ static void pidvertex_free(pidvertex_t *pidv)
     free(pidv->edge) ;
 }
 
+static void pidvertex_array_free(pidvertex_t *apidv,  unsigned int len)
+{
+    log_flow() ;
+
+    size_t pos = 0 ;
+
+    for(; pos < len ; pos++)
+        pidvertex_free(&apidv[pos]) ;
+}
+
 static void pidvertex_init_array(pidvertex_t *apidvertex, graph_t *g, unsigned int *list, unsigned int count, ssexec_t *info, uint8_t requiredby)
 {
     log_flow() ;
@@ -376,18 +383,8 @@ static void pidvertex_init_array(pidvertex_t *apidvertex, graph_t *g, unsigned i
             pidv.state |= FLAGS_DOWN ;
 
         apidvertex[pos] = pidv ;
-    }
-
-}
-
-static void pidvertex_array_free(pidvertex_t *apidv,  unsigned int len)
-{
-    log_flow() ;
-
-    size_t pos = 0 ;
 
-    for(; pos < len ; pos++)
-        pidvertex_free(&apidv[pos]) ;
+    }
 
 }
 
@@ -404,73 +401,6 @@ static int pidvertex_get_id(pidvertex_t *apidv, unsigned int id)
     return -1 ;
 }
 
-static void async_deps(unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph)
-{
-    log_flow() ;
-
-    unsigned int pos = 0 ;
-
-    while (apidvertex[i].nedge) {
-        /** TODO: the pidvertex_get_id() function make a loop
-         * through the apidvertex array to find the corresponding
-         * index of the edge at the apidvertex array.
-         * This is clearly a waste of time and need to be optimized. */
-        unsigned int id = pidvertex_get_id(apidvertex, apidvertex[i].edge[pos]) ;
-
-        if (id < 0)
-            log_dieu(LOG_EXIT_SYS, "get apidvertex id -- please make a bug report") ;
-
-        async(id, what, info, graph) ;
-        apidvertex[i].nedge-- ;
-        pos++ ;
-    }
-
-
-}
-
-static void async(unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph)
-{
-    /**
-     * @i: apidvertex array index
-     * */
-
-    log_flow() ;
-
-    int r ;
-    pid_t pid ;
-
-    char *treename = graph->data.s + genalloc_s(graph_hash_t,&graph->hash)[apidvertex[i].vertex].vertex ;
-
-    if (FLAGS_ISSET(apidvertex[i].state, flag) && !FLAGS_ISSET(apidvertex[i].state, flag_run)) {
-
-        apidvertex[i].state |= flag_run ;
-        apidvertex[i].state |= FLAGS_BLOCK ;
-
-        pid = fork() ;
-
-        if (pid < 0)
-            log_dieusys(LOG_EXIT_SYS, "fork") ;
-
-        if (!pid) {
-
-            if (apidvertex[i].nedge)
-                async_deps(i, what, info, graph) ;
-
-            r = doit(info, treename, what) ;
-            _exit(r) ;
-
-        }
-
-        apidvertex[npid++].pid = pid ;
-
-     } else {
-
-         log_trace("skipping: ", treename, " -- already ", what ? "down" : "up") ;
-     }
-
-    return ;
-}
-
 static inline void kill_all (void)
 {
     log_flow() ;
@@ -479,7 +409,7 @@ static inline void kill_all (void)
     while (j--) kill(apidvertex[j].pid, SIGKILL) ;
 }
 
-static int handle_signal(pidvertex_t *apidvertex, unsigned int what)
+static int handle_signal(pidvertex_t *apidv, unsigned int what)
 {
     log_flow() ;
 
@@ -509,32 +439,39 @@ static int handle_signal(pidvertex_t *apidvertex, unsigned int what)
 
                     } else if (!r) break ;
 
-                    for (; j < npid ; j++)
-                        if (apidvertex[j].pid == r)
+                    for (; j < napid ; j++)
+                        if (apidv[j].pid == r)
                             break ;
 
-                    if (j < npid) {
+                    if (j < napid) {
 
                         unsigned int i = j ;
-                        apidvertex[j] = apidvertex[--npid] ;
+
                         if (!WIFSIGNALED(wstat) && !WEXITSTATUS(wstat)) {
 
-                            apidvertex[i].state = 0 ;
+                            apidv[i].state = 0 ;
                             if (what)
-                                apidvertex[i].state = FLAGS_UP ;
+                                apidv[i].state = FLAGS_UP ;
                             else
-                                apidvertex[i].state = FLAGS_DOWN ;
+                                apidv[i].state = FLAGS_DOWN ;
+
+                            close(apidv[i].pipe[0]) ;
 
-                            apidvertex[i].state |= FLAGS_UNBLOCK ;
+                            npid-- ;
 
                         } else {
 
                             ok = 0 ;
-                            apidvertex[i].state = 0 ;
+
+                            apidv[i].state = 0 ;
                             if (what)
-                                apidvertex[i].state = FLAGS_DOWN ;
+                                apidv[i].state = FLAGS_DOWN ;
                             else
-                                apidvertex[i].state = FLAGS_UP ;
+                                apidv[i].state = FLAGS_UP ;
+
+                            close(apidv[i].pipe[0]) ;
+
+                            npid-- ;
                         }
                     }
                 }
@@ -547,9 +484,110 @@ static int handle_signal(pidvertex_t *apidvertex, unsigned int what)
             default : log_die(LOG_EXIT_SYS, "unexpected data in selfpipe") ;
         }
     }
+
     return ok ;
 }
 
+static int async_deps(unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph)
+{
+    log_flow() ;
+
+    int e = 0 ;
+    unsigned int pos = 0 ;
+    char trigger = 0 ;
+
+    while (apidvertex[i].nedge) {
+
+        /** TODO: the pidvertex_get_id() function make a loop
+         * through the apidvertex array to find the corresponding
+         * index of the edge at the apidvertex array.
+         * This is clearly a waste of time and need to be optimized. */
+        unsigned int id = pidvertex_get_id(apidvertex, apidvertex[i].edge[pos]) ;
+
+        if (id < 0)
+            log_dieu(LOG_EXIT_SYS, "get apidvertex id -- please make a bug report") ;
+
+        /** block until we receive a signal from the dependencies
+         * which is launched first */
+        fd_read(apidvertex[id].pipe[0], (char *)&trigger, 1) ;
+        close(apidvertex[id].pipe[0]) ;
+
+        if (trigger) {
+
+            if (trigger == (what ? 'd' : 'u'))
+                async(id, what, info, graph) ;
+            else
+                goto err ;
+        }
+
+        apidvertex[i].nedge-- ;
+        pos++ ;
+    }
+
+    e = 1 ;
+    err:
+        return e ;
+}
+
+static void async(unsigned int i, unsigned int what, ssexec_t *info, graph_t *graph)
+{
+    /**
+     * @i: apidvertex array index
+     * */
+
+    log_flow() ;
+
+    int r ;
+    pid_t pid ;
+
+    char *treename = graph->data.s + genalloc_s(graph_hash_t,&graph->hash)[apidvertex[i].vertex].vertex ;
+
+    if (FLAGS_ISSET(apidvertex[i].state, flag) && !FLAGS_ISSET(apidvertex[i].state, flag_run)) {
+
+        apidvertex[i].state |= flag_run ;
+
+        if (pipe(apidvertex[i].pipe) < 0)
+            log_dieusys(LOG_EXIT_ZERO,"pipe") ;
+
+        pid = fork() ;
+
+        if (pid < 0)
+            log_dieusys(LOG_EXIT_SYS, "fork") ;
+
+        if (!pid) {
+
+            close(apidvertex[i].pipe[0]) ;
+
+            if (apidvertex[i].nedge)
+                if (!async_deps(i, what, info, graph))
+                    log_dieu(LOG_EXIT_SYS,"start tree: ", treename) ;
+
+            r = doit(info, treename, what) ;
+
+            char event = r ? 'd' : 'u' ;
+
+            fd_write(apidvertex[i].pipe[1], (char *)&event, 1) ;
+
+            close(apidvertex[i].pipe[1]) ;
+
+            selfpipe_finish() ;
+
+            _exit(r) ;
+
+        }
+
+        close(apidvertex[i].pipe[1]) ;
+
+        apidvertex[i].pid = pid ;
+
+    } else {
+
+        log_trace("skipping: ", treename, " -- already ", what ? "down" : "up") ;
+    }
+
+    return ;
+}
+
 static int waitit(int spfd, pidvertex_t *apidv, graph_t *graph, unsigned int what, tain *deadline, ssexec_t *info)
 {
     iopause_fd x = { .fd = spfd, .events = IOPAUSE_READ } ;
@@ -557,6 +595,7 @@ static int waitit(int spfd, pidvertex_t *apidv, graph_t *graph, unsigned int wha
     int r ;
     pidvertex_t apidvertextable[napid] ;
     apidvertex = apidvertextable ;
+    npid = napid ;
 
     for (; pos < napid ; pos++)
         apidvertex[pos] = apidv[pos] ;
@@ -574,6 +613,7 @@ static int waitit(int spfd, pidvertex_t *apidv, graph_t *graph, unsigned int wha
         if (!handle_signal(apidvertex, what))
             e = 0 ;
     }
+
     return e ;
 }
 
@@ -723,6 +763,5 @@ int ssexec_all(int argc, char const *const *argv,char const *const *envp, ssexec
         graph_free_all(&graph) ;
         pidvertex_array_free(apidv, napid) ;
 
-
     return (!r) ? 111 : 0 ;
 }
-- 
GitLab