chiark / gitweb /
implement recursive_stop/stop_when_unneeded unit flags
authorLennart Poettering <lennart@poettering.net>
Fri, 29 Jan 2010 19:47:09 +0000 (20:47 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 29 Jan 2010 19:47:15 +0000 (20:47 +0100)
load-fragment.c
unit.c
unit.h

index 6864622515f81df1630a43ca739219ee89be7bb1..ac96d0f746836e8b25daca5457d4a1f4233834d5 100644 (file)
@@ -821,6 +821,8 @@ static int load_from_path(Unit *u, const char *path) {
                 { "Conflicts",              config_parse_deps,            UINT_TO_PTR(UNIT_CONFLICTS),                     "Meta"    },
                 { "Before",                 config_parse_deps,            UINT_TO_PTR(UNIT_BEFORE),                        "Meta"    },
                 { "After",                  config_parse_deps,            UINT_TO_PTR(UNIT_AFTER),                         "Meta"    },
                 { "Conflicts",              config_parse_deps,            UINT_TO_PTR(UNIT_CONFLICTS),                     "Meta"    },
                 { "Before",                 config_parse_deps,            UINT_TO_PTR(UNIT_BEFORE),                        "Meta"    },
                 { "After",                  config_parse_deps,            UINT_TO_PTR(UNIT_AFTER),                         "Meta"    },
+                { "RecursiveStop",          config_parse_bool,            &u->meta.recursive_stop,                         "Meta"    },
+                { "StopWhenUnneeded",       config_parse_bool,            &u->meta.stop_when_unneeded,                     "Meta"    },
 
                 { "PIDFile",                config_parse_path,            &u->service.pid_file,                            "Service" },
                 { "ExecStartPre",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_PRE,  "Service" },
 
                 { "PIDFile",                config_parse_path,            &u->service.pid_file,                            "Service" },
                 { "ExecStartPre",           config_parse_exec,            u->service.exec_command+SERVICE_EXEC_START_PRE,  "Service" },
diff --git a/unit.c b/unit.c
index bd4272f6ddc92de9f95786832350e4b08f1692fd..839e542e1e96b34cda55214238e435d09a1bc901 100644 (file)
--- a/unit.c
+++ b/unit.c
@@ -373,11 +373,15 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                 "%s→ Unit %s:\n"
                 "%s\tDescription: %s\n"
                 "%s\tUnit Load State: %s\n"
                 "%s→ Unit %s:\n"
                 "%s\tDescription: %s\n"
                 "%s\tUnit Load State: %s\n"
-                "%s\tUnit Active State: %s\n",
+                "%s\tUnit Active State: %s\n"
+                "%s\tRecursive Deactivate: %s\n"
+                "%s\tStop When Unneeded: %s\n",
                 prefix, unit_id(u),
                 prefix, unit_description(u),
                 prefix, load_state_table[u->meta.load_state],
                 prefix, unit_id(u),
                 prefix, unit_description(u),
                 prefix, load_state_table[u->meta.load_state],
-                prefix, active_state_table[unit_active_state(u)]);
+                prefix, active_state_table[unit_active_state(u)],
+                prefix, yes_no(u->meta.recursive_stop),
+                prefix, yes_no(u->meta.stop_when_unneeded));
 
         if (u->meta.load_path)
                 fprintf(f, "%s\tLoad Path: %s\n", prefix, u->meta.load_path);
 
         if (u->meta.load_path)
                 fprintf(f, "%s\tLoad Path: %s\n", prefix, u->meta.load_path);
@@ -538,6 +542,39 @@ bool unit_can_reload(Unit *u) {
         return UNIT_VTABLE(u)->can_reload(u);
 }
 
         return UNIT_VTABLE(u)->can_reload(u);
 }
 
+static void unit_check_uneeded(Unit *u) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+
+        /* If this service shall be shut down when unneeded then do
+         * so. */
+
+        if (!u->meta.stop_when_unneeded)
+                return;
+
+        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+                return;
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        return;
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRED_BY], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        return;
+
+        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTED_BY], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        return;
+
+        log_debug("Service %s is not needed anymore. Stopping.", unit_id(u));
+
+        /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
+        manager_add_job(u->meta.manager, JOB_STOP, u, JOB_FAIL, true, NULL);
+}
+
 static void retroactively_start_dependencies(Unit *u) {
         Iterator i;
         Unit *other;
 static void retroactively_start_dependencies(Unit *u) {
         Iterator i;
         Unit *other;
@@ -573,9 +610,29 @@ static void retroactively_stop_dependencies(Unit *u) {
         assert(u);
         assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
 
         assert(u);
         assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
 
-        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
+        if (u->meta.recursive_stop) {
+                /* Pull down units need us recursively if enabled */
+                SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY], i)
+                        if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                                manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
+        }
+
+        /* Garbage collect services that might not be needed anymore, if enabled */
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRES], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->meta.manager, JOB_STOP, other, JOB_REPLACE, true, NULL);
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUIRES], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_WANTS], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_REQUISITE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
+        SET_FOREACH(other, u->meta.dependencies[UNIT_SOFT_REQUISITE], i)
+                if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
+                        unit_check_uneeded(other);
 }
 
 void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
 }
 
 void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
@@ -665,6 +722,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
                 retroactively_start_dependencies(u);
         else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
                 retroactively_stop_dependencies(u);
                 retroactively_start_dependencies(u);
         else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
                 retroactively_stop_dependencies(u);
+
+        /* Maybe we finished startup and are now ready for being
+         * stopped because unneeded? */
+        unit_check_uneeded(u);
 }
 
 int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
 }
 
 int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
diff --git a/unit.h b/unit.h
index 2433cc7d7cf7e1ca6afcf436d63e898a6e2f358c..c12ce0b482d784542eaf5a1da3ca4af448a64b0d 100644 (file)
--- a/unit.h
+++ b/unit.h
@@ -111,6 +111,12 @@ struct Meta {
 
         bool in_load_queue:1;
 
 
         bool in_load_queue:1;
 
+        /* If we go down, pull down everything that depends on us, too */
+        bool recursive_stop;
+
+        /* Garbage collect us we nobody wants or requires us anymore */
+        bool stop_when_unneeded;
+
         usec_t active_enter_timestamp;
         usec_t active_exit_timestamp;
 
         usec_t active_enter_timestamp;
         usec_t active_exit_timestamp;