static bool job_is_runnable(Job *j) {
Unit *other;
- void *v;
assert(j);
assert(j->installed);
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);
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)
}
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);
/* 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),
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);
bool job_may_gc(Job *j) {
Unit *other;
- void *v;
assert(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;
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. */
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;
}
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;
}
* 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)
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