mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
core: add support for the "pids" cgroup controller
This adds support for the new "pids" cgroup controller of 4.3 kernels. It allows accounting the number of tasks in a cgroup and enforcing limits on it. This adds two new setting TasksAccounting= and TasksMax= to each unit, as well as a gloabl option DefaultTasksAccounting=. This also updated "cgtop" to optionally make use of the new kernel-provided accounting. systemctl has been updated to show the number of tasks for each service if it is available. This patch also adds correct support for undoing memory limits for units using a MemoryLimit=infinity syntax. We do the same for TasksMax= now and hence keep things in sync here.
This commit is contained in:
parent
15af581253
commit
03a7b521e3
@ -114,7 +114,7 @@
|
||||
<term><option>-t</option></term>
|
||||
<term><option>--order=tasks</option></term>
|
||||
|
||||
<listitem><para>Order by number of processes in control group.</para></listitem>
|
||||
<listitem><para>Order by number of tasks/processes in the control group.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -169,26 +169,49 @@
|
||||
pressing the <keycap>%</keycap> key.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-P</option></term>
|
||||
|
||||
<listitem><para>Count only userspace processes instead of all
|
||||
tasks. By default all tasks are counted: each kernel thread
|
||||
and each userspace thread individually. With this setting
|
||||
kernel threads are excluded from the counting and each
|
||||
userspace process only counts as one, regardless how many
|
||||
threads it consists of. This setting may also be toggled at
|
||||
runtime by pressing the <keycap>P</keycap> key. This option
|
||||
may not be combined with
|
||||
<option>-k</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-k</option></term>
|
||||
|
||||
<listitem><para>Include kernel threads when counting tasks in
|
||||
control groups. By default, kernel threads are not included in
|
||||
the count. This setting may also be toggled at runtime by
|
||||
pressing the <keycap>k</keycap> key.</para></listitem>
|
||||
<listitem><para>Count only userspace processes and kernel
|
||||
threads instead of all tasks. By default all tasks are
|
||||
counted: each kernel thread and each userspace thread
|
||||
individually. With this setting kernel threads are included in
|
||||
the counting and each userspace process only counts as on one,
|
||||
regardless how many threads it consists of. This setting may
|
||||
also be toggled at runtime by pressing the <keycap>k</keycap>
|
||||
key. This option may not be combined with
|
||||
<option>-P</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--recursive=</option></term>
|
||||
|
||||
<listitem><para>Controls whether the number of tasks shown for
|
||||
a control group shall include all tasks that are contained in
|
||||
any of the child control groups as well. Takes a boolean
|
||||
argument, defaults to <literal>yes</literal>. If enabled the
|
||||
tasks in child control groups are included, if disabled only
|
||||
the tasks in the control group itself are counted. This
|
||||
setting may also be toggled at runtime by pressing the
|
||||
<keycap>r</keycap> key.</para></listitem>
|
||||
<listitem><para>Controls whether the number of processes shown
|
||||
for a control group shall include all processes that are
|
||||
contained in any of the child control groups as well. Takes a
|
||||
boolean argument, defaults to <literal>yes</literal>. If
|
||||
enabled the processes in child control groups are included, if
|
||||
disabled only the processes in the control group itself are
|
||||
counted. This setting may also be toggled at runtime by
|
||||
pressing the <keycap>r</keycap> key. Note that this setting
|
||||
only applies to process counting, i.e. when the
|
||||
<option>-P</option> or <option>-k</option> options are
|
||||
used. It has not effect if all tasks are counted, in which
|
||||
case the counting is always recursive.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -286,23 +309,35 @@
|
||||
switch.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><keycap>P</keycap></term>
|
||||
|
||||
<listitem><para>Toggle between counting all tasks, or only
|
||||
userspace processes. This setting may also be controlled using
|
||||
the <option>-P</option> command line switch (see
|
||||
above).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><keycap>k</keycap></term>
|
||||
|
||||
<listitem><para>Toggle between including or excluding kernel
|
||||
threads in control group task counts. This setting may also be
|
||||
controlled using the <option>-k</option> command line
|
||||
switch.</para></listitem>
|
||||
<listitem><para>Toggle between counting all tasks, or only
|
||||
userspace processes and kernel threads. This setting may also
|
||||
be controlled using the <option>-k</option> command line
|
||||
switch (see above).</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><keycap>r</keycap></term>
|
||||
|
||||
<listitem><para>Toggle between recursively including or
|
||||
excluding tasks in child control groups in control group task
|
||||
counts. This setting may also be controlled using the
|
||||
<option>--recursive=</option> command line
|
||||
switch.</para></listitem>
|
||||
excluding processes in child control groups in control group
|
||||
process counts. This setting may also be controlled using the
|
||||
<option>--recursive=</option> command line switch. This key is
|
||||
not available of all tasks are counted, it is only available
|
||||
if processes are counted, as enabled with the
|
||||
<keycap>P</keycap> or <keycap>k</keycap>
|
||||
keys.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
@ -51,14 +51,14 @@
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/etc/systemd/system.conf</filename></para>
|
||||
<para><filename>/etc/systemd/system.conf.d/*.conf</filename></para>
|
||||
<para><filename>/run/systemd/system.conf.d/*.conf</filename></para>
|
||||
<para><filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
|
||||
<para><filename>/etc/systemd/user.conf</filename></para>
|
||||
<para><filename>/etc/systemd/user.conf.d/*.conf</filename></para>
|
||||
<para><filename>/run/systemd/user.conf.d/*.conf</filename></para>
|
||||
<para><filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
|
||||
<para><filename>/etc/systemd/system.conf</filename>,
|
||||
<filename>/etc/systemd/system.conf.d/*.conf</filename>,
|
||||
<filename>/run/systemd/system.conf.d/*.conf</filename>,
|
||||
<filename>/usr/lib/systemd/system.conf.d/*.conf</filename></para>
|
||||
<para><filename>/etc/systemd/user.conf</filename>,
|
||||
<filename>/etc/systemd/user.conf.d/*.conf</filename>,
|
||||
<filename>/run/systemd/user.conf.d/*.conf</filename>,
|
||||
<filename>/usr/lib/systemd/user.conf.d/*.conf</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
@ -305,12 +305,14 @@
|
||||
<term><varname>DefaultCPUAccounting=</varname></term>
|
||||
<term><varname>DefaultBlockIOAccounting=</varname></term>
|
||||
<term><varname>DefaultMemoryAccounting=</varname></term>
|
||||
<term><varname>DefaultTasksAccounting=</varname></term>
|
||||
|
||||
<listitem><para>Configure the default resource accounting
|
||||
settings, as configured per-unit by
|
||||
<varname>CPUAccounting=</varname>,
|
||||
<varname>BlockIOAccounting=</varname> and
|
||||
<varname>MemoryAccounting=</varname>. See
|
||||
<varname>BlockIOAccounting=</varname>,
|
||||
<varname>MemoryAccounting=</varname> and
|
||||
<varname>TasksAccounting=</varname>. See
|
||||
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
for details on the per-unit settings.</para></listitem>
|
||||
</varlistentry>
|
||||
|
@ -103,10 +103,10 @@
|
||||
<listitem>
|
||||
<para>Turn on CPU usage accounting for this unit. Takes a
|
||||
boolean argument. Note that turning on CPU accounting for
|
||||
one unit might also implicitly turn it on for all units
|
||||
one unit will also implicitly turn it on for all units
|
||||
contained in the same slice and for all its parent slices
|
||||
and the units contained therein. The system default for this
|
||||
setting maybe controlled with
|
||||
setting may be controlled with
|
||||
<varname>DefaultCPUAccounting=</varname> in
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
@ -134,7 +134,7 @@
|
||||
prioritizing specific services at boot-up differently than
|
||||
during normal runtime.</para>
|
||||
|
||||
<para>Those options imply
|
||||
<para>These options imply
|
||||
<literal>CPUAccounting=true</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -168,9 +168,10 @@
|
||||
<listitem>
|
||||
<para>Turn on process and kernel memory accounting for this
|
||||
unit. Takes a boolean argument. Note that turning on memory
|
||||
accounting for one unit might also implicitly turn it on for
|
||||
all its parent slices. The system default for this setting
|
||||
maybe controlled with
|
||||
accounting for one unit will also implicitly turn it on for
|
||||
all units contained in the same slice and for all its parent
|
||||
slices and the units contained therein. The system default
|
||||
for this setting may be controlled with
|
||||
<varname>DefaultMemoryAccounting=</varname> in
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
@ -186,26 +187,64 @@
|
||||
memory size in bytes. If the value is suffixed with K, M, G
|
||||
or T, the specified memory size is parsed as Kilobytes,
|
||||
Megabytes, Gigabytes, or Terabytes (with the base 1024),
|
||||
respectively. This controls the
|
||||
<literal>memory.limit_in_bytes</literal> control group
|
||||
attribute. For details about this control group attribute,
|
||||
see <ulink
|
||||
respectively. If assigned the special value
|
||||
<literal>infinity</literal> no memory limit is applied. This
|
||||
controls the <literal>memory.limit_in_bytes</literal>
|
||||
control group attribute. For details about this control
|
||||
group attribute, see <ulink
|
||||
url="https://www.kernel.org/doc/Documentation/cgroups/memory.txt">memory.txt</ulink>.</para>
|
||||
|
||||
<para>Implies <literal>MemoryAccounting=true</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>TasksAccounting=</varname></term>
|
||||
|
||||
<listitem>
|
||||
<para>Turn on task accounting for this unit. Takes a
|
||||
boolean argument. If enabled, the system manager will keep
|
||||
track of the number of tasks in the unit. The number of
|
||||
tasks accounted this way includes both kernel threads and
|
||||
userspace processes, with each thread counting
|
||||
individually. Note that turning on tasks accounting for one
|
||||
unit will also implicitly turn it on for all units contained
|
||||
in the same slice and for all its parent slices and the
|
||||
units contained therein. The system default for this setting
|
||||
may be controlled with
|
||||
<varname>DefaultTasksAccounting=</varname> in
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>TasksMax=<replaceable>N</replaceable></varname></term>
|
||||
|
||||
<listitem>
|
||||
<para>Specify the maximum number of tasks that may be
|
||||
created in the unit. This ensures that the number of tasks
|
||||
accounted for the unit (see above) stays below a specific
|
||||
limit. If assigned the special value
|
||||
<literal>infinity</literal> no tasks limit is applied. This
|
||||
controls the <literal>pids.max</literal> control group
|
||||
attribute. For details about this control group attribute,
|
||||
see <ulink
|
||||
url="https://www.kernel.org/doc/Documentation/cgroups/pids.txt">pids.txt</ulink>.</para>
|
||||
|
||||
<para>Implies <literal>TasksAccounting=true</literal>.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>BlockIOAccounting=</varname></term>
|
||||
|
||||
<listitem>
|
||||
<para>Turn on Block IO accounting for this unit. Takes a
|
||||
boolean argument. Note that turning on block IO accounting
|
||||
for one unit might also implicitly turn it on for all units
|
||||
for one unit will also implicitly turn it on for all units
|
||||
contained in the same slice and all for its parent slices
|
||||
and the units contained therein. The system default for this
|
||||
setting maybe controlled with
|
||||
setting may be controlled with
|
||||
<varname>DefaultBlockIOAccounting=</varname> in
|
||||
<citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
</listitem>
|
||||
|
@ -2018,9 +2018,10 @@ int cg_mask_supported(CGroupMask *ret) {
|
||||
mask |= CGROUP_CONTROLLER_TO_MASK(v);
|
||||
}
|
||||
|
||||
/* Currently, we only support the memory controller in
|
||||
* the unified hierarchy, mask everything else off. */
|
||||
mask &= CGROUP_MASK_MEMORY;
|
||||
/* Currently, we only support the memory and pids
|
||||
* controller in the unified hierarchy, mask
|
||||
* everything else off. */
|
||||
mask &= CGROUP_MASK_MEMORY | CGROUP_MASK_PIDS;
|
||||
|
||||
} else {
|
||||
CGroupController c;
|
||||
@ -2212,6 +2213,7 @@ static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
|
||||
[CGROUP_CONTROLLER_BLKIO] = "blkio",
|
||||
[CGROUP_CONTROLLER_MEMORY] = "memory",
|
||||
[CGROUP_CONTROLLER_DEVICES] = "devices",
|
||||
[CGROUP_CONTROLLER_PIDS] = "pids",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController);
|
||||
|
@ -35,6 +35,7 @@ typedef enum CGroupController {
|
||||
CGROUP_CONTROLLER_BLKIO,
|
||||
CGROUP_CONTROLLER_MEMORY,
|
||||
CGROUP_CONTROLLER_DEVICES,
|
||||
CGROUP_CONTROLLER_PIDS,
|
||||
_CGROUP_CONTROLLER_MAX,
|
||||
_CGROUP_CONTROLLER_INVALID = -1,
|
||||
} CGroupController;
|
||||
@ -48,6 +49,7 @@ typedef enum CGroupMask {
|
||||
CGROUP_MASK_BLKIO = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_BLKIO),
|
||||
CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY),
|
||||
CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES),
|
||||
CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS),
|
||||
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
|
||||
} CGroupMask;
|
||||
|
||||
|
@ -45,7 +45,7 @@ typedef struct Group {
|
||||
bool memory_valid:1;
|
||||
bool io_valid:1;
|
||||
|
||||
unsigned n_tasks;
|
||||
uint64_t n_tasks;
|
||||
|
||||
unsigned cpu_iteration;
|
||||
nsec_t cpu_usage;
|
||||
@ -65,7 +65,12 @@ static unsigned arg_iterations = (unsigned) -1;
|
||||
static bool arg_batch = false;
|
||||
static bool arg_raw = false;
|
||||
static usec_t arg_delay = 1*USEC_PER_SEC;
|
||||
static bool arg_kernel_threads = false;
|
||||
|
||||
enum {
|
||||
COUNT_PIDS,
|
||||
COUNT_USERSPACE_PROCESSES,
|
||||
COUNT_ALL_PROCESSES,
|
||||
} arg_count = COUNT_PIDS;
|
||||
static bool arg_recursive = true;
|
||||
|
||||
static enum {
|
||||
@ -73,7 +78,7 @@ static enum {
|
||||
ORDER_TASKS,
|
||||
ORDER_CPU,
|
||||
ORDER_MEMORY,
|
||||
ORDER_IO
|
||||
ORDER_IO,
|
||||
} arg_order = ORDER_CPU;
|
||||
|
||||
static enum {
|
||||
@ -153,7 +158,7 @@ static int process(
|
||||
}
|
||||
}
|
||||
|
||||
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
|
||||
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER) && IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES)) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
pid_t pid;
|
||||
|
||||
@ -166,7 +171,7 @@ static int process(
|
||||
g->n_tasks = 0;
|
||||
while (cg_read_pid(f, &pid) > 0) {
|
||||
|
||||
if (!arg_kernel_threads && is_kernel_thread(pid) > 0)
|
||||
if (arg_count == COUNT_USERSPACE_PROCESSES && is_kernel_thread(pid) > 0)
|
||||
continue;
|
||||
|
||||
g->n_tasks++;
|
||||
@ -175,6 +180,26 @@ static int process(
|
||||
if (g->n_tasks > 0)
|
||||
g->n_tasks_valid = true;
|
||||
|
||||
} else if (streq(controller, "pids") && arg_count == COUNT_PIDS) {
|
||||
_cleanup_free_ char *p = NULL, *v = NULL;
|
||||
|
||||
r = cg_get_path(controller, path, "pids.current", &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = read_one_line_file(p, &v);
|
||||
if (r == -ENOENT)
|
||||
return 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = safe_atou64(v, &g->n_tasks);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (g->n_tasks > 0)
|
||||
g->n_tasks_valid = true;
|
||||
|
||||
} else if (streq(controller, "cpuacct") && cg_unified() <= 0) {
|
||||
_cleanup_free_ char *p = NULL, *v = NULL;
|
||||
uint64_t new_usage;
|
||||
@ -371,6 +396,7 @@ static int refresh_one(
|
||||
return r;
|
||||
|
||||
if (arg_recursive &&
|
||||
IN_SET(arg_count, COUNT_ALL_PROCESSES, COUNT_USERSPACE_PROCESSES) &&
|
||||
child &&
|
||||
child->n_tasks_valid &&
|
||||
streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
|
||||
@ -407,6 +433,9 @@ static int refresh(const char *root, Hashmap *a, Hashmap *b, unsigned iteration)
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = refresh_one("blkio", root, a, b, iteration, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = refresh_one("pids", root, a, b, iteration, 0, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -549,7 +578,7 @@ static void display(Hashmap *a) {
|
||||
printf("%s%-*s%s %s%7s%s %s%s%s %s%8s%s %s%8s%s %s%8s%s\n\n",
|
||||
arg_order == ORDER_PATH ? ON : "", path_columns, "Control Group",
|
||||
arg_order == ORDER_PATH ? OFF : "",
|
||||
arg_order == ORDER_TASKS ? ON : "", "Tasks",
|
||||
arg_order == ORDER_TASKS ? ON : "", arg_count == COUNT_PIDS ? "Tasks" : arg_count == COUNT_USERSPACE_PROCESSES ? "Procs" : "Proc+",
|
||||
arg_order == ORDER_TASKS ? OFF : "",
|
||||
arg_order == ORDER_CPU ? ON : "", buffer,
|
||||
arg_order == ORDER_CPU ? OFF : "",
|
||||
@ -576,7 +605,7 @@ static void display(Hashmap *a) {
|
||||
printf("%-*s", path_columns, ellipsized ?: path);
|
||||
|
||||
if (g->n_tasks_valid)
|
||||
printf(" %7u", g->n_tasks);
|
||||
printf(" %7" PRIu64, g->n_tasks);
|
||||
else
|
||||
fputs(" -", stdout);
|
||||
|
||||
@ -602,15 +631,16 @@ static void help(void) {
|
||||
" -h --help Show this help\n"
|
||||
" --version Show package version\n"
|
||||
" -p --order=path Order by path\n"
|
||||
" -t --order=tasks Order by number of tasks\n"
|
||||
" -t --order=tasks Order by number of tasks/processes\n"
|
||||
" -c --order=cpu Order by CPU load (default)\n"
|
||||
" -m --order=memory Order by memory load\n"
|
||||
" -i --order=io Order by IO load\n"
|
||||
" -r --raw Provide raw (not human-readable) numbers\n"
|
||||
" --cpu=percentage Show CPU usage as percentage (default)\n"
|
||||
" --cpu=time Show CPU usage as time\n"
|
||||
" -k Include kernel threads in task count\n"
|
||||
" --recursive=BOOL Sum up task count recursively\n"
|
||||
" -P Count userspace processes instead of tasks (excl. kernel)\n"
|
||||
" -k Count all processes instead of tasks (incl. kernel)\n"
|
||||
" --recursive=BOOL Sum up process count recursively\n"
|
||||
" -d --delay=DELAY Delay between updates\n"
|
||||
" -n --iterations=N Run for N iterations before exiting\n"
|
||||
" -b --batch Run in batch mode, accepting no input\n"
|
||||
@ -642,12 +672,13 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{}
|
||||
};
|
||||
|
||||
bool recursive_unset = false;
|
||||
int c, r;
|
||||
|
||||
assert(argc >= 1);
|
||||
assert(argv);
|
||||
|
||||
while ((c = getopt_long(argc, argv, "hptcmin:brd:k", options, NULL)) >= 0)
|
||||
while ((c = getopt_long(argc, argv, "hptcmin:brd:kP", options, NULL)) >= 0)
|
||||
|
||||
switch (c) {
|
||||
|
||||
@ -748,7 +779,11 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
arg_kernel_threads = true;
|
||||
arg_count = COUNT_ALL_PROCESSES;
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
arg_count = COUNT_USERSPACE_PROCESSES;
|
||||
break;
|
||||
|
||||
case ARG_RECURSIVE:
|
||||
@ -759,6 +794,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
arg_recursive = r;
|
||||
recursive_unset = r == 0;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
@ -773,9 +809,23 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (recursive_unset && arg_count == COUNT_PIDS) {
|
||||
log_error("Non-recursive counting is only supported when counting processes, not tasks. Use -P or -k.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const char* counting_what(void) {
|
||||
if (arg_count == COUNT_PIDS)
|
||||
return "tasks";
|
||||
else if (arg_count == COUNT_ALL_PROCESSES)
|
||||
return "all processes (incl. kernel)";
|
||||
else
|
||||
return "userspace processes (excl. kernel)";
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int r;
|
||||
Hashmap *a = NULL, *b = NULL;
|
||||
@ -783,10 +833,19 @@ int main(int argc, char *argv[]) {
|
||||
usec_t last_refresh = 0;
|
||||
bool quit = false, immediate_refresh = false;
|
||||
_cleanup_free_ char *root = NULL;
|
||||
CGroupMask mask;
|
||||
|
||||
log_parse_environment();
|
||||
log_open();
|
||||
|
||||
r = cg_mask_supported(&mask);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Failed to determine supported controllers: %m");
|
||||
goto finish;
|
||||
}
|
||||
|
||||
arg_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_USERSPACE_PROCESSES;
|
||||
|
||||
r = parse_argv(argc, argv);
|
||||
if (r <= 0)
|
||||
goto finish;
|
||||
@ -899,15 +958,26 @@ int main(int argc, char *argv[]) {
|
||||
break;
|
||||
|
||||
case 'k':
|
||||
arg_kernel_threads = !arg_kernel_threads;
|
||||
fprintf(stdout, "\nCounting kernel threads: %s.", yes_no(arg_kernel_threads));
|
||||
arg_count = arg_count != COUNT_ALL_PROCESSES ? COUNT_ALL_PROCESSES : COUNT_PIDS;
|
||||
fprintf(stdout, "\nCounting: %s.", counting_what());
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
break;
|
||||
|
||||
case 'P':
|
||||
arg_count = arg_count != COUNT_USERSPACE_PROCESSES ? COUNT_USERSPACE_PROCESSES : COUNT_PIDS;
|
||||
fprintf(stdout, "\nCounting: %s.", counting_what());
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
arg_recursive = !arg_recursive;
|
||||
fprintf(stdout, "\nRecursive task counting: %s", yes_no(arg_recursive));
|
||||
if (arg_count == COUNT_PIDS)
|
||||
fprintf(stdout, "\n\aCannot toggle recursive counting, not available in task counting mode.");
|
||||
else {
|
||||
arg_recursive = !arg_recursive;
|
||||
fprintf(stdout, "\nRecursive process counting: %s", yes_no(arg_recursive));
|
||||
}
|
||||
fflush(stdout);
|
||||
sleep(1);
|
||||
break;
|
||||
@ -939,9 +1009,10 @@ int main(int argc, char *argv[]) {
|
||||
case '?':
|
||||
case 'h':
|
||||
fprintf(stdout,
|
||||
"\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n"
|
||||
"\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks/procs; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n"
|
||||
"\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n"
|
||||
"\t<" ON "k" OFF "> Count kernel threads; <" ON "r" OFF "> Count recursively; <" ON "q" OFF "> Quit");
|
||||
"\t<" ON "P" OFF "> Toggle count userspace processes; <" ON "k" OFF "> Toggle count all processes\n"
|
||||
"\t<" ON "r" OFF "> Count processes recursively; <" ON "q" OFF "> Quit");
|
||||
fflush(stdout);
|
||||
sleep(3);
|
||||
break;
|
||||
|
@ -22,10 +22,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include "process-util.h"
|
||||
#include "path-util.h"
|
||||
#include "special.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "special.h"
|
||||
|
||||
#include "cgroup.h"
|
||||
|
||||
#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
|
||||
@ -41,6 +42,7 @@ void cgroup_context_init(CGroupContext *c) {
|
||||
c->memory_limit = (uint64_t) -1;
|
||||
c->blockio_weight = (unsigned long) -1;
|
||||
c->startup_blockio_weight = (unsigned long) -1;
|
||||
c->tasks_max = (uint64_t) -1;
|
||||
|
||||
c->cpu_quota_per_sec_usec = USEC_INFINITY;
|
||||
}
|
||||
@ -106,6 +108,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
||||
"%sBlockIOWeight=%lu\n"
|
||||
"%sStartupBlockIOWeight=%lu\n"
|
||||
"%sMemoryLimit=%" PRIu64 "\n"
|
||||
"%sTasksMax=%" PRIu64 "\n"
|
||||
"%sDevicePolicy=%s\n"
|
||||
"%sDelegate=%s\n",
|
||||
prefix, yes_no(c->cpu_accounting),
|
||||
@ -117,6 +120,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
|
||||
prefix, c->blockio_weight,
|
||||
prefix, c->startup_blockio_weight,
|
||||
prefix, c->memory_limit,
|
||||
prefix, c->tasks_max,
|
||||
prefix, cgroup_device_policy_to_string(c->device_policy),
|
||||
prefix, yes_no(c->delegate));
|
||||
|
||||
@ -466,6 +470,21 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
|
||||
log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
|
||||
}
|
||||
}
|
||||
|
||||
if ((mask & CGROUP_MASK_PIDS) && !is_root) {
|
||||
|
||||
if (c->tasks_max != (uint64_t) -1) {
|
||||
char buf[DECIMAL_STR_MAX(uint64_t) + 2];
|
||||
|
||||
sprintf(buf, "%" PRIu64 "\n", c->tasks_max);
|
||||
r = cg_set_attribute("pids", path, "pids.max", buf);
|
||||
} else
|
||||
r = cg_set_attribute("pids", path, "pids.max", "max");
|
||||
|
||||
if (r < 0)
|
||||
log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
|
||||
"Failed to set pids.max on %s: %m", path);
|
||||
}
|
||||
}
|
||||
|
||||
CGroupMask cgroup_context_get_mask(CGroupContext *c) {
|
||||
@ -494,6 +513,10 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
|
||||
c->device_policy != CGROUP_AUTO)
|
||||
mask |= CGROUP_MASK_DEVICES;
|
||||
|
||||
if (c->tasks_accounting ||
|
||||
c->tasks_max != (uint64_t) -1)
|
||||
mask |= CGROUP_MASK_PIDS;
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
@ -1459,6 +1482,28 @@ int unit_get_memory_current(Unit *u, uint64_t *ret) {
|
||||
return safe_atou64(v, ret);
|
||||
}
|
||||
|
||||
int unit_get_tasks_current(Unit *u, uint64_t *ret) {
|
||||
_cleanup_free_ char *v = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
assert(ret);
|
||||
|
||||
if (!u->cgroup_path)
|
||||
return -ENODATA;
|
||||
|
||||
if ((u->cgroup_realized_mask & CGROUP_MASK_PIDS) == 0)
|
||||
return -ENODATA;
|
||||
|
||||
r = cg_get_attribute("pids", u->cgroup_path, "pids.current", &v);
|
||||
if (r == -ENOENT)
|
||||
return -ENODATA;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return safe_atou64(v, ret);
|
||||
}
|
||||
|
||||
static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
|
||||
_cleanup_free_ char *v = NULL;
|
||||
uint64_t ns;
|
||||
|
@ -72,6 +72,7 @@ struct CGroupContext {
|
||||
bool cpu_accounting;
|
||||
bool blockio_accounting;
|
||||
bool memory_accounting;
|
||||
bool tasks_accounting;
|
||||
|
||||
unsigned long cpu_shares;
|
||||
unsigned long startup_cpu_shares;
|
||||
@ -88,6 +89,8 @@ struct CGroupContext {
|
||||
LIST_HEAD(CGroupDeviceAllow, device_allow);
|
||||
|
||||
bool delegate;
|
||||
|
||||
uint64_t tasks_max;
|
||||
};
|
||||
|
||||
#include "unit.h"
|
||||
@ -137,6 +140,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret);
|
||||
int unit_watch_all_pids(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);
|
||||
int unit_reset_cpu_usage(Unit *u);
|
||||
|
||||
|
@ -168,6 +168,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
|
||||
SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
|
||||
SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
|
||||
SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
|
||||
SD_BUS_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
|
||||
SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
@ -551,7 +553,11 @@ int bus_cgroup_set_property(
|
||||
if (mode != UNIT_CHECK) {
|
||||
c->memory_limit = limit;
|
||||
u->cgroup_realized_mask &= ~CGROUP_MASK_MEMORY;
|
||||
unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
|
||||
|
||||
if (limit == (uint64_t) -1)
|
||||
unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
|
||||
else
|
||||
unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, limit);
|
||||
}
|
||||
|
||||
return 1;
|
||||
@ -667,6 +673,39 @@ int bus_cgroup_set_property(
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "TasksAccounting")) {
|
||||
int b;
|
||||
|
||||
r = sd_bus_message_read(message, "b", &b);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
c->tasks_accounting = b;
|
||||
u->cgroup_realized_mask &= ~CGROUP_MASK_PIDS;
|
||||
unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
} else if (streq(name, "TasksMax")) {
|
||||
uint64_t limit;
|
||||
|
||||
r = sd_bus_message_read(message, "t", &limit);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (mode != UNIT_CHECK) {
|
||||
c->tasks_max = limit;
|
||||
u->cgroup_realized_mask &= ~CGROUP_MASK_PIDS;
|
||||
|
||||
if (limit == (uint64_t) -1)
|
||||
unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
|
||||
else
|
||||
unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (u->transient && u->load_state == UNIT_STUB) {
|
||||
|
@ -736,6 +736,30 @@ static int property_get_current_memory(
|
||||
return sd_bus_message_append(reply, "t", sz);
|
||||
}
|
||||
|
||||
static int property_get_current_tasks(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
uint64_t cn = (uint64_t) -1;
|
||||
Unit *u = userdata;
|
||||
int r;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(u);
|
||||
|
||||
r = unit_get_tasks_current(u, &cn);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m");
|
||||
|
||||
return sd_bus_message_append(reply, "t", cn);
|
||||
}
|
||||
|
||||
static int property_get_cpu_usage(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
@ -796,6 +820,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
|
||||
SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0),
|
||||
SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
|
||||
SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
|
||||
SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
|
||||
SD_BUS_VTABLE_END
|
||||
};
|
||||
|
||||
|
@ -124,6 +124,8 @@ $1.StartupBlockIOWeight, config_parse_blockio_weight, 0,
|
||||
$1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context)
|
||||
$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
|
||||
$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
|
||||
$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
|
||||
$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context)
|
||||
$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)'
|
||||
)m4_dnl
|
||||
Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
|
||||
|
@ -2686,7 +2686,7 @@ int config_parse_memory_limit(
|
||||
off_t bytes;
|
||||
int r;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
if (isempty(rvalue) || streq(rvalue, "infinity")) {
|
||||
c->memory_limit = (uint64_t) -1;
|
||||
return 0;
|
||||
}
|
||||
@ -2694,9 +2694,8 @@ int config_parse_memory_limit(
|
||||
assert_cc(sizeof(uint64_t) == sizeof(off_t));
|
||||
|
||||
r = parse_size(rvalue, 1024, &bytes);
|
||||
if (r < 0) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL,
|
||||
"Memory limit '%s' invalid. Ignoring.", rvalue);
|
||||
if (r < 0 || bytes < 1) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Memory limit '%s' invalid. Ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -2704,6 +2703,36 @@ int config_parse_memory_limit(
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_tasks_max(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
unsigned line,
|
||||
const char *section,
|
||||
unsigned section_line,
|
||||
const char *lvalue,
|
||||
int ltype,
|
||||
const char *rvalue,
|
||||
void *data,
|
||||
void *userdata) {
|
||||
|
||||
CGroupContext *c = data;
|
||||
uint64_t u;
|
||||
int r;
|
||||
|
||||
if (isempty(rvalue) || streq(rvalue, "infinity")) {
|
||||
c->tasks_max = (uint64_t) -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = safe_atou64(rvalue, &u);
|
||||
if (r < 0 || u < 1) {
|
||||
log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int config_parse_device_allow(
|
||||
const char *unit,
|
||||
const char *filename,
|
||||
|
@ -84,6 +84,7 @@ int config_parse_environ(const char *unit, const char *filename, unsigned line,
|
||||
int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_device_policy(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_device_allow(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
int config_parse_blockio_weight(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
|
||||
|
@ -114,6 +114,7 @@ static FILE* arg_serialization = NULL;
|
||||
static bool arg_default_cpu_accounting = false;
|
||||
static bool arg_default_blockio_accounting = false;
|
||||
static bool arg_default_memory_accounting = false;
|
||||
static bool arg_default_tasks_accounting = false;
|
||||
|
||||
static void nop_handler(int sig) {}
|
||||
|
||||
@ -676,6 +677,7 @@ static int parse_config_file(void) {
|
||||
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
|
||||
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
|
||||
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
|
||||
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -704,6 +706,7 @@ static void manager_set_defaults(Manager *m) {
|
||||
m->default_cpu_accounting = arg_default_cpu_accounting;
|
||||
m->default_blockio_accounting = arg_default_blockio_accounting;
|
||||
m->default_memory_accounting = arg_default_memory_accounting;
|
||||
m->default_tasks_accounting = arg_default_tasks_accounting;
|
||||
|
||||
manager_set_default_rlimits(m, arg_default_rlimit);
|
||||
manager_environment_add(m, NULL, arg_default_environment);
|
||||
|
@ -256,6 +256,7 @@ struct Manager {
|
||||
bool default_cpu_accounting;
|
||||
bool default_memory_accounting;
|
||||
bool default_blockio_accounting;
|
||||
bool default_tasks_accounting;
|
||||
|
||||
usec_t default_timer_accuracy_usec;
|
||||
|
||||
|
@ -125,6 +125,7 @@ static void unit_init(Unit *u) {
|
||||
cc->cpu_accounting = u->manager->default_cpu_accounting;
|
||||
cc->blockio_accounting = u->manager->default_blockio_accounting;
|
||||
cc->memory_accounting = u->manager->default_memory_accounting;
|
||||
cc->tasks_accounting = u->manager->default_tasks_accounting;
|
||||
}
|
||||
|
||||
ec = unit_get_exec_context(u);
|
||||
|
@ -1421,7 +1421,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
return bus_log_create_error(r);
|
||||
|
||||
if (STR_IN_SET(field,
|
||||
"CPUAccounting", "MemoryAccounting", "BlockIOAccounting",
|
||||
"CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting",
|
||||
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
|
||||
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit")) {
|
||||
|
||||
@ -1436,14 +1436,33 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
|
||||
} else if (streq(field, "MemoryLimit")) {
|
||||
off_t bytes;
|
||||
|
||||
r = parse_size(eq, 1024, &bytes);
|
||||
if (r < 0) {
|
||||
log_error("Failed to parse bytes specification %s", assignment);
|
||||
return -EINVAL;
|
||||
if (isempty(eq) || streq(eq, "infinity"))
|
||||
bytes = (uint64_t) -1;
|
||||
else {
|
||||
r = parse_size(eq, 1024, &bytes);
|
||||
if (r < 0) {
|
||||
log_error("Failed to parse bytes specification %s", assignment);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", (uint64_t) bytes);
|
||||
|
||||
} else if (streq(field, "TasksMax")) {
|
||||
uint64_t n;
|
||||
|
||||
if (isempty(eq) || streq(eq, "infinity"))
|
||||
n = (uint64_t) -1;
|
||||
else {
|
||||
r = safe_atou64(eq, &n);
|
||||
if (r < 0) {
|
||||
log_error("Failed to parse maximum tasks specification %s", assignment);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
r = sd_bus_message_append(m, "v", "t", n);
|
||||
|
||||
} else if (STR_IN_SET(field, "CPUShares", "BlockIOWeight")) {
|
||||
uint64_t u;
|
||||
|
||||
|
@ -20,59 +20,60 @@
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/reboot.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <locale.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-daemon.h"
|
||||
#include "sd-login.h"
|
||||
#include "sd-bus.h"
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "macro.h"
|
||||
#include "set.h"
|
||||
#include "utmp-wtmp.h"
|
||||
#include "special.h"
|
||||
#include "initreq.h"
|
||||
#include "path-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
#include "build.h"
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-util.h"
|
||||
#include "cgroup-show.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "list.h"
|
||||
#include "path-lookup.h"
|
||||
#include "exit-status.h"
|
||||
#include "build.h"
|
||||
#include "unit-name.h"
|
||||
#include "pager.h"
|
||||
#include "spawn-ask-password-agent.h"
|
||||
#include "spawn-polkit-agent.h"
|
||||
#include "install.h"
|
||||
#include "logs-show.h"
|
||||
#include "socket-util.h"
|
||||
#include "fileio.h"
|
||||
#include "copy.h"
|
||||
#include "env-util.h"
|
||||
#include "bus-util.h"
|
||||
#include "bus-message.h"
|
||||
#include "bus-error.h"
|
||||
#include "bus-common-errors.h"
|
||||
#include "mkdir.h"
|
||||
#include "dropin.h"
|
||||
#include "efivars.h"
|
||||
#include "env-util.h"
|
||||
#include "exit-status.h"
|
||||
#include "fileio.h"
|
||||
#include "formats-util.h"
|
||||
#include "process-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "hostname-util.h"
|
||||
#include "initreq.h"
|
||||
#include "install.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "logs-show.h"
|
||||
#include "macro.h"
|
||||
#include "mkdir.h"
|
||||
#include "pager.h"
|
||||
#include "path-lookup.h"
|
||||
#include "path-util.h"
|
||||
#include "process-util.h"
|
||||
#include "set.h"
|
||||
#include "signal-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "spawn-ask-password-agent.h"
|
||||
#include "spawn-polkit-agent.h"
|
||||
#include "special.h"
|
||||
#include "strv.h"
|
||||
#include "terminal-util.h"
|
||||
#include "unit-name.h"
|
||||
#include "util.h"
|
||||
#include "utmp-wtmp.h"
|
||||
|
||||
static char **arg_types = NULL;
|
||||
static char **arg_states = NULL;
|
||||
@ -3285,6 +3286,8 @@ typedef struct UnitStatusInfo {
|
||||
uint64_t memory_current;
|
||||
uint64_t memory_limit;
|
||||
uint64_t cpu_usage_nsec;
|
||||
uint64_t tasks_current;
|
||||
uint64_t tasks_max;
|
||||
|
||||
LIST_HEAD(ExecStatusInfo, exec);
|
||||
} UnitStatusInfo;
|
||||
@ -3543,6 +3546,15 @@ static void print_status_info(
|
||||
if (i->status_errno > 0)
|
||||
printf(" Error: %i (%s)\n", i->status_errno, strerror(i->status_errno));
|
||||
|
||||
if (i->tasks_current != (uint64_t) -1) {
|
||||
printf(" Tasks: %" PRIu64, i->tasks_current);
|
||||
|
||||
if (i->tasks_max != (uint64_t) -1)
|
||||
printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
|
||||
else
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (i->memory_current != (uint64_t) -1) {
|
||||
char buf[FORMAT_BYTES_MAX];
|
||||
|
||||
@ -3776,6 +3788,10 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
|
||||
i->memory_current = u;
|
||||
else if (streq(name, "MemoryLimit"))
|
||||
i->memory_limit = u;
|
||||
else if (streq(name, "TasksCurrent"))
|
||||
i->tasks_current = u;
|
||||
else if (streq(name, "TasksMax"))
|
||||
i->tasks_max = u;
|
||||
else if (streq(name, "CPUUsageNSec"))
|
||||
i->cpu_usage_nsec = u;
|
||||
|
||||
@ -4252,6 +4268,8 @@ static int show_one(
|
||||
.memory_current = (uint64_t) -1,
|
||||
.memory_limit = (uint64_t) -1,
|
||||
.cpu_usage_nsec = (uint64_t) -1,
|
||||
.tasks_current = (uint64_t) -1,
|
||||
.tasks_max = (uint64_t) -1,
|
||||
};
|
||||
ExecStatusInfo *p;
|
||||
int r;
|
||||
|
Loading…
Reference in New Issue
Block a user