summaryrefslogtreecommitdiff
path: root/src/serverlib/s6rc_db_check_pipelines.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/serverlib/s6rc_db_check_pipelines.c')
-rw-r--r--src/serverlib/s6rc_db_check_pipelines.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/serverlib/s6rc_db_check_pipelines.c b/src/serverlib/s6rc_db_check_pipelines.c
new file mode 100644
index 0000000..68121e2
--- /dev/null
+++ b/src/serverlib/s6rc_db_check_pipelines.c
@@ -0,0 +1,61 @@
+/* ISC license. */
+
+#include <string.h>
+#include <stdint.h>
+#include <skalibs/diuint32.h>
+#include <s6-rc/s6rc-db.h>
+
+struct recinfo_s
+{
+ s6rc_db_t const *db ;
+ unsigned char *mark ;
+} ;
+
+static uint32_t check_prod_rec (struct recinfo_s *recinfo, uint32_t n)
+{
+ uint32_t i = 0 ;
+ if (recinfo->mark[n] & 3) return n ;
+ recinfo->mark[n] |= 1 ;
+ for (; i < recinfo->db->services[n].x.longrun.nproducers ; i++)
+ {
+ uint32_t j = recinfo->db->producers[recinfo->db->services[n].x.longrun.producers + i] ;
+ if (j >= recinfo->db->nlong) return (recinfo->mark[n] |= 4, n) ;
+ if (recinfo->db->services[j].x.longrun.consumer != n) return (recinfo->mark[j] |= 4, j) ;
+ j = check_prod_rec(recinfo, j) ;
+ if (j < recinfo->db->nlong) return j ;
+ }
+ recinfo->mark[n] |= 2 ;
+ return recinfo->db->nlong ;
+}
+
+int s6rc_db_check_pipelines (s6rc_db_t const *db, diuint32 *problem)
+{
+ uint32_t i = db->nlong ;
+ unsigned char mark[db->nlong] ;
+ struct recinfo_s recinfo = { .db = db, .mark = mark } ;
+ memset(mark, 0, db->nlong) ;
+ while (i--)
+ {
+ if (db->services[i].x.longrun.consumer >= db->nlong && db->services[i].x.longrun.nproducers)
+ {
+ uint32_t j = check_prod_rec(&recinfo, i) ;
+ if (j < db->nlong)
+ {
+ problem->left = i ;
+ problem->right = j ;
+ return mark[j] & 4 ? 3 : mark[j] & 2 ? 2 : 1 ;
+ }
+ }
+ }
+ i = db->nlong ;
+ while (i--)
+ {
+ if (!mark[i] && db->services[i].x.longrun.nproducers)
+ {
+ problem->left = db->services[i].x.longrun.consumer ;
+ problem->right = i ;
+ return 1 ;
+ }
+ }
+ return 0 ;
+}