mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
Merge pull request #1239 from poettering/cgroup-pids
core: add support for the "pids" cgroup controller
This commit is contained in:
commit
a18f3caa56
@ -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':
|
||||
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 task counting: %s", yes_no(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,15 +2686,14 @@ int config_parse_memory_limit(
|
||||
uint64_t bytes;
|
||||
int r;
|
||||
|
||||
if (isempty(rvalue)) {
|
||||
if (isempty(rvalue) || streq(rvalue, "infinity")) {
|
||||
c->memory_limit = (uint64_t) -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -2702,6 +2701,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")) {
|
||||
uint64_t bytes;
|
||||
|
||||
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", 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