X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fjob.c;h=07d4fc3cc0fc236d136d047c2513db24c9de34d7;hb=78ff1acdfe6a1f50d4ac62dc354c667999be0508;hp=aa7cdbff2add4c3522c38641380d6dc95ea69521;hpb=e6eda1f23efab618bb26e7015230d8552b401dc6;p=elogind.git diff --git a/src/core/job.c b/src/core/job.c index aa7cdbff2..07d4fc3cc 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -33,6 +33,20 @@ #include "log.h" #include "dbus-job.h" +JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) { + JobBusClient *cl; + size_t name_len; + + name_len = strlen(name); + cl = malloc0(sizeof(JobBusClient) + name_len + 1); + if (!cl) + return NULL; + + cl->bus = connection; + memcpy(cl->name, name, name_len + 1); + return cl; +} + Job* job_new(Unit *unit, JobType type) { Job *j; @@ -54,22 +68,9 @@ Job* job_new(Unit *unit, JobType type) { return j; } -void job_uninstall(Job *j) { - assert(j->installed); - /* Detach from next 'bigger' objects */ - - bus_job_send_removed_signal(j); - - if (j->unit->job == j) { - j->unit->job = NULL; - unit_add_to_gc_queue(j->unit); - } - - hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); - j->installed = false; -} - void job_free(Job *j) { + JobBusClient *cl; + assert(j); assert(!j->installed); assert(!j->transaction_prev); @@ -92,10 +93,93 @@ void job_free(Job *j) { close_nointr_nofail(j->timer_watch.fd); } - free(j->bus_client); + while ((cl = j->bus_client_list)) { + LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl); + free(cl); + } free(j); } +void job_uninstall(Job *j) { + assert(j->installed); + assert(j->unit->job == j); + /* Detach from next 'bigger' objects */ + + bus_job_send_removed_signal(j); + + j->unit->job = NULL; + unit_add_to_gc_queue(j->unit); + + hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id)); + j->installed = false; +} + +static bool job_type_allows_late_merge(JobType t) { + /* Tells whether it is OK to merge a job of type 't' with an already + * running job. + * Reloads cannot be merged this way. Think of the sequence: + * 1. Reload of a daemon is in progress; the daemon has already loaded + * its config file, but hasn't completed the reload operation yet. + * 2. Edit foo's config file. + * 3. Trigger another reload to have the daemon use the new config. + * Should the second reload job be merged into the first one, the daemon + * would not know about the new config. + * JOB_RESTART jobs on the other hand can be merged, because they get + * patched into JOB_START after stopping the unit. So if we see a + * JOB_RESTART running, it means the unit hasn't stopped yet and at + * this time the merge is still allowed. */ + return !(t == JOB_RELOAD || t == JOB_RELOAD_OR_START); +} + +static void job_merge_into_installed(Job *j, Job *other) { + assert(j->installed); + assert(j->unit == other->unit); + + j->type = job_type_lookup_merge(j->type, other->type); + assert(j->type >= 0); + + j->override = j->override || other->override; +} + +Job* job_install(Job *j) { + Job *uj = j->unit->job; + + assert(!j->installed); + + if (uj) { + if (job_type_is_conflicting(uj->type, j->type)) + job_finish_and_invalidate(uj, JOB_CANCELED); + else { + /* not conflicting, i.e. mergeable */ + + if (uj->state == JOB_WAITING || + (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) { + job_merge_into_installed(uj, j); + log_debug("Merged into installed job %s/%s as %u", + uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); + return uj; + } else { + /* already running and not safe to merge into */ + /* Patch uj to become a merged job and re-run it. */ + /* XXX It should be safer to queue j to run after uj finishes, but it is + * not currently possible to have more than one installed job per unit. */ + job_merge_into_installed(uj, j); + log_debug("Merged into running job, re-running: %s/%s as %u", + uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id); + uj->state = JOB_WAITING; + return uj; + } + } + } + + /* Install the job */ + j->unit->job = j; + j->installed = true; + j->manager->n_installed_jobs ++; + log_debug("Installed new job %s/%s as %u", j->unit->id, job_type_to_string(j->type), (unsigned) j->id); + return j; +} + JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) { JobDependency *l; @@ -405,20 +489,20 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { case JOB_DONE: if (u->condition_result) - unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Started %s", unit_description(u)); + unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Started %s.", unit_description(u)); break; case JOB_FAILED: - unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s", unit_description(u)); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, "Failed to start %s.", unit_description(u)); unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id); break; case JOB_DEPENDENCY: - unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s", unit_description(u)); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " ABORT" ANSI_HIGHLIGHT_OFF, "Dependency failed. Aborted start of %s.", unit_description(u)); break; case JOB_TIMEOUT: - unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s", unit_description(u)); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out starting %s.", unit_description(u)); break; default: @@ -430,12 +514,12 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) { switch (result) { case JOB_TIMEOUT: - unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s", unit_description(u)); + unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, "Timed out stopping %s.", unit_description(u)); break; case JOB_DONE: case JOB_FAILED: - unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Stopped %s", unit_description(u)); + unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, "Stopped %s.", unit_description(u)); break; default: