chiark / gitweb /
core: add NOP jobs, job type collapsing
[elogind.git] / src / core / unit.c
index df79fe3a69f62517c4967bf83a156d9254674721..491ba3f33f846996e68b3f4925c80c7f59cd412a 100644 (file)
@@ -249,6 +249,9 @@ bool unit_check_gc(Unit *u) {
         if (u->job)
                 return true;
 
+        if (u->nop_job)
+                return true;
+
         if (unit_active_state(u) != UNIT_INACTIVE)
                 return true;
 
@@ -352,8 +355,17 @@ void unit_free(Unit *u) {
         SET_FOREACH(t, u->names, i)
                 hashmap_remove_value(u->manager->units, t, u);
 
-        if (u->job)
-                job_free(u->job);
+        if (u->job) {
+                Job *j = u->job;
+                job_uninstall(j);
+                job_free(j);
+        }
+
+        if (u->nop_job) {
+                Job *j = u->nop_job;
+                job_uninstall(j);
+                job_free(j);
+        }
 
         for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
                 bidi_set_free(u, u->dependencies[d]);
@@ -498,6 +510,9 @@ int unit_merge(Unit *u, Unit *other) {
         if (other->job)
                 return -EEXIST;
 
+        if (other->nop_job)
+                return -EEXIST;
+
         if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
                 return -EEXIST;
 
@@ -726,6 +741,9 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
         if (u->job)
                 job_dump(u->job, f, prefix2);
 
+        if (u->nop_job)
+                job_dump(u->nop_job, f, prefix2);
+
         free(p2);
 }
 
@@ -1223,12 +1241,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                 case JOB_VERIFY_ACTIVE:
 
                         if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
-                                job_finish_and_invalidate(u->job, JOB_DONE);
+                                job_finish_and_invalidate(u->job, JOB_DONE, true);
                         else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
                                 unexpected = true;
 
                                 if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                                        job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
+                                        job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
                         }
 
                         break;
@@ -1238,12 +1256,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
 
                         if (u->job->state == JOB_RUNNING) {
                                 if (ns == UNIT_ACTIVE)
-                                        job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED);
+                                        job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true);
                                 else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
                                         unexpected = true;
 
                                         if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                                                job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
+                                                job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
                                 }
                         }
 
@@ -1254,10 +1272,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                 case JOB_TRY_RESTART:
 
                         if (UNIT_IS_INACTIVE_OR_FAILED(ns))
-                                job_finish_and_invalidate(u->job, JOB_DONE);
+                                job_finish_and_invalidate(u->job, JOB_DONE, true);
                         else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
                                 unexpected = true;
-                                job_finish_and_invalidate(u->job, JOB_FAILED);
+                                job_finish_and_invalidate(u->job, JOB_FAILED, true);
                         }
 
                         break;
@@ -1504,6 +1522,7 @@ bool unit_job_is_applicable(Unit *u, JobType j) {
         case JOB_VERIFY_ACTIVE:
         case JOB_START:
         case JOB_STOP:
+        case JOB_NOP:
                 return true;
 
         case JOB_RESTART:
@@ -2285,8 +2304,15 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds) {
         if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0)
                 return r;
 
-        if (u->job)
-                unit_serialize_item(u, f, "job", job_type_to_string(u->job->type));
+        if (u->job) {
+                fprintf(f, "job\n");
+                job_serialize(u->job, f, fds);
+        }
+
+        if (u->nop_job) {
+                fprintf(f, "job\n");
+                job_serialize(u->nop_job, f, fds);
+        }
 
         dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
         dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp);
@@ -2365,13 +2391,38 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                         v = l+k;
 
                 if (streq(l, "job")) {
-                        JobType type;
+                        if (v[0] == '\0') {
+                                /* new-style serialized job */
+                                Job *j = job_new_raw(u);
+                                if (!j)
+                                        return -ENOMEM;
+
+                                r = job_deserialize(j, f, fds);
+                                if (r < 0) {
+                                        job_free(j);
+                                        return r;
+                                }
 
-                        if ((type = job_type_from_string(v)) < 0)
-                                log_debug("Failed to parse job type value %s", v);
-                        else
-                                u->deserialized_job = type;
+                                r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j);
+                                if (r < 0) {
+                                        job_free(j);
+                                        return r;
+                                }
 
+                                r = job_install_deserialized(j);
+                                if (r < 0) {
+                                        hashmap_remove(u->manager->jobs, UINT32_TO_PTR(j->id));
+                                        job_free(j);
+                                        return r;
+                                }
+                        } else {
+                                /* legacy */
+                                JobType type = job_type_from_string(v);
+                                if (type < 0)
+                                        log_debug("Failed to parse job type value %s", v);
+                                else
+                                        u->deserialized_job = type;
+                        }
                         continue;
                 } else if (streq(l, "inactive-exit-timestamp")) {
                         dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
@@ -2447,8 +2498,14 @@ int unit_coldplug(Unit *u) {
                 if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
                         return r;
 
-        if (u->deserialized_job >= 0) {
-                if ((r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL)) < 0)
+        if (u->job) {
+                r = job_coldplug(u->job);
+                if (r < 0)
+                        return r;
+        } else if (u->deserialized_job >= 0) {
+                /* legacy */
+                r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL);
+                if (r < 0)
                         return r;
 
                 u->deserialized_job = _JOB_TYPE_INVALID;