return n;
}
+static unsigned manager_dispatch_release_resources_queue(Manager *m) {
+ unsigned n = 0;
+ Unit *u;
+
+ assert(m);
+
+ while ((u = m->release_resources_queue)) {
+ assert(u->in_release_resources_queue);
+
+ LIST_REMOVE(release_resources_queue, m->release_resources_queue, u);
+ u->in_release_resources_queue = false;
+
+ n++;
+
+ unit_release_resources(u);
+ }
+
+ return n;
+}
+
enum {
GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
GC_OFFSET_UNSURE, /* No clue */
if (manager_dispatch_stop_when_unneeded_queue(m) > 0)
continue;
+ if (manager_dispatch_release_resources_queue(m) > 0)
+ continue;
+
if (manager_dispatch_dbus_queue(m) > 0)
continue;
return false;
}
+void unit_release_resources(Unit *u) {
+ UnitActiveState state;
+
+ assert(u);
+
+ if (u->job || u->nop_job)
+ return;
+
+ if (u->perpetual)
+ return;
+
+ state = unit_active_state(u);
+ if (!IN_SET(state, UNIT_INACTIVE, UNIT_FAILED))
+ return;
+
+ if (unit_will_restart(u))
+ return;
+
+ if (UNIT_VTABLE(u)->release_resources)
+ UNIT_VTABLE(u)->release_resources(u);
+}
+
bool unit_may_gc(Unit *u) {
UnitActiveState state;
int r;
assert(u);
- /* Checks whether the unit is ready to be unloaded for garbage collection.
- * Returns true when the unit may be collected, and false if there's some
- * reason to keep it loaded.
+ /* Checks whether the unit is ready to be unloaded for garbage collection. Returns true when the
+ * unit may be collected, and false if there's some reason to keep it loaded.
*
- * References from other units are *not* checked here. Instead, this is done
- * in unit_gc_sweep(), but using markers to properly collect dependency loops.
+ * References from other units are *not* checked here. Instead, this is done in unit_gc_sweep(), but
+ * using markers to properly collect dependency loops.
*/
if (u->job || u->nop_job)
return false;
- state = unit_active_state(u);
-
- /* If the unit is inactive and failed and no job is queued for it, then release its runtime resources */
- if (UNIT_IS_INACTIVE_OR_FAILED(state) &&
- UNIT_VTABLE(u)->release_resources)
- UNIT_VTABLE(u)->release_resources(u);
-
if (u->perpetual)
return false;
if (sd_bus_track_count(u->bus_track) > 0)
return false;
- /* But we keep the unit object around for longer when it is referenced or configured to not be gc'ed */
+ state = unit_active_state(u);
+
+ /* But we keep the unit object around for longer when it is referenced or configured to not be
+ * gc'ed */
switch (u->collect_mode) {
case COLLECT_INACTIVE:
return false;
}
- if (UNIT_VTABLE(u)->may_gc && !UNIT_VTABLE(u)->may_gc(u))
- return false;
+ if (!UNIT_VTABLE(u)->may_gc)
+ return true;
- return true;
+ return UNIT_VTABLE(u)->may_gc(u);
}
void unit_add_to_load_queue(Unit *u) {
u->in_stop_when_bound_queue = true;
}
+void unit_submit_to_release_resources_queue(Unit *u) {
+ assert(u);
+
+ if (u->in_release_resources_queue)
+ return;
+
+ if (u->job || u->nop_job)
+ return;
+
+ if (u->perpetual)
+ return;
+
+ if (!UNIT_VTABLE(u)->release_resources)
+ return;
+
+ LIST_PREPEND(release_resources_queue, u->manager->release_resources_queue, u);
+ u->in_release_resources_queue = true;
+}
+
static void unit_clear_dependencies(Unit *u) {
assert(u);
if (u->in_stop_when_bound_queue)
LIST_REMOVE(stop_when_bound_queue, u->manager->stop_when_bound_queue, u);
+ if (u->in_release_resources_queue)
+ LIST_REMOVE(release_resources_queue, u->manager->release_resources_queue, u);
+
bpf_firewall_close(u);
hashmap_free(u->bpf_foreign_by_key);
assert(j);
if (j->state == JOB_WAITING)
-
/* So we reached a different state for this job. Let's see if we can run it now if it failed previously
* due to EAGAIN. */
job_add_to_run_queue(j);
/* Maybe the unit should be GC'ed now? */
unit_add_to_gc_queue(u);
+
+ /* Maybe we can release some resources now? */
+ unit_submit_to_release_resources_queue(u);
}
if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
/* Queue of units that have a BindTo= dependency on some other unit, and should possibly be shut down */
LIST_FIELDS(Unit, stop_when_bound_queue);
+ /* Queue of units that should be checked if they can release resources now */
+ LIST_FIELDS(Unit, release_resources_queue);
+
/* PIDs we keep an eye on. Note that a unit might have many
* more, but these are the ones we care enough about to
* process SIGCHLD for */
bool in_stop_when_unneeded_queue:1;
bool in_start_when_upheld_queue:1;
bool in_stop_when_bound_queue:1;
+ bool in_release_resources_queue:1;
bool sent_dbus_new_signal:1;
int unit_choose_id(Unit *u, const char *name);
int unit_set_description(Unit *u, const char *description);
+void unit_release_resources(Unit *u);
+
bool unit_may_gc(Unit *u);
static inline bool unit_is_extrinsic(Unit *u) {
void unit_submit_to_stop_when_unneeded_queue(Unit *u);
void unit_submit_to_start_when_upheld_queue(Unit *u);
void unit_submit_to_stop_when_bound_queue(Unit *u);
+void unit_submit_to_release_resources_queue(Unit *u);
int unit_merge(Unit *u, Unit *other);
int unit_merge_by_name(Unit *u, const char *other);