Merge pull request #16603 from benzea/benzea/special-app-slice

Use app.slice by default in user manager (and define special user slices)
This commit is contained in:
Lennart Poettering 2020-11-11 14:11:02 +01:00 committed by GitHub
commit 23dce98e89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 166 additions and 38 deletions

View File

@ -1179,6 +1179,60 @@
</varlistentry>
</variablelist>
</refsect2>
<refsect2>
<title>Special User Slice Units</title>
<para>There are four <literal>.slice</literal> units which form the basis of the user hierarchy for
assignment of resources for user applications and services. See
<citerefentry><refentrytitle>systemd.slice</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details about slice units and the documentation about
<ulink url="https://systemd.io/DESKTOP_ENVIRONMENTS">Desktop Environments</ulink>
for further information.</para>
<variablelist>
<varlistentry>
<term><filename>-.slice</filename></term>
<listitem>
<para>The root slice is the root of the user's slice hierarchy.
It usually does not contain units directly, but may be used to set defaults for the whole tree.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>app.slice</filename></term>
<listitem>
<para>By default, all user services and applications managed by
<command>systemd</command> are found in this slice.
All interactively launched applications like web browsers and text editors
as well as non-critical services should be placed into this slice.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>session.slice</filename></term>
<listitem>
<para>All essential services and applications required for the
session should use this slice.
These are services that either cannot be restarted easily
or where latency issues may affect the interactivity of the system and applications.
This includes the display server, screen readers and other services such as DBus or XDG portals.
Such services should be configured to be part of this slice by
adding <varname>Slice=session.slice</varname> to their unit files.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><filename>background.slice</filename></term>
<listitem>
<para>All services running low-priority background tasks should use this slice.
This permits resources to be preferentially assigned to the other slices.
Examples include non-interactive tasks like file indexing or backup operations
where latency is not important.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect2>
</refsect1>
<refsect1>

View File

@ -107,3 +107,8 @@
/* The root directory. */
#define SPECIAL_ROOT_MOUNT "-.mount"
/* Special slices valid for the user instance */
#define SPECIAL_SESSION_SLICE "session.slice"
#define SPECIAL_APP_SLICE "app.slice"
#define SPECIAL_BACKGROUND_SLICE "background.slice"

View File

@ -412,8 +412,9 @@ static int mount_add_quota_dependencies(Mount *m) {
return 0;
}
static bool mount_is_extrinsic(Mount *m) {
static bool mount_is_extrinsic(Unit *u) {
MountParameters *p;
Mount *m = MOUNT(u);
assert(m);
/* Returns true for all units that are "magic" and should be excluded from the usual
@ -422,10 +423,7 @@ static bool mount_is_extrinsic(Mount *m) {
* ourselves but it's fine if the user operates on them with us. */
/* We only automatically manage mounts if we are in system mode */
if (!MANAGER_IS_SYSTEM(UNIT(m)->manager))
return true;
if (UNIT(m)->perpetual) /* All perpetual units never change state */
if (MANAGER_IS_USER(u->manager))
return true;
p = get_mount_parameters(m);
@ -493,7 +491,7 @@ static int mount_add_default_dependencies(Mount *m) {
* guaranteed to stay mounted the whole time, since our system is on it. Also, don't
* bother with anything mounted below virtual file systems, it's also going to be virtual,
* and hence not worth the effort. */
if (mount_is_extrinsic(m))
if (mount_is_extrinsic(UNIT(m)))
return 0;
p = get_mount_parameters(m);
@ -790,7 +788,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
prefix, p ? strna(p->options) : "n/a",
prefix, yes_no(m->from_proc_self_mountinfo),
prefix, yes_no(m->from_fragment),
prefix, yes_no(mount_is_extrinsic(m)),
prefix, yes_no(mount_is_extrinsic(u)),
prefix, m->directory_mode,
prefix, yes_no(m->sloppy_options),
prefix, yes_no(m->lazy_unmount),
@ -2161,6 +2159,7 @@ const UnitVTable mount_vtable = {
.will_restart = unit_will_restart_default,
.may_gc = mount_may_gc,
.is_extrinsic = mount_is_extrinsic,
.sigchld_event = mount_sigchld_event,

View File

@ -56,6 +56,35 @@ static bool SWAP_STATE_WITH_PROCESS(SwapState state) {
SWAP_CLEANING);
}
_pure_ static UnitActiveState swap_active_state(Unit *u) {
assert(u);
return state_translation_table[SWAP(u)->state];
}
_pure_ static const char *swap_sub_state_to_string(Unit *u) {
assert(u);
return swap_state_to_string(SWAP(u)->state);
}
_pure_ static bool swap_may_gc(Unit *u) {
Swap *s = SWAP(u);
assert(s);
if (s->from_proc_swaps)
return false;
return true;
}
_pure_ static bool swap_is_extrinsic(Unit *u) {
assert(SWAP(u));
return MANAGER_IS_USER(u->manager);
}
static void swap_unset_proc_swaps(Swap *s) {
assert(s);
@ -610,13 +639,15 @@ static void swap_dump(Unit *u, FILE *f, const char *prefix) {
"%sClean Result: %s\n"
"%sWhat: %s\n"
"%sFrom /proc/swaps: %s\n"
"%sFrom fragment: %s\n",
"%sFrom fragment: %s\n"
"%sExtrinsic: %s\n",
prefix, swap_state_to_string(s->state),
prefix, swap_result_to_string(s->result),
prefix, swap_result_to_string(s->clean_result),
prefix, s->what,
prefix, yes_no(s->from_proc_swaps),
prefix, yes_no(s->from_fragment));
prefix, yes_no(s->from_fragment),
prefix, yes_no(swap_is_extrinsic(u)));
if (s->devnode)
fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode);
@ -1028,29 +1059,6 @@ static int swap_deserialize_item(Unit *u, const char *key, const char *value, FD
return 0;
}
_pure_ static UnitActiveState swap_active_state(Unit *u) {
assert(u);
return state_translation_table[SWAP(u)->state];
}
_pure_ static const char *swap_sub_state_to_string(Unit *u) {
assert(u);
return swap_state_to_string(SWAP(u)->state);
}
_pure_ static bool swap_may_gc(Unit *u) {
Swap *s = SWAP(u);
assert(s);
if (s->from_proc_swaps)
return false;
return true;
}
static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
Swap *s = SWAP(u);
SwapResult f;
@ -1649,6 +1657,7 @@ const UnitVTable swap_vtable = {
.will_restart = unit_will_restart_default,
.may_gc = swap_may_gc,
.is_extrinsic = swap_is_extrinsic,
.sigchld_event = swap_sigchld_event,

View File

@ -1988,6 +1988,10 @@ int unit_stop(Unit *u) {
bool unit_can_stop(Unit *u) {
assert(u);
/* Note: if we return true here, it does not mean that the unit may be successfully stopped.
* Extrinsic units follow external state and they may stop following external state changes
* (hence we return true here), but an attempt to do this through the manager will fail. */
if (!unit_type_supported(u->type))
return false;
@ -3345,12 +3349,17 @@ int unit_set_default_slice(Unit *u) {
if (MANAGER_IS_SYSTEM(u->manager))
slice_name = strjoina("system-", escaped, ".slice");
else
slice_name = strjoina(escaped, ".slice");
} else
slice_name =
MANAGER_IS_SYSTEM(u->manager) && !unit_has_name(u, SPECIAL_INIT_SCOPE)
? SPECIAL_SYSTEM_SLICE
: SPECIAL_ROOT_SLICE;
slice_name = strjoina("app-", escaped, ".slice");
} else if (unit_is_extrinsic(u))
/* Keep all extrinsic units (e.g. perpetual units and swap and mount units in user mode) in
* the root slice. They don't really belong in one of the subslices. */
slice_name = SPECIAL_ROOT_SLICE;
else if (MANAGER_IS_SYSTEM(u->manager))
slice_name = SPECIAL_SYSTEM_SLICE;
else
slice_name = SPECIAL_APP_SLICE;
r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice);
if (r < 0)

View File

@ -531,6 +531,9 @@ typedef struct UnitVTable {
* even though nothing references it and it isn't active in any way. */
bool (*may_gc)(Unit *u);
/* Return true when the unit is not controlled by the manager (e.g. extrinsic mounts). */
bool (*is_extrinsic)(Unit *u);
/* When the unit is not running and no job for it queued we shall release its runtime resources */
void (*release_resources)(Unit *u);
@ -684,6 +687,11 @@ int unit_set_description(Unit *u, const char *description);
bool unit_may_gc(Unit *u);
static inline bool unit_is_extrinsic(Unit *u) {
return u->perpetual ||
(UNIT_VTABLE(u)->is_extrinsic && UNIT_VTABLE(u)->is_extrinsic(u));
}
void unit_add_to_load_queue(Unit *u);
void unit_add_to_dbus_queue(Unit *u);
void unit_add_to_cleanup_queue(Unit *u);

12
units/user/app.slice Normal file
View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=User Application Slice
Documentation=man:systemd.special(7)

View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=User Background Tasks Slice
Documentation=man:systemd.special(7)

View File

@ -1,6 +1,8 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
units = [
'app.slice',
'background.slice',
'basic.target',
'bluetooth.target',
'default.target',
@ -9,6 +11,7 @@ units = [
'graphical-session.target',
'paths.target',
'printer.target',
'session.slice',
'shutdown.target',
'smartcard.target',
'sockets.target',

12
units/user/session.slice Normal file
View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1+
#
# This file is part of systemd.
#
# systemd is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
[Unit]
Description=User Core Session Slice
Documentation=man:systemd.special(7)

View File

@ -14,3 +14,7 @@ DefaultDependencies=no
Requires=shutdown.target
After=shutdown.target
SuccessAction=exit-force
[Service]
# Place into the root slice to not keep another slice unit alive
Slice=-.slice

View File

@ -19,3 +19,4 @@ Type=oneshot
ExecStart=systemd-tmpfiles --user --clean
SuccessExitStatus=DATAERR
IOSchedulingClass=idle
Slice=background.slice