core: introduce system state enum
The system state knows the states starting → running/degraded/maintenance → stopping, where: starting = system startup running = normal operation degraded = at least one unit is currently in failed state maintenance = rescue/emergency mode is active or queued stopping = system shutdown
This commit is contained in:
parent
0325941fff
commit
f755e3b74b
|
@ -239,6 +239,24 @@ static int property_get_n_names(
|
|||
return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units));
|
||||
}
|
||||
|
||||
static int property_get_n_failed_units(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(m);
|
||||
|
||||
return sd_bus_message_append(reply, "u", (uint32_t) set_size(m->failed_units));
|
||||
}
|
||||
|
||||
static int property_get_n_jobs(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
|
@ -281,6 +299,24 @@ static int property_get_progress(
|
|||
return sd_bus_message_append(reply, "d", d);
|
||||
}
|
||||
|
||||
static int property_get_system_state(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
Manager *m = userdata;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(m);
|
||||
|
||||
return sd_bus_message_append(reply, "s", manager_state_to_string(manager_state(m)));
|
||||
}
|
||||
|
||||
static int property_set_runtime_watchdog(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
|
@ -1598,6 +1634,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
|||
SD_BUS_WRITABLE_PROPERTY("LogLevel", "s", property_get_log_level, property_set_log_level, 0, 0),
|
||||
SD_BUS_WRITABLE_PROPERTY("LogTarget", "s", property_get_log_target, property_set_log_target, 0, 0),
|
||||
SD_BUS_PROPERTY("NNames", "u", property_get_n_names, 0, 0),
|
||||
SD_BUS_PROPERTY("NFailedUnits", "u", property_get_n_failed_units, 0, 0),
|
||||
SD_BUS_PROPERTY("NJobs", "u", property_get_n_jobs, 0, 0),
|
||||
SD_BUS_PROPERTY("NInstalledJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_installed_jobs), 0),
|
||||
SD_BUS_PROPERTY("NFailedJobs", "u", bus_property_get_unsigned, offsetof(Manager, n_failed_jobs), 0),
|
||||
|
@ -1611,6 +1648,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
|
|||
SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), SD_BUS_VTABLE_PROPERTY_CONST),
|
||||
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
|
||||
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
|
||||
|
||||
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
|
|
|
@ -140,6 +140,8 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
|
|||
}
|
||||
|
||||
void manager_flip_auto_status(Manager *m, bool enable) {
|
||||
assert(m);
|
||||
|
||||
if (enable) {
|
||||
if (m->show_status == SHOW_STATUS_AUTO)
|
||||
manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
|
||||
|
@ -451,6 +453,10 @@ int manager_new(SystemdRunningAs running_as, Manager **_m) {
|
|||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = set_ensure_allocated(&m->failed_units, trivial_hash_func, trivial_compare_func);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = sd_event_default(&m->event);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
@ -778,6 +784,8 @@ void manager_free(Manager *m) {
|
|||
hashmap_free(m->watch_pids2);
|
||||
hashmap_free(m->watch_bus);
|
||||
|
||||
set_free(m->failed_units);
|
||||
|
||||
sd_event_source_unref(m->signal_event_source);
|
||||
sd_event_source_unref(m->notify_event_source);
|
||||
sd_event_source_unref(m->time_change_event_source);
|
||||
|
@ -1799,7 +1807,7 @@ int manager_loop(Manager *m) {
|
|||
RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
|
||||
|
||||
assert(m);
|
||||
m->exit_code = MANAGER_RUNNING;
|
||||
m->exit_code = MANAGER_OK;
|
||||
|
||||
/* Release the path cache */
|
||||
set_free_free(m->unit_path_cache);
|
||||
|
@ -1813,7 +1821,7 @@ int manager_loop(Manager *m) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
while (m->exit_code == MANAGER_RUNNING) {
|
||||
while (m->exit_code == MANAGER_OK) {
|
||||
usec_t wait_usec;
|
||||
|
||||
if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM)
|
||||
|
@ -2463,10 +2471,12 @@ void manager_check_finished(Manager *m) {
|
|||
m->jobs_in_progress_event_source = sd_event_source_unref(m->jobs_in_progress_event_source);
|
||||
|
||||
if (hashmap_size(m->jobs) > 0) {
|
||||
|
||||
if (m->jobs_in_progress_event_source) {
|
||||
uint64_t next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
|
||||
sd_event_source_set_time(m->jobs_in_progress_event_source, next);
|
||||
sd_event_source_set_time(m->jobs_in_progress_event_source,
|
||||
now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2858,8 +2868,51 @@ Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
|
|||
}
|
||||
|
||||
const char *manager_get_runtime_prefix(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
return m->running_as == SYSTEMD_SYSTEM ?
|
||||
"/run" :
|
||||
getenv("XDG_RUNTIME_DIR");
|
||||
}
|
||||
|
||||
ManagerState manager_state(Manager *m) {
|
||||
Unit *u;
|
||||
|
||||
assert(m);
|
||||
|
||||
/* Did we ever finish booting? If not then we are still starting up */
|
||||
if (!dual_timestamp_is_set(&m->finish_timestamp))
|
||||
return MANAGER_STARTING;
|
||||
|
||||
/* Is the special shutdown target queued? If so, we are in shutdown state */
|
||||
u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
|
||||
if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))
|
||||
return MANAGER_STOPPING;
|
||||
|
||||
/* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
|
||||
u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);
|
||||
if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
|
||||
(u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
|
||||
return MANAGER_MAINTENANCE;
|
||||
|
||||
u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
|
||||
if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
|
||||
(u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
|
||||
return MANAGER_MAINTENANCE;
|
||||
|
||||
/* Are there any failed units? If so, we are in degraded mode */
|
||||
if (set_size(m->failed_units) > 0)
|
||||
return MANAGER_DEGRADED;
|
||||
|
||||
return MANAGER_RUNNING;
|
||||
}
|
||||
|
||||
static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
|
||||
[MANAGER_STARTING] = "starting",
|
||||
[MANAGER_RUNNING] = "running",
|
||||
[MANAGER_DEGRADED] = "degraded",
|
||||
[MANAGER_MAINTENANCE] = "maintenance",
|
||||
[MANAGER_STOPPING] = "stopping",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
|
||||
|
|
|
@ -35,8 +35,18 @@
|
|||
|
||||
typedef struct Manager Manager;
|
||||
|
||||
typedef enum ManagerExitCode {
|
||||
typedef enum ManagerState {
|
||||
MANAGER_STARTING,
|
||||
MANAGER_RUNNING,
|
||||
MANAGER_DEGRADED,
|
||||
MANAGER_MAINTENANCE,
|
||||
MANAGER_STOPPING,
|
||||
_MANAGER_STATE_MAX,
|
||||
_MANAGER_STATE_INVALID = -1
|
||||
} ManagerState;
|
||||
|
||||
typedef enum ManagerExitCode {
|
||||
MANAGER_OK,
|
||||
MANAGER_EXIT,
|
||||
MANAGER_RELOAD,
|
||||
MANAGER_REEXECUTE,
|
||||
|
@ -106,6 +116,9 @@ struct Manager {
|
|||
Hashmap *watch_pids1; /* pid => Unit object n:1 */
|
||||
Hashmap *watch_pids2; /* pid => Unit object n:1 */
|
||||
|
||||
/* A set which contains all currently failed units */
|
||||
Set *failed_units;
|
||||
|
||||
sd_event_source *run_queue_event_source;
|
||||
|
||||
char *notify_socket;
|
||||
|
@ -321,3 +334,8 @@ void manager_flip_auto_status(Manager *m, bool enable);
|
|||
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
|
||||
|
||||
const char *manager_get_runtime_prefix(Manager *m);
|
||||
|
||||
ManagerState manager_state(Manager *m);
|
||||
|
||||
const char *manager_state_to_string(ManagerState m) _const_;
|
||||
ManagerState manager_state_from_string(const char *s) _pure_;
|
||||
|
|
|
@ -471,6 +471,8 @@ void unit_free(Unit *u) {
|
|||
free(u->cgroup_path);
|
||||
}
|
||||
|
||||
set_remove(u->manager->failed_units, u);
|
||||
|
||||
free(u->description);
|
||||
strv_free(u->documentation);
|
||||
free(u->fragment_path);
|
||||
|
@ -1507,6 +1509,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
|
|||
|
||||
m = u->manager;
|
||||
|
||||
/* Update timestamps for state changes */
|
||||
if (m->n_reloading <= 0) {
|
||||
dual_timestamp ts;
|
||||
|
||||
|
@ -1523,6 +1526,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
|
|||
u->active_exit_timestamp = ts;
|
||||
}
|
||||
|
||||
/* Keep track of failed of units */
|
||||
if (ns == UNIT_FAILED && os != UNIT_FAILED)
|
||||
set_put(u->manager->failed_units, u);
|
||||
else if (os == UNIT_FAILED && ns != UNIT_FAILED)
|
||||
set_remove(u->manager->failed_units, u);
|
||||
|
||||
/* Make sure the cgroup is always removed when we become inactive */
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
|
||||
unit_destroy_cgroup(u);
|
||||
|
||||
|
|
Loading…
Reference in New Issue