[systemd-devel] [RFC] core: introduce ExitOnIdle= and ExitOnIdleSec=
Camilo Aguilar
camilo.aguilar at gmail.com
Mon Apr 20 07:58:42 PDT 2015
This will be nice to have.
On Mon, Apr 20, 2015 at 10:56 AM WaLyong Cho <walyong.cho at samsung.com>
wrote:
> If a service does not consume CPU during some time(can be configured
> by ExitOnIdleSec=) and set to stopped on idle state(ExitOnIdle=), the
> service will be stopped. This can be useful if the service provides
> some of activation methods.
> ---
> src/core/load-fragment-gperf.gperf.m4 | 2 +
> src/core/service.c | 97
> +++++++++++++++++++++++++++++++++++
> src/core/service.h | 5 ++
> src/core/unit.h | 1 +
> 4 files changed, 105 insertions(+)
>
> diff --git a/src/core/load-fragment-gperf.gperf.m4
> b/src/core/load-fragment-gperf.gperf.m4
> index 5305984..60d573e 100644
> --- a/src/core/load-fragment-gperf.gperf.m4
> +++ b/src/core/load-fragment-gperf.gperf.m4
> @@ -229,6 +229,8 @@ Service.BusName,
> config_parse_bus_name, 0,
> Service.FileDescriptorStoreMax, config_parse_unsigned, 0,
> offsetof(Service, n_fd_store_max)
> Service.NotifyAccess, config_parse_notify_access, 0,
> offsetof(Service, notify_access)
> Service.Sockets, config_parse_service_sockets, 0,
> 0
> +Service.ExitOnIdle, config_parse_bool, 0,
> offsetof(Service, exit_on_idle)
> +Service.ExitOnIdleSec, config_parse_sec, 0,
> offsetof(Service, exit_on_idle_usec)
> m4_ifdef(`ENABLE_KDBUS',
> `Service.BusPolicy, config_parse_bus_endpoint_policy, 0,
> offsetof(Service, exec_context)',
> `Service.BusPolicy, config_parse_warn_compat,
> DISABLED_EXPERIMENTAL, 0')
> diff --git a/src/core/service.c b/src/core/service.c
> index fa818fc..c8752ae 100644
> --- a/src/core/service.c
> +++ b/src/core/service.c
> @@ -91,6 +91,7 @@ static const UnitActiveState
> state_translation_table_idle[_SERVICE_STATE_MAX] =
> static int service_dispatch_io(sd_event_source *source, int fd, uint32_t
> events, void *userdata);
> static int service_dispatch_timer(sd_event_source *source, usec_t usec,
> void *userdata);
> static int service_dispatch_watchdog(sd_event_source *source, usec_t
> usec, void *userdata);
> +static int service_dispatch_exit_on_idle_timer(sd_event_source *source,
> usec_t usec, void *userdata);
>
> static void service_enter_signal(Service *s, ServiceState state,
> ServiceResult f);
> static void service_enter_reload_by_notify(Service *s);
> @@ -108,6 +109,8 @@ static void service_init(Unit *u) {
> s->socket_fd = -1;
> s->bus_endpoint_fd = -1;
> s->guess_main_pid = true;
> + s->exit_on_idle = false;
> + s->exit_on_idle_usec = 0;
>
> RATELIMIT_INIT(s->start_limit,
> u->manager->default_start_limit_interval,
> u->manager->default_start_limit_burst);
>
> @@ -279,6 +282,56 @@ static void service_release_resources(Unit *u) {
> assert(s->n_fd_store == 0);
> }
>
> +static void service_stop_exit_on_idle_timer(Service *s) {
> + assert(s);
> +
> + s->exit_on_idle_event_source =
> sd_event_source_unref(s->exit_on_idle_event_source);
> + s->exit_on_idle_timestamp = DUAL_TIMESTAMP_NULL;
> +}
> +
> +static void service_start_exit_on_idle_timer(Service *s) {
> + int r;
> +
> + assert(s);
> +
> + if (s->exit_on_idle_usec <= 0)
> + return;
> +
> + if (s->exit_on_idle_event_source) {
> + r =
> sd_event_source_set_time(s->exit_on_idle_event_source,
> s->exit_on_idle_timestamp.monotonic + s->exit_on_idle_usec);
> + if (r < 0) {
> + log_unit_warning(UNIT(s)->id, "%s failed to reset
> exit-on-idle timer: %s", UNIT(s)->id, strerror(-r));
> + return;
> + }
> +
> + r =
> sd_event_source_set_enabled(s->exit_on_idle_event_source, SD_EVENT_ON);
> + } else {
> + r = sd_event_add_time(
> + UNIT(s)->manager->event,
> + &s->exit_on_idle_event_source,
> + CLOCK_MONOTONIC,
> + s->exit_on_idle_timestamp.monotonic +
> s->exit_on_idle_usec, 0,
> + service_dispatch_exit_on_idle_timer, s);
> + if (r < 0) {
> + log_unit_warning(UNIT(s)->id, "%s failed to add
> exit-on-idle timer: %s", UNIT(s)->id, strerror(-r));
> + return;
> + }
> +
> + r =
> sd_event_source_set_priority(s->exit_on_idle_event_source,
> SD_EVENT_PRIORITY_IDLE);
> + }
> +
> + if (r < 0)
> + log_unit_warning(UNIT(s)->id, "%s failed to install
> exit-on-idle timer: %s", UNIT(s)->id, strerror(-r));
> + return;
> +}
> +
> +static void service_reset_exit_on_idle_timer(Service *s) {
> + assert(s);
> +
> + dual_timestamp_get(&s->exit_on_idle_timestamp);
> + service_start_exit_on_idle_timer(s);
> +}
> +
> static void service_done(Unit *u) {
> Service *s = SERVICE(u);
>
> @@ -518,6 +571,7 @@ static void service_fix_output(Service *s) {
> }
>
> static int service_add_extras(Service *s) {
> + CGroupContext *cc;
> int r;
>
> assert(s);
> @@ -571,6 +625,15 @@ static int service_add_extras(Service *s) {
> return r;
> }
>
> + if (s->exit_on_idle && s->exit_on_idle_usec <= 0)
> + s->exit_on_idle_usec = USEC_PER_MINUTE;
> +
> + if (s->exit_on_idle) {
> + cc = unit_get_cgroup_context(UNIT(s));
> + if (cc)
> + cc->cpu_accounting = true;
> + }
> +
> if (UNIT(s)->default_dependencies) {
> r = service_add_default_dependencies(s);
> if (r < 0)
> @@ -850,6 +913,12 @@ static void service_set_state(Service *s,
> ServiceState state) {
> if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING,
> SERVICE_RELOAD))
> service_stop_watchdog(s);
>
> + if (IN_SET(state, SERVICE_RUNNING))
> + service_start_exit_on_idle_timer(s);
> +
> + if (IN_SET(state, SERVICE_DEAD))
> + service_stop_exit_on_idle_timer(s);
> +
> /* For the inactive states unit_notify() will trim the cgroup,
> * but for exit we have to do that ourselves... */
> if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
> @@ -2770,6 +2839,34 @@ static int
> service_dispatch_watchdog(sd_event_source *source, usec_t usec, void
> format_timespan(t, sizeof(t), s->watchdog_usec,
> 1));
>
> service_enter_signal(s, SERVICE_STOP_SIGABRT,
> SERVICE_FAILURE_WATCHDOG);
> + return 0;
> +}
> +
> +static int service_dispatch_exit_on_idle_timer(sd_event_source *source,
> usec_t usec, void *userdata) {
> + Service *s = SERVICE(userdata);
> + nsec_t usage;
> + int r;
> +
> + assert(s);
> + assert(source == s->exit_on_idle_event_source);
> +
> + r = unit_get_cpu_usage(UNIT(s), &usage);
> + if (r < 0) {
> + log_unit_error_errno(UNIT(s)->id, r, "%s failed to get
> cpu usage: %m", UNIT(s)->id);
> + return 0;
> + }
> +
> + if (usage == UNIT(s)->cpuacct_usage) {
> + log_unit_info(UNIT(s)->id, "%s is in idle state,
> stopping...", UNIT(s)->id);
> + r = manager_add_job(UNIT(s)->manager, JOB_STOP, UNIT(s),
> JOB_FAIL, true, NULL, NULL);
> + if (r < 0) {
> + log_unit_error_errno(UNIT(s)->id, r, "%s failed
> to enqueue stopping job: %m", UNIT(s)->id);
> + return r;
> + }
> + } else {
> + UNIT(s)->cpuacct_usage = usage;
> + service_reset_exit_on_idle_timer(s);
> + }
>
> return 0;
> }
> diff --git a/src/core/service.h b/src/core/service.h
> index 7da0a93..909908e 100644
> --- a/src/core/service.h
> +++ b/src/core/service.h
> @@ -212,6 +212,11 @@ struct Service {
> ServiceFDStore *fd_store;
> unsigned n_fd_store;
> unsigned n_fd_store_max;
> +
> + bool exit_on_idle;
> + dual_timestamp exit_on_idle_timestamp;
> + usec_t exit_on_idle_usec;
> + sd_event_source *exit_on_idle_event_source;
> };
>
> extern const UnitVTable service_vtable;
> diff --git a/src/core/unit.h b/src/core/unit.h
> index 11242c2..84c0cd0 100644
> --- a/src/core/unit.h
> +++ b/src/core/unit.h
> @@ -178,6 +178,7 @@ struct Unit {
>
> /* Where the cpuacct.usage cgroup counter was at the time the
> unit was started */
> nsec_t cpuacct_usage_base;
> + nsec_t cpuacct_usage;
>
> /* Counterparts in the cgroup filesystem */
> char *cgroup_path;
> --
> 1.9.3
>
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freedesktop.org/archives/systemd-devel/attachments/20150420/d0481481/attachment-0001.html>
More information about the systemd-devel
mailing list