From: Lennart Poettering Date: Tue, 19 Jan 2010 03:15:20 +0000 (+0100) Subject: first try at implementing job creation X-Git-Tag: v1~845 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=11dd41ce4b465f6260ce68aa050a488f88f694eb;hp=42f4e3c4413ad35e3815f25211fee95d775488a7 first try at implementing job creation --- diff --git a/default.milestone b/default.milestone index 48f117139..c20a10e91 100644 --- a/default.milestone +++ b/default.milestone @@ -1,3 +1,4 @@ [Meta] -Wants=postfix.socket +Names=multiuser.milestone +Wants=postfix.socket syslog.socket Description=Default Milestone diff --git a/hashmap.c b/hashmap.c index 4db61732f..c55a07a88 100644 --- a/hashmap.c +++ b/hashmap.c @@ -106,12 +106,19 @@ void hashmap_free(Hashmap*h) { if (!h) return; - while (h->iterate_list_head) - remove_entry(h, h->iterate_list_head); + hashmap_clear(h); free(h); } +void hashmap_clear(Hashmap *h) { + if (!h) + return; + + while (h->iterate_list_head) + remove_entry(h, h->iterate_list_head); +} + static struct hashmap_entry *hash_scan(Hashmap *h, unsigned hash, const void *key) { struct hashmap_entry *e; assert(h); diff --git a/hashmap.h b/hashmap.h index e3b9d9aa3..91d8b46db 100644 --- a/hashmap.h +++ b/hashmap.h @@ -37,6 +37,7 @@ bool hashmap_isempty(Hashmap *h); void *hashmap_iterate(Hashmap *h, void **state, const void **key); void *hashmap_iterate_backwards(Hashmap *h, void **state, const void **key); +void hashmap_clear(Hashmap *h); void *hashmap_steal_first(Hashmap *h); void* hashmap_first(Hashmap *h); void* hashmap_last(Hashmap *h); @@ -44,6 +45,9 @@ void* hashmap_last(Hashmap *h); #define HASHMAP_FOREACH(e, h, state) \ for ((state) = NULL, (e) = hashmap_iterate((h), &(state), NULL); (e); (e) = hashmap_iterate((h), &(state), NULL)) +#define HASHMAP_FOREACH_KEY(e, k, h, state) \ + for ((state) = NULL, (e) = hashmap_iterate((h), &(state), (const void**) &(k)); (e); (e) = hashmap_iterate((h), &(state), (const void**) &(k))) + #define HASHMAP_FOREACH_BACKWARDS(e, h, state) \ for ((state) = NULL, (e) = hashmap_iterate_backwards((h), &(state), NULL); (e); (e) = hashmap_iterate_backwards((h), &(state), NULL)) diff --git a/job.c b/job.c index 2cf8be533..2f7912d26 100644 --- a/job.c +++ b/job.c @@ -25,31 +25,14 @@ Job* job_new(Manager *m, JobType type, Name *name) { return j; } -int job_link(Job *j) { - int r; - - assert(j); - assert(!j->linked); - - if ((r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j)) < 0) - return r; - - j->name->meta.job = j; - - j->linked = true; - - return 0; -} - void job_free(Job *j) { assert(j); /* Detach from next 'bigger' objects */ if (j->linked) { - assert(j->name); - assert(j->name->meta.job == j); - j->name->meta.job = NULL; + if (j->name->meta.job == j) + j->name->meta.job = NULL; hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); } @@ -82,7 +65,7 @@ void job_dump(Job *j, FILE*f) { assert(j); assert(f); - fprintf(f, "Job %u (%s) →%s in state %s\n", + fprintf(f, "Job %u (%s) → %s in state %s\n", j->id, name_id(j->name), job_type_table[j->type], diff --git a/job.h b/job.h index 0fc6fec46..0cb0a6e81 100644 --- a/job.h +++ b/job.h @@ -51,7 +51,6 @@ struct Job { }; Job* job_new(Manager *m, JobType type, Name *name); -int job_link(Job *job); void job_free(Job *job); void job_dump(Job *j, FILE*f); diff --git a/load-fragment.c b/load-fragment.c index d6b5e2f39..05a7114b4 100644 --- a/load-fragment.c +++ b/load-fragment.c @@ -111,6 +111,8 @@ static int config_parse_names( free(t); return r; } + + t = NULL; } free(t); diff --git a/main.c b/main.c index f19fb6b5c..a5c169454 100644 --- a/main.c +++ b/main.c @@ -23,12 +23,13 @@ int main(int argc, char *argv[]) { goto finish; } - manager_dump_names(m, stdout); - /* if ((r = manager_add_job(m, JOB_START, milestone, JOB_REPLACE, &job)) < 0) { */ - /* fprintf(stderr, "Failed to start default milestone: %s\n", strerror(-r)); */ - /* goto finish; */ - /* } */ + if ((r = manager_add_job(m, JOB_START, milestone, JOB_REPLACE, &job)) < 0) { + fprintf(stderr, "Failed to start default milestone: %s\n", strerror(-r)); + goto finish; + } + + manager_dump_names(m, stdout); retval = 0; diff --git a/manager.c b/manager.c index 86ed086eb..d2708aacf 100644 --- a/manager.c +++ b/manager.c @@ -54,6 +54,58 @@ void manager_free(Manager *m) { free(m); } +static void transaction_abort(Manager *m) { + Job *j; + + assert(m); + assert(m->n_dependency_depth == 0); + + while ((j = hashmap_steal_first(m->jobs_to_add))) + job_free(j); + + set_clear(m->jobs_to_remove); +} + +static int transaction_activate(Manager *m) { + Job *j; + int r; + void *state; + + assert(m); + assert(m->n_dependency_depth == 0); + + /* This applies the changes recorded in jobs_to_add and + * jobs_to_remove to the actual list of jobs */ + + HASHMAP_FOREACH(j, m->jobs_to_add, state) { + assert(!j->linked); + + if ((r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j)) < 0) + goto rollback; + } + + /* all entries are now registered, now make sure the names + * know about that. */ + + while ((j = hashmap_steal_first(m->jobs_to_add))) { + j->name->meta.job = j; + j->linked = true; + } + + while ((j = set_steal_first(m->jobs_to_remove))) + job_free(j); + + return 0; + +rollback: + + HASHMAP_FOREACH(j, m->jobs_to_add, state) + hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); + + transaction_abort(m); + return r; +} + int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_ret) { Job *ret, *other; void *state; @@ -64,7 +116,6 @@ int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_r assert(type < _JOB_TYPE_MAX); assert(name); assert(mode < _JOB_MODE_MAX); - assert(_ret); /* Check for conflicts, first against the jobs we shall * create */ @@ -88,6 +139,8 @@ int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_r if (!(ret = job_new(m, type, name))) return -ENOMEM; + m->n_dependency_depth ++; + if ((r = hashmap_put(m->jobs_to_add, name, ret)) < 0) goto fail; @@ -118,6 +171,13 @@ int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_r goto fail; } + if (--m->n_dependency_depth <= 0) + if ((r = transaction_activate(m)) < 0) { + transaction_abort(m); + return r; + } + + if (_ret) *_ret = ret; @@ -126,6 +186,9 @@ int manager_add_job(Manager *m, JobType type, Name *name, JobMode mode, Job **_r fail: job_free(ret); + if (--m->n_dependency_depth <= 0) + transaction_abort(m); + return r; } @@ -251,6 +314,9 @@ finish: if ((r = name_load_dropin(name)) < 0) return r; + if ((r = name_link_names(name)) < 0) + return r; + name->meta.state = NAME_LOADED; return 0; } @@ -348,10 +414,12 @@ void manager_dump_jobs(Manager *s, FILE *f) { void manager_dump_names(Manager *s, FILE *f) { void *state; Name *n; + const char *t; assert(s); assert(f); - HASHMAP_FOREACH(n, s->names, state) - name_dump(n, f); + HASHMAP_FOREACH_KEY(n, t, s->names, state) + if (name_id(n) == t) + name_dump(n, f); } diff --git a/manager.h b/manager.h index c08f3ccde..3ee3b0ac5 100644 --- a/manager.h +++ b/manager.h @@ -34,6 +34,8 @@ struct Manager { Set *jobs_to_remove; bool dispatching_load_queue:1; + + unsigned n_dependency_depth; }; Manager* manager_new(void); diff --git a/name.c b/name.c index cbd847a91..0ef7a77ff 100644 --- a/name.c +++ b/name.c @@ -80,31 +80,55 @@ Name *name_new(Manager *m) { return n; } +int name_link_names(Name *n) { + char *t; + void *state; + int r; + + assert(n); + + if (!n->meta.linked) + return 0; + + /* Link all names that aren't linked yet */ + + SET_FOREACH(t, n->meta.names, state) + if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0) { + + if (r == -EEXIST && hashmap_get(n->meta.manager->names, t) == n) + continue; + + return r; + } + + return 0; +} + int name_link(Name *n) { - char **t; int r; - void *state; assert(n); assert(!set_isempty(n->meta.names)); assert(!n->meta.linked); - SET_FOREACH(t, n->meta.names, state) - if ((r = hashmap_put(n->meta.manager->names, t, n)) < 0) - goto fail; + n->meta.linked = true; - if (n->meta.state == NAME_STUB) - LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta); + if ((r = name_link_names(n) < 0)) { + char *t; + void *state; - n->meta.linked = true; + /* Rollback the registered names */ + SET_FOREACH(t, n->meta.names, state) + hashmap_remove(n->meta.manager->names, t); - return 0; + n->meta.linked = false; + return r; + } -fail: - SET_FOREACH(t, n->meta.names, state) - assert_se(hashmap_remove(n->meta.manager->names, t) == n); + if (n->meta.state == NAME_STUB) + LIST_PREPEND(Meta, n->meta.manager->load_queue, &n->meta); - return r; + return 0; } static void bidi_set_free(Name *name, Set *s) { @@ -134,7 +158,7 @@ void name_free(Name *name) { /* Detach from next 'bigger' objects */ if (name->meta.linked) { - char **t; + char *t; void *state; SET_FOREACH(t, name->meta.names, state) @@ -357,6 +381,10 @@ int name_merge(Name *name, Name *other) { if ((r = ensure_merge(&name->meta.dependencies[d], other->meta.dependencies[d])) < 0) return r; + if (name->meta.linked) + if ((r = name_link_names(name)) < 0) + return r; + return 0; } @@ -388,14 +416,24 @@ void name_dump(Name *n, FILE *f) { [SOCKET_MAINTAINANCE] = "maintainance" }; + void *state; + char *t; + assert(n); - fprintf(stderr, - "Name %s (\"%s\") in state %s\n", + fprintf(f, + "Name %s\n" + "\tDescription: %s\n" + "\tState: %s\n", name_id(n), n->meta.description ? n->meta.description : name_id(n), state_table[n->meta.state]); + fprintf(f, "\tNames: "); + SET_FOREACH(t, n->meta.names, state) + fprintf(f, "%s ", t); + fprintf(f, "\n"); + switch (n->meta.type) { case NAME_SOCKET: { int r; @@ -407,7 +445,7 @@ void name_dump(Name *n, FILE *f) { else t = s; - fprintf(stderr, "\t%s in state %s\n", t, socket_state_table[n->socket.state]); + fprintf(f, "\t%s in state %s\n", t, socket_state_table[n->socket.state]); free(s); break; } @@ -417,7 +455,7 @@ void name_dump(Name *n, FILE *f) { } if (n->meta.job) { - fprintf(f, "\t▶ "); + fprintf(f, "\t"); job_dump(n->meta.job, f); } } diff --git a/name.h b/name.h index 0ed105659..67ca6f10e 100644 --- a/name.h +++ b/name.h @@ -279,6 +279,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_link_names(Name *name); int name_merge(Name *name, Name *other); int name_augment(Name *n); const char* name_id(Name *n); diff --git a/postfix.socket b/postfix.socket index da5b09312..8f9c0e8aa 100644 --- a/postfix.socket +++ b/postfix.socket @@ -1,5 +1,5 @@ [Meta] -Description=Postfix Listening Socket +Description=Postfix SMTP Socket [Socket] Listen=25 diff --git a/set.c b/set.c index 21a1739b0..74137b775 100644 --- a/set.c +++ b/set.c @@ -69,3 +69,7 @@ int set_merge(Set *s, Set *other) { Set* set_copy(Set *s) { return MAKE_SET(hashmap_copy(MAKE_HASHMAP(s))); } + +void set_clear(Set *s) { + hashmap_clear(MAKE_HASHMAP(s)); +} diff --git a/set.h b/set.h index a2e405941..b206ba80f 100644 --- a/set.h +++ b/set.h @@ -29,6 +29,7 @@ bool set_isempty(Set *s); void *set_iterate(Set *s, void **state); void *set_iterate_backwards(Set *s, void **state); +void set_clear(Set *s); void *set_steal_first(Set *s); void* set_first(Set *s); void* set_last(Set *s); diff --git a/syslog.socket b/syslog.socket index 3d5fa818a..b599762e7 100644 --- a/syslog.socket +++ b/syslog.socket @@ -1,2 +1,6 @@ +[Meta] +Description=Syslog Socket + [Socket] Listen=/dev/log +Type=dgram