int scope_abandon(Scope *s) { assert(s); if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED)) return -ESTALE; free(s->controller); s->controller = NULL; /* The client is no longer watching the remaining processes, * so let's step in here, under the assumption that the * remaining processes will be sooner or later reassigned to * us as parent. */ unit_tidy_watch_pids(UNIT(s), 0, 0); unit_watch_all_pids(UNIT(s)); /* If the PID set is empty now, then let's finish this off */ if (set_isempty(UNIT(s)->pids)) scope_notify_cgroup_empty_event(UNIT(s)); else scope_set_state(s, SCOPE_ABANDONED); return 0; }
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { int r; assert(s); if (f != SCOPE_SUCCESS) s->result = f; r = unit_kill_context( UNIT(s), &s->kill_context, state != SCOPE_STOP_SIGTERM, -1, -1, false); if (r < 0) goto fail; if (r > 0) { r = scope_arm_timer(s); if (r < 0) goto fail; scope_set_state(s, state); } else scope_enter_dead(s, SCOPE_SUCCESS); return; fail: log_warning_unit(UNIT(s)->id, "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); scope_enter_dead(s, SCOPE_FAILURE_RESOURCES); }
static int scope_start(Unit *u) { Scope *s = SCOPE(u); int r; assert(s); if (s->state == SCOPE_FAILED) return -EPERM; if (s->state == SCOPE_STOP_SIGTERM || s->state == SCOPE_STOP_SIGKILL) return -EAGAIN; assert(s->state == SCOPE_DEAD); if (!u->transient && UNIT(s)->manager->n_reloading <= 0) return -ENOENT; r = unit_realize_cgroup(u); if (r < 0) { log_error("Failed to realize cgroup: %s", strerror(-r)); return r; } r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, UNIT(s)->pids); if (r < 0) return r; s->result = SCOPE_SUCCESS; scope_set_state(s, SCOPE_RUNNING); return 0; }
static int scope_start(Unit *u) { Scope *s = SCOPE(u); int r; assert(s); if (s->state == SCOPE_FAILED) return -EPERM; /* We can't fulfill this right now, please try again later */ if (s->state == SCOPE_STOP_SIGTERM || s->state == SCOPE_STOP_SIGKILL) return -EAGAIN; assert(s->state == SCOPE_DEAD); if (!u->transient && UNIT(s)->manager->n_reloading <= 0) return -ENOENT; (void) unit_realize_cgroup(u); (void) unit_reset_cpu_usage(u); r = unit_attach_pids_to_cgroup(u); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m"); scope_enter_dead(s, SCOPE_FAILURE_RESOURCES); return r; } s->result = SCOPE_SUCCESS; scope_set_state(s, SCOPE_RUNNING); return 1; }
static void scope_enter_dead(Scope *s, ScopeResult f) { assert(s); if (f != SCOPE_SUCCESS) s->result = f; scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD); }
static void scope_enter_dead(Scope *s, ScopeResult f) { assert(s); if (s->result == SCOPE_SUCCESS) s->result = f; unit_log_result(UNIT(s), s->result == SCOPE_SUCCESS, scope_result_to_string(s->result)); scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD); }
static void scope_reset_failed(Unit *u) { Scope *s = SCOPE(u); assert(s); if (s->state == SCOPE_FAILED) scope_set_state(s, SCOPE_DEAD); s->result = SCOPE_SUCCESS; }
static void scope_enter_dead(Scope *s, ScopeResult f) { assert(s); if (s->result == SCOPE_SUCCESS) s->result = f; if (s->result != SCOPE_SUCCESS) log_unit_warning(UNIT(s), "Failed with result '%s'.", scope_result_to_string(s->result)); scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD); }
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { bool skip_signal = false; int r; assert(s); if (s->result == SCOPE_SUCCESS) s->result = f; /* Before sending any signal, make sure we track all members of this cgroup */ (void) unit_watch_all_pids(UNIT(s)); /* Also, enqueue a job that we recheck all our PIDs a bit later, given that it's likely some processes have * died now */ (void) unit_enqueue_rewatch_pids(UNIT(s)); /* If we have a controller set let's ask the controller nicely to terminate the scope, instead of us going * directly into SIGTERM berserk mode */ if (state == SCOPE_STOP_SIGTERM) skip_signal = bus_scope_send_request_stop(s) > 0; if (skip_signal) r = 1; /* wait */ else { r = unit_kill_context( UNIT(s), &s->kill_context, state != SCOPE_STOP_SIGTERM ? KILL_KILL : s->was_abandoned ? KILL_TERMINATE_AND_LOG : KILL_TERMINATE, -1, -1, false); if (r < 0) goto fail; } if (r > 0) { r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec)); if (r < 0) goto fail; scope_set_state(s, state); } else if (state == SCOPE_STOP_SIGTERM) scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS); else scope_enter_dead(s, SCOPE_SUCCESS); return; fail: log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m"); scope_enter_dead(s, SCOPE_FAILURE_RESOURCES); }
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { bool skip_signal = false; int r; assert(s); if (s->result == SCOPE_SUCCESS) s->result = f; unit_watch_all_pids(UNIT(s)); /* If we have a controller set let's ask the controller nicely * to terminate the scope, instead of us going directly into * SIGTERM berserk mode */ if (state == SCOPE_STOP_SIGTERM) skip_signal = bus_scope_send_request_stop(s) > 0; if (skip_signal) r = 1; /* wait */ else { r = unit_kill_context( UNIT(s), &s->kill_context, state != SCOPE_STOP_SIGTERM ? KILL_KILL : s->was_abandoned ? KILL_TERMINATE_AND_LOG : KILL_TERMINATE, -1, -1, false); if (r < 0) goto fail; } if (r > 0) { r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec)); if (r < 0) goto fail; scope_set_state(s, state); } else if (state == SCOPE_STOP_SIGTERM) scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS); else scope_enter_dead(s, SCOPE_SUCCESS); return; fail: log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m"); scope_enter_dead(s, SCOPE_FAILURE_RESOURCES); }
static int scope_start(Unit *u) { Scope *s = SCOPE(u); int r; assert(s); if (unit_has_name(u, SPECIAL_INIT_SCOPE)) return -EPERM; if (s->state == SCOPE_FAILED) return -EPERM; /* We can't fulfill this right now, please try again later */ if (IN_SET(s->state, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL)) return -EAGAIN; assert(s->state == SCOPE_DEAD); if (!u->transient && !MANAGER_IS_RELOADING(u->manager)) return -ENOENT; (void) bus_scope_track_controller(s); r = unit_acquire_invocation_id(u); if (r < 0) return r; (void) unit_realize_cgroup(u); (void) unit_reset_cpu_accounting(u); (void) unit_reset_ip_accounting(u); unit_export_state_files(UNIT(s)); r = unit_attach_pids_to_cgroup(u, UNIT(s)->pids, NULL); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m"); scope_enter_dead(s, SCOPE_FAILURE_RESOURCES); return r; } s->result = SCOPE_SUCCESS; scope_set_state(s, SCOPE_RUNNING); /* Start watching the PIDs currently in the scope */ (void) unit_enqueue_rewatch_pids(UNIT(s)); return 1; }
static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { bool skip_signal = false; int r; assert(s); if (f != SCOPE_SUCCESS) s->result = f; unit_watch_all_pids(UNIT(s)); /* If we have a controller set let's ask the controller nicely * to terminate the scope, instead of us going directly into * SIGTERM beserk mode */ if (state == SCOPE_STOP_SIGTERM) skip_signal = bus_scope_send_request_stop(s) > 0; if (!skip_signal) { r = unit_kill_context( UNIT(s), &s->kill_context, state != SCOPE_STOP_SIGTERM, -1, -1, false); if (r < 0) goto fail; } else r = 1; if (r > 0) { r = scope_arm_timer(s); if (r < 0) goto fail; scope_set_state(s, state); } else if (state == SCOPE_STOP_SIGTERM) scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS); else scope_enter_dead(s, SCOPE_SUCCESS); return; fail: log_warning_unit(UNIT(s)->id, "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r)); scope_enter_dead(s, SCOPE_FAILURE_RESOURCES); }
static int scope_coldplug(Unit *u) { Scope *s = SCOPE(u); int r; assert(s); assert(s->state == SCOPE_DEAD); if (s->deserialized_state != s->state) { if (s->deserialized_state == SCOPE_STOP_SIGKILL || s->deserialized_state == SCOPE_STOP_SIGTERM) { r = scope_arm_timer(s); if (r < 0) return r; } scope_set_state(s, s->deserialized_state); } return 0; }
int scope_abandon(Scope *s) { assert(s); if (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) return -EPERM; if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED)) return -ESTALE; s->was_abandoned = true; s->controller = mfree(s->controller); s->controller_track = sd_bus_track_unref(s->controller_track); scope_set_state(s, SCOPE_ABANDONED); /* The client is no longer watching the remaining processes, so let's step in here, under the assumption that * the remaining processes will be sooner or later reassigned to us as parent. */ (void) unit_enqueue_rewatch_pids(UNIT(s)); return 0; }
static int scope_coldplug(Unit *u) { Scope *s = SCOPE(u); int r; assert(s); assert(s->state == SCOPE_DEAD); if (s->deserialized_state == s->state) return 0; if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) { r = scope_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_stop_usec)); if (r < 0) return r; } if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED)) unit_watch_all_pids(UNIT(s)); scope_set_state(s, s->deserialized_state); return 0; }
static int scope_coldplug(Unit *u) { Scope *s = SCOPE(u); int r; assert(s); assert(s->state == SCOPE_DEAD); if (s->deserialized_state != s->state) { if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) { r = scope_arm_timer(s); if (r < 0) return r; } if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED)) unit_watch_all_pids(UNIT(s)); scope_set_state(s, s->deserialized_state); } return 0; }