summaryrefslogtreecommitdiffstats
path: root/service.c
diff options
context:
space:
mode:
authorFelix Fietkau <nbd@openwrt.org>2012-06-07 17:51:41 +0200
committerFelix Fietkau <nbd@openwrt.org>2012-06-07 17:51:41 +0200
commit86009b5439a898fa00cc27e675bb7834576be70a (patch)
tree7f30f346f20646e3e5c64a69bf18c1ccf0f9f9f7 /service.c
parente0d721487a618490a7db06f76904868a71684071 (diff)
downloadunitd-86009b5439a898fa00cc27e675bb7834576be70a.tar
unitd-86009b5439a898fa00cc27e675bb7834576be70a.zip
add more instance state handling code
Diffstat (limited to 'service.c')
-rw-r--r--service.c114
1 files changed, 94 insertions, 20 deletions
diff --git a/service.c b/service.c
index f50daa7..360810e 100644
--- 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;
}