summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-01-18 23:50:13 +0100
committerLennart Poettering <lennart@poettering.net>2010-01-18 23:50:13 +0100
commit87d1515de5ae611e95144def9ef4b2c0c933f6fe (patch)
tree4cdeceee70826dffd460775aaddbea8e60e51eaa
parent91cdde8a7a08c6797995cc67f4b55ac43780cdd8 (diff)
first try at implementing dependency loader
-rw-r--r--job.c9
-rw-r--r--load-fragment.c105
-rw-r--r--manager.c40
-rw-r--r--manager.h4
-rw-r--r--name.c140
-rw-r--r--name.h35
6 files changed, 244 insertions, 89 deletions
diff --git a/job.c b/job.c
index 5cd8f73a9..689908aeb 100644
--- a/job.c
+++ b/job.c
@@ -47,13 +47,16 @@ void job_free(Job *j) {
/* Detach from next 'bigger' objects */
if (j->linked) {
- if (j->name && j->name->meta.job == j)
- j->name->meta.job = NULL;
+ assert(j->name);
+ assert(j->name->meta.job == j);
+ j->name->meta.job = NULL;
hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
}
- /* Free data and next 'smaller' objects */
+ hashmap_remove(j->manager->jobs_to_add, j->name);
+ set_remove(j->manager->jobs_to_remove, j);
+ /* Free data and next 'smaller' objects */
free(j);
}
diff --git a/load-fragment.c b/load-fragment.c
index b5b3e4862..4510cc916 100644
--- a/load-fragment.c
+++ b/load-fragment.c
@@ -9,7 +9,7 @@
#include "conf-parser.h"
#include "load-fragment.h"
-int config_parse_names(
+int config_parse_deps(
const char *filename,
unsigned line,
const char *section,
@@ -54,41 +54,100 @@ int config_parse_names(
return 0;
}
+int config_parse_names(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Set **set = data;
+ Name *name = userdata;
+ char *w;
+ size_t l;
+ char *state;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ FOREACH_WORD(w, &l, rvalue, state) {
+ char *t;
+ int r;
+ Name *other;
+
+ if (!(t = strndup(w, l)))
+ return -ENOMEM;
+
+ other = manager_get_name(name->meta.manager, t);
+
+ if (other) {
+
+ if (other != name) {
+
+ if (other->meta.state != NAME_STUB) {
+ free(t);
+ return -EEXIST;
+ }
+
+ if ((r = name_merge(name, other) < 0)) {
+ free(t);
+ return r;
+ }
+ }
+
+ } else {
+
+ if (!*set)
+ if (!(*set = set_new(trivial_hash_func, trivial_compare_func))) {
+ free(t);
+ return -ENOMEM;
+ }
+
+ if ((r = set_put(*set, t)) < 0) {
+ free(t);
+ return r;
+ }
+ }
+
+ free(t);
+ }
+
+ return 0;
+}
+
int name_load_fragment(Name *n) {
const ConfigItem items[] = {
- { "Names", config_parse_strv, &n->meta.names, "Meta" },
- { "Description", config_parse_string, &n->meta.description, "Meta" },
- { "Requires", config_parse_names, &n->meta.requires, "Meta" },
- { "SoftRequires", config_parse_names, &n->meta.soft_requires, "Meta" },
- { "Wants", config_parse_names, &n->meta.wants, "Meta" },
- { "Requisite", config_parse_names, &n->meta.requisite, "Meta" },
- { "SoftRequisite", config_parse_names, &n->meta.soft_requisite, "Meta" },
- { "Conflicts", config_parse_names, &n->meta.conflicts, "Meta" },
- { "Before", config_parse_names, &n->meta.before, "Meta" },
- { "After", config_parse_names, &n->meta.after, "Meta" },
+ { "Names", config_parse_names, &n->meta.names, "Meta" },
+ { "Description", config_parse_string, &n->meta.description, "Meta" },
+ { "Requires", config_parse_deps, n->meta.dependencies+NAME_REQUIRES, "Meta" },
+ { "SoftRequires", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUIRES, "Meta" },
+ { "Wants", config_parse_deps, n->meta.dependencies+NAME_WANTS, "Meta" },
+ { "Requisite", config_parse_deps, n->meta.dependencies+NAME_REQUISITE, "Meta" },
+ { "SoftRequisite", config_parse_deps, n->meta.dependencies+NAME_SOFT_REQUISITE, "Meta" },
+ { "Conflicts", config_parse_deps, n->meta.dependencies+NAME_CONFLICTS, "Meta" },
+ { "Before", config_parse_deps, n->meta.dependencies+NAME_BEFORE, "Meta" },
+ { "After", config_parse_deps, n->meta.dependencies+NAME_AFTER, "Meta" },
{ NULL, NULL, NULL, NULL }
};
- char **t, **l;
+ char *t;
int r;
+ void *state;
assert(n);
assert(n->meta.state == NAME_STUB);
- /* We copy the strv here so that we can iterate through it
- * while being safe for modification */
- if (!(l = strv_copy(n->meta.names)))
- return -ENOMEM;
-
- STRV_FOREACH(t, n->meta.names)
- if ((r = config_parse(*t, items, n)) < 0)
+ SET_FOREACH(t, n->meta.names, state)
+ if ((r = config_parse(t, items, n)) < 0)
goto fail;
- return 0;
+ r = 0;
fail:
-
- strv_free(l);
- return 0;
+ return r;
}
diff --git a/manager.c b/manager.c
index 97c99e504..0ad60b2b0 100644
--- a/manager.c
+++ b/manager.c
@@ -2,6 +2,7 @@
#include <assert.h>
#include <errno.h>
+#include <string.h>
#include "manager.h"
#include "hashmap.h"
@@ -91,28 +92,28 @@ int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_r
goto fail;
if (type == JOB_START || type == JOB_VERIFY_STARTED || type == JOB_RESTART_FINISH) {
- SET_FOREACH(dep, ret->name->meta.requires, state)
+ SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUIRES], state)
if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
goto fail;
- SET_FOREACH(dep, ret->name->meta.soft_requires, state)
+ SET_FOREACH(dep, ret->name->meta.dependencies[NAME_SOFT_REQUIRES], state)
if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0)
goto fail;
- SET_FOREACH(dep, ret->name->meta.wants, state)
+ SET_FOREACH(dep, ret->name->meta.dependencies[NAME_WANTS], state)
if ((r = manager_add_job(m, type, dep, JOB_FAIL, NULL)) < 0)
goto fail;
- SET_FOREACH(dep, ret->name->meta.requisite, state)
+ SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUISITE], state)
if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, mode, NULL)) < 0)
goto fail;
- SET_FOREACH(dep, ret->name->meta.soft_requisite, state)
+ SET_FOREACH(dep, ret->name->meta.dependencies[NAME_SOFT_REQUISITE], state)
if ((r = manager_add_job(m, JOB_VERIFY_STARTED, dep, JOB_FAIL, NULL)) < 0)
goto fail;
- SET_FOREACH(dep, ret->name->meta.conflicts, state)
+ SET_FOREACH(dep, ret->name->meta.dependencies[NAME_CONFLICTS], state)
if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
goto fail;
} else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
- SET_FOREACH(dep, ret->name->meta.required_by, state)
+ SET_FOREACH(dep, ret->name->meta.dependencies[NAME_REQUIRED_BY], state)
if ((r = manager_add_job(m, type, dep, mode, NULL)) < 0)
goto fail;
}
@@ -142,17 +143,18 @@ Name *manager_get_name(Manager *m, const char *name) {
return hashmap_get(m->names, name);
}
-static int detect_type(Name *name) {
- char **n;
+static int verify_type(Name *name) {
+ char *n;
+ void *state;
assert(name);
- name->meta.type = _NAME_TYPE_INVALID;
+ /* Checks that all aliases of this name have the same and valid type */
- STRV_FOREACH(n, name->meta.names) {
+ SET_FOREACH(n, name->meta.names, state) {
NameType t;
- if ((t = name_type_from_string(*n)) == _NAME_TYPE_INVALID)
+ if ((t = name_type_from_string(n)) == _NAME_TYPE_INVALID)
return -EINVAL;
if (name->meta.type == _NAME_TYPE_INVALID) {
@@ -164,6 +166,9 @@ static int detect_type(Name *name) {
return -EINVAL;
}
+ if (name->meta.type == _NAME_TYPE_INVALID)
+ return -EINVAL;
+
return 0;
}
@@ -209,7 +214,7 @@ static int load(Name *name) {
if (name->meta.state != NAME_STUB)
return 0;
- if ((r = detect_type(name)) < 0)
+ if ((r = verify_type(name)) < 0)
return r;
if (name->meta.type == NAME_SERVICE) {
@@ -278,6 +283,7 @@ int manager_load_name(Manager *m, const char *name, Name **_ret) {
Name *ret;
NameType t;
int r;
+ char *n;
assert(m);
assert(name);
@@ -300,8 +306,14 @@ int manager_load_name(Manager *m, const char *name, Name **_ret) {
ret->meta.type = t;
- if (!(ret->meta.names = strv_new(name, NULL))) {
+ if (!(n = strdup(name))) {
+ name_free(ret);
+ return -ENOMEM;
+ }
+
+ if (set_put(ret->meta.names, n) < 0) {
name_free(ret);
+ free(n);
return -ENOMEM;
}
diff --git a/manager.h b/manager.h
index 9cd131d5a..64c4c9d14 100644
--- a/manager.h
+++ b/manager.h
@@ -17,6 +17,10 @@ typedef struct Manager Manager;
struct Manager {
uint32_t current_job_id;
+ /* Note that the set of names we know of is allowed to be
+ * incosistent. However the subset of it that is loaded may
+ * not, and the list of jobs may neither. */
+
/* Active jobs and names */
Hashmap *names; /* name string => Name object n:1 */
Hashmap *jobs; /* job id => Job object 1:1 */
diff --git a/name.c b/name.c
index 15e324c5f..f29ce2298 100644
--- a/name.c
+++ b/name.c
@@ -65,6 +65,11 @@ Name *name_new(Manager *m) {
if (!(n = new0(Name, 1)))
return NULL;
+ if (!(n->meta.names = set_new(string_hash_func, string_compare_func))) {
+ free(n);
+ return NULL;
+ }
+
/* Not much initialization happening here at this time */
n->meta.manager = m;
n->meta.type = _NAME_TYPE_INVALID;
@@ -78,12 +83,14 @@ Name *name_new(Manager *m) {
int name_link(Name *n) {
char **t;
int r;
+ void *state;
assert(n);
+ assert(!set_isempty(n->meta.names));
assert(!n->meta.linked);
- STRV_FOREACH(t, n->meta.names)
- if ((r = hashmap_put(n->meta.manager->names, *t, n)) < 0)
+ SET_FOREACH(t, n->meta.names, state)
+ if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0)
goto fail;
if (n->meta.state == NAME_STUB)
@@ -94,43 +101,56 @@ int name_link(Name *n) {
return 0;
fail:
- t--;
- STRV_FOREACH_BACKWARDS(t, n->meta.names)
- hashmap_remove(n->meta.manager->names, *t);
+ SET_FOREACH(t, n->meta.names, state)
+ assert_se(hashmap_remove(n->meta.manager->names, t) == n);
return r;
}
+static void bidi_set_free(Name *name, Set *s) {
+ void *state;
+ Name *other;
+
+ assert(name);
+ assert(s);
+
+ /* Frees the set and makes sure we are dropped from the
+ * inverse pointers */
+
+ SET_FOREACH(other, s, state) {
+ NameDependency d;
+
+ for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
+ set_remove(other->meta.dependencies[d], name);
+ }
+
+ set_free(s);
+}
+
void name_free(Name *name) {
+ NameDependency d;
+ char *t;
assert(name);
/* Detach from next 'bigger' objects */
-
if (name->meta.linked) {
char **t;
+ void *state;
- STRV_FOREACH(t, name->meta.names)
- hashmap_remove(name->meta.manager->names, *t);
+ SET_FOREACH(t, name->meta.names, state)
+ assert_se(hashmap_remove(name->meta.manager->names, t) == name);
- if (name->meta.job)
- job_free(name->meta.job);
+ if (name->meta.state == NAME_STUB)
+ LIST_REMOVE(Meta, name->meta.manager->load_queue, &name->meta);
}
/* Free data and next 'smaller' objects */
-
if (name->meta.job)
job_free(name->meta.job);
- /* FIXME: Other names pointing to us should probably drop their refs to us when we get destructed */
- set_free(name->meta.requires);
- set_free(name->meta.soft_requires);
- set_free(name->meta.wants);
- set_free(name->meta.requisite);
- set_free(name->meta.soft_requires);
- set_free(name->meta.conflicts);
- set_free(name->meta.before);
- set_free(name->meta.after);
+ for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
+ bidi_set_free(name, name->meta.dependencies[d]);
switch (name->meta.type) {
@@ -169,7 +189,10 @@ void name_free(Name *name) {
}
free(name->meta.description);
- strv_free(name->meta.names);
+
+ while ((t = set_steal_first(name->meta.names)))
+ free(t);
+ set_free(name->meta.names);
free(name);
}
@@ -264,31 +287,76 @@ int name_augment(Name *n) {
assert(n);
- /* Adds in the missing links to make all dependencies both-ways */
+ /* Adds in the missing links to make all dependencies bidirectional */
- SET_FOREACH(other, n->meta.before, state)
- if ((r = ensure_in_set(&other->meta.after, n) < 0))
+ SET_FOREACH(other, n->meta.dependencies[NAME_BEFORE], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_AFTER], n) < 0))
return r;
- SET_FOREACH(other, n->meta.after, state)
- if ((r = ensure_in_set(&other->meta.before, n) < 0))
+ SET_FOREACH(other, n->meta.dependencies[NAME_AFTER], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_BEFORE], n) < 0))
return r;
- SET_FOREACH(other, n->meta.conflicts, state)
- if ((r = ensure_in_set(&other->meta.conflicts, n) < 0))
+ SET_FOREACH(other, n->meta.dependencies[NAME_CONFLICTS], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_CONFLICTS], n) < 0))
return r;
- SET_FOREACH(other, n->meta.requires, state)
- if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+ SET_FOREACH(other, n->meta.dependencies[NAME_REQUIRES], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n) < 0))
return r;
- SET_FOREACH(other, n->meta.soft_requires, state)
- if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+ SET_FOREACH(other, n->meta.dependencies[NAME_REQUISITE], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_REQUIRED_BY], n) < 0))
return r;
- SET_FOREACH(other, n->meta.requisite, state)
- if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+
+ SET_FOREACH(other, n->meta.dependencies[NAME_WANTS], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0))
return r;
- SET_FOREACH(other, n->meta.soft_requisite, state)
- if ((r = ensure_in_set(&other->meta.required_by, n) < 0))
+ SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUIRES], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0))
+ return r;
+ SET_FOREACH(other, n->meta.dependencies[NAME_SOFT_REQUISITE], state)
+ if ((r = ensure_in_set(&other->meta.dependencies[NAME_WANTED_BY], n) < 0))
return r;
return r;
}
+
+static int ensure_merge(Set **s, Set *other) {
+
+ if (!other)
+ return 0;
+
+ if (*s)
+ return set_merge(*s, other);
+
+ if (!(*s = set_copy(other)))
+ return -ENOMEM;
+
+ return 0;
+}
+
+int name_merge(Name *name, Name *other) {
+ int r;
+ NameDependency d;
+
+ assert(name);
+ assert(other);
+
+ assert(name->meta.manager == other->meta.manager);
+
+ if (name->meta.type != other->meta.type)
+ return -EINVAL;
+
+ if (other->meta.state != NAME_STUB)
+ return -EINVAL;
+
+ /* Merge names */
+ if ((r = ensure_merge(&name->meta.names, other->meta.names)) < 0)
+ return r;
+
+ /* Merge dependencies */
+ for (d = 0; d < _NAME_DEPENDENCY_MAX; d++)
+ if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0)
+ return r;
+
+ return 0;
+}
diff --git a/name.h b/name.h
index 062c95aa1..696953108 100644
--- a/name.h
+++ b/name.h
@@ -42,24 +42,33 @@ typedef enum NameState {
NAME_FAILED
} NameState;
-struct Meta {
- Manager *manager;
- NameType type;
- NameState state;
-
- char **names;
-
+typedef enum NameDependency {
/* Positive dependencies */
- Set *requires, *soft_requires, *wants, *requisite, *soft_requisite;
- Set *required_by; /* inverse of 'requires', 'soft_requires', 'requisite' and 'soft_requisite' is 'required_by' */
+ NAME_REQUIRES,
+ NAME_SOFT_REQUIRES,
+ NAME_WANTS,
+ NAME_REQUISITE,
+ NAME_SOFT_REQUISITE,
+ NAME_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */
+ NAME_WANTED_BY, /* inverse of 'wants', 'soft_requires' and 'soft_requisite' is 'wanted_by' */
/* Negative dependencies */
- Set *conflicts; /* inverse of 'conflicts' is 'conflicts' */
+ NAME_CONFLICTS, /* inverse of 'conflicts' is 'conflicts' */
/* Order */
- Set *before, *after; /* inverse of before is after and vice versa */
+ NAME_BEFORE, /* inverse of before is after and vice versa */
+ NAME_AFTER,
+ _NAME_DEPENDENCY_MAX
+} NameDependency;
+
+struct Meta {
+ Manager *manager;
+ NameType type;
+ NameState state;
+
+ Set *names;
+ Set *dependencies[_NAME_DEPENDENCY_MAX];
- /* Information */
char *description;
/* If there is something to do with this name, then this is
@@ -265,7 +274,7 @@ bool name_is_valid(const char *n);
Name *name_new(Manager *m);
void name_free(Name *name);
int name_link(Name *name);
-
+int name_merge(Name *name, Name *other);
int name_augment(Name *n);
#endif