add more instance state handling code
authorFelix Fietkau <nbd@openwrt.org>
Thu, 7 Jun 2012 15:51:41 +0000 (17:51 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Thu, 7 Jun 2012 15:51:41 +0000 (17:51 +0200)
service.c
service.h

index f50daa74a1d03396f71ab9da8dc50d2342fd75c0..360810ea8b20ce3cf06053db10310af17bc950c9 100644 (file)
--- a/service.c
+++ b/service.c
@@ -6,33 +6,83 @@ struct avl_tree services;
 static struct blob_buf b;
 
 static void
-service_instance_update(struct vlist_tree *tree, struct vlist_node *node_new,
-                       struct vlist_node *node_old)
+start_instance(struct service_instance *in)
 {
-       struct service_instance *in_o = NULL, *in_n = NULL;
+       in->restart = false;
+}
 
-       if (node_old)
-               in_o = container_of(node_old, struct service_instance, node);
+static void
+instance_timeout(struct uloop_timeout *t)
+{
+       struct service_instance *in;
 
-       if (node_new)
-               in_n = container_of(node_new, struct service_instance, node);
+       in = container_of(t, struct service_instance, timeout);
+       kill(in->proc.pid, SIGKILL);
+       uloop_process_delete(&in->proc);
+       in->proc.cb(&in->proc, -1);
+}
 
-       do {
-               if (!in_o || !in_n)
-                       break;
+static void
+instance_exit(struct uloop_process *p, int ret)
+{
+       struct service_instance *in;
+
+       in = container_of(p, struct service_instance, proc);
+       uloop_timeout_cancel(&in->timeout);
+       if (in->restart)
+               start_instance(in);
+}
 
-               /* full match, nothing to do */
+static void
+stop_instance(struct service_instance *in, bool restart)
+{
+       if (!in->proc.pending)
                return;
-       } while (0);
 
-       if (in_o) {
-               /* kill old process */
-               free(in_o);
-       }
+       kill(in->proc.pid, SIGTERM);
+}
 
-       if (in_n) {
-               /* start new process */
-       }
+static bool
+instance_config_changed(struct service_instance *in, struct service_instance *in_new)
+{
+       int len = blob_pad_len(in->config);
+
+       if (len != blob_pad_len(in_new->config))
+               return true;
+
+       if (memcmp(in->config, in_new->config, blob_pad_len(in->config)) != 0)
+               return true;
+
+       return false;
+}
+
+static bool
+update_instance(struct service_instance *in, struct service_instance *in_new)
+{
+       bool changed = instance_config_changed(in, in_new);
+
+       in->config = in_new->config;
+       if (!changed)
+               return false;
+
+       stop_instance(in, true);
+       return true;
+}
+
+static void
+free_instance(struct service_instance *in)
+{
+       uloop_process_delete(&in->proc);
+       uloop_timeout_cancel(&in->timeout);
+       free(in);
+}
+
+static void
+init_instance(struct service_instance *in, struct blob_attr *config)
+{
+       in->config = config;
+       in->timeout.cb = instance_timeout;
+       in->proc.cb = instance_exit;
 }
 
 static void
@@ -48,10 +98,33 @@ service_instance_add(struct service *s, struct blob_attr *attr)
        if (!in)
                return;
 
-       in->config = attr;
+       init_instance(in, attr);
        vlist_add(&s->instances, &in->node, (void *) name);
 }
 
+static void
+service_instance_update(struct vlist_tree *tree, struct vlist_node *node_new,
+                       struct vlist_node *node_old)
+{
+       struct service_instance *in_o = NULL, *in_n = NULL;
+
+       if (node_old)
+               in_o = container_of(node_old, struct service_instance, node);
+
+       if (node_new)
+               in_n = container_of(node_new, struct service_instance, node);
+
+       if (in_o && in_n) {
+               update_instance(in_o, in_n);
+               free_instance(in_n);
+       } else if (in_o) {
+               stop_instance(in_o, false);
+               free_instance(in_o);
+       } else if (in_n) {
+               start_instance(in_n);
+       }
+}
+
 static struct service *
 service_alloc(const char *name)
 {
@@ -59,6 +132,7 @@ service_alloc(const char *name)
 
        s = calloc(1, sizeof(*s));
        vlist_init(&s->instances, avl_strcmp, service_instance_update);
+       s->instances.keep_old = true;
 
        return s;
 }
index c2afdaedf1a4b945a29470bfa372ad5bb0ecbe34..96175c4713d578d98f326d5745cb15abd298c82d 100644 (file)
--- a/service.h
+++ b/service.h
@@ -15,7 +15,9 @@ struct service_instance {
        struct vlist_node node;
        const char *name;
 
+       bool restart;
        struct blob_attr *config;
        struct uloop_process proc;
+       struct uloop_timeout timeout;
 };