]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/job.c
Merge pull request #20030 from keszybz/exec_fd-event-source
[thirdparty/systemd.git] / src / core / job.c
index c0bb188b450654d8778b429f81546d1def091bd0..afe0985ce186fa17090a5f630257dbd78e3e6295 100644 (file)
@@ -455,7 +455,6 @@ int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
 
 static bool job_is_runnable(Job *j) {
         Unit *other;
-        void *v;
 
         assert(j);
         assert(j->installed);
@@ -477,16 +476,16 @@ static bool job_is_runnable(Job *j) {
         if (j->type == JOB_NOP)
                 return true;
 
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER])
-                if (other->job && job_compare(j, other->job, UNIT_AFTER) > 0) {
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_AFTER)
+                if (other->job && job_compare(j, other->job, UNIT_ATOM_AFTER) > 0) {
                         log_unit_debug(j->unit,
                                        "starting held back, waiting for: %s",
                                        other->id);
                         return false;
                 }
 
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE])
-                if (other->job && job_compare(j, other->job, UNIT_BEFORE) > 0) {
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_BEFORE)
+                if (other->job && job_compare(j, other->job, UNIT_ATOM_BEFORE) > 0) {
                         log_unit_debug(j->unit,
                                        "stopping held back, waiting for: %s",
                                        other->id);
@@ -951,13 +950,12 @@ static void job_emit_done_status_message(Unit *u, uint32_t job_id, JobType t, Jo
         job_print_done_status_message(u, t, result);
 }
 
-static void job_fail_dependencies(Unit *u, UnitDependency d) {
+static void job_fail_dependencies(Unit *u, UnitDependencyAtom match_atom) {
         Unit *other;
-        void *v;
 
         assert(u);
 
-        HASHMAP_FOREACH_KEY(v, other, u->dependencies[d]) {
+        UNIT_FOREACH_DEPENDENCY(other, u, match_atom) {
                 Job *j = other->job;
 
                 if (!j)
@@ -970,10 +968,8 @@ static void job_fail_dependencies(Unit *u, UnitDependency d) {
 }
 
 int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool already) {
-        Unit *u;
-        Unit *other;
+        Unit *u, *other;
         JobType t;
-        void *v;
 
         assert(j);
         assert(j->installed);
@@ -1012,43 +1008,36 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
 
         /* Fail depending jobs on failure */
         if (result != JOB_DONE && recursive) {
-                if (IN_SET(t, JOB_START, JOB_VERIFY_ACTIVE)) {
-                        job_fail_dependencies(u, UNIT_REQUIRED_BY);
-                        job_fail_dependencies(u, UNIT_REQUISITE_OF);
-                        job_fail_dependencies(u, UNIT_BOUND_BY);
-                } else if (t == JOB_STOP)
-                        job_fail_dependencies(u, UNIT_CONFLICTED_BY);
+                if (IN_SET(t, JOB_START, JOB_VERIFY_ACTIVE))
+                        job_fail_dependencies(u, UNIT_ATOM_PROPAGATE_START_FAILURE);
+                else if (t == JOB_STOP)
+                        job_fail_dependencies(u, UNIT_ATOM_PROPAGATE_STOP_FAILURE);
         }
 
-        /* A special check to make sure we take down anything RequisiteOf if we
-         * aren't active. This is when the verify-active job merges with a
-         * satisfying job type, and then loses it's invalidation effect, as the
-         * result there is JOB_DONE for the start job we merged into, while we
-         * should be failing the depending job if the said unit isn't in fact
-         * active. Oneshots are an example of this, where going directly from
-         * activating to inactive is success.
+        /* A special check to make sure we take down anything RequisiteOf= if we aren't active. This is when
+         * the verify-active job merges with a satisfying job type, and then loses it's invalidation effect,
+         * as the result there is JOB_DONE for the start job we merged into, while we should be failing the
+         * depending job if the said unit isn't in fact active. Oneshots are an example of this, where going
+         * directly from activating to inactive is success.
          *
-         * This happens when you use ConditionXYZ= in a unit too, since in that
-         * case the job completes with the JOB_DONE result, but the unit never
-         * really becomes active. Note that such a case still involves merging:
+         * This happens when you use ConditionXYZ= in a unit too, since in that case the job completes with
+         * the JOB_DONE result, but the unit never really becomes active. Note that such a case still
+         * involves merging:
          *
-         * A start job waits for something else, and a verify-active comes in
-         * and merges in the installed job. Then, later, when it becomes
-         * runnable, it finishes with JOB_DONE result as execution on conditions
-         * not being met is skipped, breaking our dependency semantics.
+         * A start job waits for something else, and a verify-active comes in and merges in the installed
+         * job. Then, later, when it becomes runnable, it finishes with JOB_DONE result as execution on
+         * conditions not being met is skipped, breaking our dependency semantics.
          *
-         * Also, depending on if start job waits or not, the merging may or may
-         * not happen (the verify-active job may trigger after it finishes), so
-         * you get undeterministic results without this check.
+         * Also, depending on if start job waits or not, the merging may or may not happen (the verify-active
+         * job may trigger after it finishes), so you get undeterministic results without this check.
          */
-        if (result == JOB_DONE && recursive && !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
-                if (IN_SET(t, JOB_START, JOB_RELOAD))
-                        job_fail_dependencies(u, UNIT_REQUISITE_OF);
-        }
-        /* Trigger OnFailure dependencies that are not generated by
-         * the unit itself. We don't treat JOB_CANCELED as failure in
-         * this context. And JOB_FAILURE is already handled by the
-         * unit itself. */
+        if (result == JOB_DONE && recursive &&
+            IN_SET(t, JOB_START, JOB_RELOAD) &&
+            !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
+                job_fail_dependencies(u, UNIT_ATOM_PROPAGATE_INACTIVE_START_AS_FAILURE);
+
+        /* Trigger OnFailure= dependencies that are not generated by the unit itself. We don't treat
+         * JOB_CANCELED as failure in this context. And JOB_FAILURE is already handled by the unit itself. */
         if (IN_SET(result, JOB_TIMEOUT, JOB_DEPENDENCY)) {
                 log_unit_struct(u, LOG_NOTICE,
                                 "JOB_TYPE=%s", job_type_to_string(t),
@@ -1058,19 +1047,19 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
                                                  job_type_to_string(t),
                                                  job_result_to_string(result)));
 
-                unit_start_on_failure(u);
+                unit_start_on_failure(u, "OnFailure=", UNIT_ATOM_ON_FAILURE, u->on_failure_job_mode);
         }
 
         unit_trigger_notify(u);
 
 finish:
         /* Try to start the next jobs that can be started */
-        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_AFTER])
+        UNIT_FOREACH_DEPENDENCY(other, u, UNIT_ATOM_AFTER)
                 if (other->job) {
                         job_add_to_run_queue(other->job);
                         job_add_to_gc_queue(other->job);
                 }
-        HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BEFORE])
+        UNIT_FOREACH_DEPENDENCY(other, u, UNIT_ATOM_BEFORE)
                 if (other->job) {
                         job_add_to_run_queue(other->job);
                         job_add_to_gc_queue(other->job);
@@ -1420,7 +1409,6 @@ int job_get_timeout(Job *j, usec_t *timeout) {
 
 bool job_may_gc(Job *j) {
         Unit *other;
-        void *v;
 
         assert(j);
 
@@ -1449,12 +1437,12 @@ bool job_may_gc(Job *j) {
                 return false;
 
         /* The logic is inverse to job_is_runnable, we cannot GC as long as we block any job. */
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE])
-                if (other->job && job_compare(j, other->job, UNIT_BEFORE) < 0)
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_BEFORE)
+                if (other->job && job_compare(j, other->job, UNIT_ATOM_BEFORE) < 0)
                         return false;
 
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER])
-                if (other->job && job_compare(j, other->job, UNIT_AFTER) < 0)
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_AFTER)
+                if (other->job && job_compare(j, other->job, UNIT_ATOM_AFTER) < 0)
                         return false;
 
         return true;
@@ -1498,9 +1486,8 @@ static size_t sort_job_list(Job **list, size_t n) {
 
 int job_get_before(Job *j, Job*** ret) {
         _cleanup_free_ Job** list = NULL;
-        size_t n = 0, n_allocated = 0;
         Unit *other = NULL;
-        void *v;
+        size_t n = 0;
 
         /* Returns a list of all pending jobs that need to finish before this job may be started. */
 
@@ -1512,24 +1499,24 @@ int job_get_before(Job *j, Job*** ret) {
                 return 0;
         }
 
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER]) {
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_AFTER) {
                 if (!other->job)
                         continue;
-                if (job_compare(j, other->job, UNIT_AFTER) <= 0)
+                if (job_compare(j, other->job, UNIT_ATOM_AFTER) <= 0)
                         continue;
 
-                if (!GREEDY_REALLOC(list, n_allocated, n+1))
+                if (!GREEDY_REALLOC(list, n+1))
                         return -ENOMEM;
                 list[n++] = other->job;
         }
 
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE]) {
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_BEFORE) {
                 if (!other->job)
                         continue;
-                if (job_compare(j, other->job, UNIT_BEFORE) <= 0)
+                if (job_compare(j, other->job, UNIT_ATOM_BEFORE) <= 0)
                         continue;
 
-                if (!GREEDY_REALLOC(list, n_allocated, n+1))
+                if (!GREEDY_REALLOC(list, n+1))
                         return -ENOMEM;
                 list[n++] = other->job;
         }
@@ -1543,41 +1530,40 @@ int job_get_before(Job *j, Job*** ret) {
 
 int job_get_after(Job *j, Job*** ret) {
         _cleanup_free_ Job** list = NULL;
-        size_t n = 0, n_allocated = 0;
         Unit *other = NULL;
-        void *v;
+        size_t n = 0;
 
         assert(j);
         assert(ret);
 
         /* Returns a list of all pending jobs that are waiting for this job to finish. */
 
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_BEFORE]) {
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_BEFORE) {
                 if (!other->job)
                         continue;
 
                 if (other->job->ignore_order)
                         continue;
 
-                if (job_compare(j, other->job, UNIT_BEFORE) >= 0)
+                if (job_compare(j, other->job, UNIT_ATOM_BEFORE) >= 0)
                         continue;
 
-                if (!GREEDY_REALLOC(list, n_allocated, n+1))
+                if (!GREEDY_REALLOC(list, n+1))
                         return -ENOMEM;
                 list[n++] = other->job;
         }
 
-        HASHMAP_FOREACH_KEY(v, other, j->unit->dependencies[UNIT_AFTER]) {
+        UNIT_FOREACH_DEPENDENCY(other, j->unit, UNIT_ATOM_AFTER) {
                 if (!other->job)
                         continue;
 
                 if (other->job->ignore_order)
                         continue;
 
-                if (job_compare(j, other->job, UNIT_AFTER) >= 0)
+                if (job_compare(j, other->job, UNIT_ATOM_AFTER) >= 0)
                         continue;
 
-                if (!GREEDY_REALLOC(list, n_allocated, n+1))
+                if (!GREEDY_REALLOC(list, n+1))
                         return -ENOMEM;
                 list[n++] = other->job;
         }
@@ -1666,13 +1652,14 @@ const char* job_type_to_access_method(JobType t) {
  *  stop a  + start b → 1st step stop a,  2nd step start b
  *  stop a  + stop b  → 1st step stop b,  2nd step stop a
  *
- *  This has the side effect that restarts are properly
- *  synchronized too.
+ *  This has the side effect that restarts are properly synchronized too.
  */
-int job_compare(Job *a, Job *b, UnitDependency assume_dep) {
+int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep) {
+        assert(a);
+        assert(b);
         assert(a->type < _JOB_TYPE_MAX_IN_TRANSACTION);
         assert(b->type < _JOB_TYPE_MAX_IN_TRANSACTION);
-        assert(IN_SET(assume_dep, UNIT_AFTER, UNIT_BEFORE));
+        assert(IN_SET(assume_dep, UNIT_ATOM_AFTER, UNIT_ATOM_BEFORE));
 
         /* Trivial cases first */
         if (a->type == JOB_NOP || b->type == JOB_NOP)
@@ -1681,12 +1668,11 @@ int job_compare(Job *a, Job *b, UnitDependency assume_dep) {
         if (a->ignore_order || b->ignore_order)
                 return 0;
 
-        if (assume_dep == UNIT_AFTER)
-                return -job_compare(b, a, UNIT_BEFORE);
+        if (assume_dep == UNIT_ATOM_AFTER)
+                return -job_compare(b, a, UNIT_ATOM_BEFORE);
 
-        /* Let's make it simple, JOB_STOP goes always first (in case both ua and ub stop,
-         * then ub's stop goes first anyway).
-         * JOB_RESTART is JOB_STOP in disguise (before it is patched to JOB_START). */
+        /* Let's make it simple, JOB_STOP goes always first (in case both ua and ub stop, then ub's stop goes
+         * first anyway). JOB_RESTART is JOB_STOP in disguise (before it is patched to JOB_START). */
         if (IN_SET(b->type, JOB_STOP, JOB_RESTART))
                 return 1;
         else