diff --git a/src/core/unit.c b/src/core/unit.c index 76902cca90..7d95f9db0b 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -4831,3 +4831,72 @@ int unit_fork_helper_process(Unit *u, pid_t *ret) { *ret = pid; return 1; } + +static void unit_update_dependency_mask(Unit *u, UnitDependency d, Unit *other, UnitDependencyInfo di) { + assert(u); + assert(d >= 0); + assert(d < _UNIT_DEPENDENCY_MAX); + assert(other); + + if (di.origin_mask == 0 && di.destination_mask == 0) { + /* No bit set anymore, let's drop the whole entry */ + assert_se(hashmap_remove(u->dependencies[d], other)); + log_unit_debug(u, "%s lost dependency %s=%s", u->id, unit_dependency_to_string(d), other->id); + } else + /* Mask was reduced, let's update the entry */ + assert_se(hashmap_update(u->dependencies[d], other, di.data) == 0); +} + +void unit_remove_dependencies(Unit *u, UnitDependencyMask mask) { + UnitDependency d; + + assert(u); + + /* Removes all dependencies u has on other units marked for ownership by 'mask'. */ + + if (mask == 0) + return; + + for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { + bool done; + + do { + UnitDependencyInfo di; + Unit *other; + Iterator i; + + done = true; + + HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d], i) { + UnitDependency q; + + if ((di.origin_mask & ~mask) == di.origin_mask) + continue; + di.origin_mask &= ~mask; + unit_update_dependency_mask(u, d, other, di); + + /* We updated the dependency from our unit to the other unit now. But most dependencies + * imply a reverse dependency. Hence, let's delete that one too. For that we go through + * all dependency types on the other unit and delete all those which point to us and + * have the right mask set. */ + + for (q = 0; q < _UNIT_DEPENDENCY_MAX; q++) { + UnitDependencyInfo dj; + + dj.data = hashmap_get(other->dependencies[q], u); + if ((dj.destination_mask & ~mask) == dj.destination_mask) + continue; + dj.destination_mask &= ~mask; + + unit_update_dependency_mask(other, q, u, dj); + } + + unit_add_to_gc_queue(other); + + done = false; + break; + } + + } while (!done); + } +} diff --git a/src/core/unit.h b/src/core/unit.h index 5b9dce3d0b..5e5e791bc4 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -740,6 +740,8 @@ void unit_set_exec_params(Unit *s, ExecParameters *p); int unit_fork_helper_process(Unit *u, pid_t *ret); +void unit_remove_dependencies(Unit *u, UnitDependencyMask mask); + /* Macros which append UNIT= or USER_UNIT= to the message */ #define log_unit_full(unit, level, error, ...) \ diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 55249fdce2..a2e68bf5d9 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -115,6 +115,33 @@ int main(int argc, char *argv[]) { assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0); manager_dump_jobs(m, stdout, "\t"); + assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b)); + assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c)); + assert_se(!hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + + assert_se(unit_add_dependency(a, UNIT_PROPAGATES_RELOAD_TO, b, true, UNIT_DEPENDENCY_UDEV) == 0); + assert_se(unit_add_dependency(a, UNIT_PROPAGATES_RELOAD_TO, c, true, UNIT_DEPENDENCY_PROC_SWAP) == 0); + + assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b)); + assert_se(hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c)); + assert_se(hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + + unit_remove_dependencies(a, UNIT_DEPENDENCY_UDEV); + + assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b)); + assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + assert_se(hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c)); + assert_se(hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + + unit_remove_dependencies(a, UNIT_DEPENDENCY_PROC_SWAP); + + assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b)); + assert_se(!hashmap_get(b->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], c)); + assert_se(!hashmap_get(c->dependencies[UNIT_RELOAD_PROPAGATED_FROM], a)); + manager_free(m); return 0;