return ret;
}
+int unit_synthesize_cgroup_empty_event(Unit *u) {
+ int r;
+
+ assert(u);
+
+ /* Enqueue a synthetic cgroup empty event if this unit doesn't watch any PIDs anymore. This is compatibility
+ * support for non-unified systems where notifications aren't reliable, and hence need to take whatever we can
+ * get as notification source as soon as we stopped having any useful PIDs to watch for. */
+
+ if (!u->cgroup_path)
+ return -ENOENT;
+
+ r = cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER);
+ if (r < 0)
+ return r;
+ if (r > 0) /* On unified we have reliable notifications, and don't need this */
+ return 0;
+
+ if (!set_isempty(u->pids))
+ return 0;
+
+ unit_add_to_cgroup_empty_queue(u);
+ return 0;
+}
+
int unit_watch_all_pids(Unit *u) {
int r;
int unit_search_main_pid(Unit *u, pid_t *ret);
int unit_watch_all_pids(Unit *u);
+int unit_synthesize_cgroup_empty_event(Unit *u);
+
int unit_get_memory_current(Unit *u, uint64_t *ret);
int unit_get_tasks_current(Unit *u, uint64_t *ret);
int unit_get_cpu_usage(Unit *u, nsec_t *ret);
static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- /* If we get a SIGCHLD event for one of the processes we were
- interested in, then we look for others to watch, under the
- assumption that we'll sooner or later get a SIGCHLD for
- them, as the original process we watched was probably the
- parent of them, and they are hence now our children. */
+ assert(u);
+ /* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to
+ * watch, under the assumption that we'll sooner or later get a SIGCHLD for them, as the original
+ * process we watched was probably the parent of them, and they are hence now our children. */
unit_tidy_watch_pids(u, 0, 0);
unit_watch_all_pids(u);
- /* If the PID set is empty now, then let's finish this off
- (On unified we use proper notifications) */
- if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) == 0 && set_isempty(u->pids))
- scope_notify_cgroup_empty_event(u);
+ /* If the PID set is empty now, then let's finish this off. */
+ unit_synthesize_cgroup_empty_event(u);
}
static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
if (notify_dbus)
unit_add_to_dbus_queue(u);
- /* We got one SIGCHLD for the service, let's watch all
- * processes that are now running of the service, and watch
- * that. Among the PIDs we then watch will be children
- * reassigned to us, which hopefully allows us to identify
- * when all children are gone */
+ /* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to watch,
+ * under the assumption that we'll sooner or later get a SIGCHLD for them, as the original process we watched
+ * was probably the parent of them, and they are hence now our children. */
unit_tidy_watch_pids(u, s->main_pid, s->control_pid);
unit_watch_all_pids(u);
- /* If the PID set is empty now, then let's finish this off
- (On unified we use proper notifications) */
- if (cg_unified_controller(SYSTEMD_CGROUP_CONTROLLER) == 0 && set_isempty(u->pids))
- unit_add_to_cgroup_empty_queue(u);
+ /* If the PID set is empty now, then let's check if the cgroup is empty too and finish off the unit. */
+ unit_synthesize_cgroup_empty_event(u);
}
static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {