+unsigned manager_dispatch_cgroup_queue(Manager *m) {
+ ManagerState state;
+ unsigned n = 0;
+ Unit *i;
+ int r;
+
+ state = manager_state(m);
+
+ while ((i = m->cgroup_queue)) {
+ assert(i->in_cgroup_queue);
+
+ r = unit_realize_cgroup_now(i, state);
+ if (r < 0)
+ log_warning_errno(r, "Failed to realize cgroups for queued unit %s, ignoring: %m", i->id);
+
+ n++;
+ }
+
+ return n;
+}
+
+static void unit_queue_siblings(Unit *u) {
+ Unit *slice;
+
+ /* This adds the siblings of the specified unit and the
+ * siblings of all parent units to the cgroup queue. (But
+ * neither the specified unit itself nor the parents.) */
+
+ while ((slice = UNIT_DEREF(u->slice))) {
+ Iterator i;
+ Unit *m;
+
+ SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
+ if (m == u)
+ continue;
+
+ /* Skip units that have a dependency on the slice
+ * but aren't actually in it. */
+ if (UNIT_DEREF(m->slice) != slice)
+ continue;
+
+ /* No point in doing cgroup application for units
+ * without active processes. */
+ if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m)))
+ continue;
+
+ /* If the unit doesn't need any new controllers
+ * and has current ones realized, it doesn't need
+ * any changes. */
+ if (unit_has_mask_realized(m, unit_get_target_mask(m)))
+ continue;
+
+ unit_add_to_cgroup_queue(m);
+ }
+
+ u = slice;
+ }
+}
+
+int unit_realize_cgroup(Unit *u) {
+ assert(u);
+
+ if (!UNIT_HAS_CGROUP_CONTEXT(u))
+ return 0;
+
+ /* So, here's the deal: when realizing the cgroups for this
+ * unit, we need to first create all parents, but there's more
+ * actually: for the weight-based controllers we also need to
+ * make sure that all our siblings (i.e. units that are in the
+ * same slice as we are) have cgroups, too. Otherwise, things
+ * would become very uneven as each of their processes would
+ * get as much resources as all our group together. This call
+ * will synchronously create the parent cgroups, but will
+ * defer work on the siblings to the next event loop
+ * iteration. */
+
+ /* Add all sibling slices to the cgroup queue. */
+ unit_queue_siblings(u);
+
+ /* And realize this one now (and apply the values) */
+ return unit_realize_cgroup_now(u, manager_state(u->manager));
+}
+
+void unit_release_cgroup(Unit *u) {
+ assert(u);
+
+ /* Forgets all cgroup details for this cgroup */
+
+ if (u->cgroup_path) {
+ (void) hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
+ u->cgroup_path = mfree(u->cgroup_path);
+ }
+
+ if (u->cgroup_inotify_wd >= 0) {
+ if (inotify_rm_watch(u->manager->cgroup_inotify_fd, u->cgroup_inotify_wd) < 0)
+ log_unit_debug_errno(u, errno, "Failed to remove cgroup inotify watch %i for %s, ignoring", u->cgroup_inotify_wd, u->id);
+
+ (void) hashmap_remove(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd));
+ u->cgroup_inotify_wd = -1;
+ }
+}
+
+void unit_prune_cgroup(Unit *u) {
+ int r;
+ bool is_root_slice;
+
+ assert(u);
+
+ /* Removes the cgroup, if empty and possible, and stops watching it. */
+
+ if (!u->cgroup_path)
+ return;
+
+ is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
+
+ r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
+ if (r < 0) {
+ log_debug_errno(r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
+ return;
+ }
+
+ if (is_root_slice)
+ return;
+
+ unit_release_cgroup(u);
+
+ u->cgroup_realized = false;
+ u->cgroup_realized_mask = 0;
+}
+
+int unit_search_main_pid(Unit *u, pid_t *ret) {