• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 19448983682

17 Nov 2025 11:32PM UTC coverage: 72.503% (-0.2%) from 72.719%
19448983682

push

github

web-flow
core/unit: unit_process_job() tweaks (#39753)

6 of 8 new or added lines in 1 file covered. (75.0%)

3363 existing lines in 68 files now uncovered.

308308 of 425234 relevant lines covered (72.5%)

1141671.45 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.08
/src/basic/limits-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <unistd.h>
4

5
#include "alloc-util.h"
6
#include "cgroup-util.h"
7
#include "limits-util.h"
8
#include "log.h"
9
#include "memory-util.h"
10
#include "parse-util.h"
11
#include "process-util.h"
12
#include "procfs-util.h"
13

14
uint64_t physical_memory(void) {
8,788✔
15
        _cleanup_free_ char *root = NULL, *value = NULL;
8,788✔
16
        uint64_t mem, lim;
8,788✔
17
        size_t ps;
8,788✔
18
        long sc;
8,788✔
19
        int r;
8,788✔
20

21
        /* We return this as uint64_t in case we are running as 32-bit process on a 64-bit kernel with huge amounts of
22
         * memory.
23
         *
24
         * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
25
         * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
26

27
        sc = sysconf(_SC_PHYS_PAGES);
8,788✔
28
        assert(sc > 0);
8,788✔
29

30
        ps = page_size();
8,788✔
31
        mem = (uint64_t) sc * (uint64_t) ps;
8,788✔
32

33
        r = cg_get_root_path(&root);
8,788✔
34
        if (r < 0) {
8,788✔
35
                log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
×
36
                return mem;
×
37
        }
38

39
        r = cg_get_attribute(root, "memory.max", &value);
8,788✔
40
        if (r == -ENOENT) /* Field does not exist on the system's top-level cgroup, hence don't
8,788✔
41
                           * complain. (Note that it might exist on our own root though, if we live
42
                           * in a cgroup namespace, hence check anyway instead of not even
43
                           * trying.) */
44
                return mem;
45
        if (r < 0) {
7,976✔
UNCOV
46
                log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
×
UNCOV
47
                return mem;
×
48
        }
49

50
        if (streq(value, "max"))
7,976✔
51
                return mem;
52

53
        r = safe_atou64(value, &lim);
×
UNCOV
54
        if (r < 0) {
×
UNCOV
55
                log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
×
UNCOV
56
                return mem;
×
57
        }
UNCOV
58
        if (lim == UINT64_MAX)
×
59
                return mem;
60

61
        /* Make sure the limit is a multiple of our own page size */
62
        lim /= ps;
×
UNCOV
63
        lim *= ps;
×
64

UNCOV
65
        return MIN(mem, lim);
×
66
}
67

68
uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
371✔
69
        uint64_t p, m, ps;
371✔
70

71
        /* Shortcut two special cases */
72
        if (v == 0)
371✔
73
                return 0;
74
        if (v == max)
367✔
75
                return physical_memory();
4✔
76

77
        assert(max > 0);
363✔
78

79
        /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
80
         * the result is a multiple of the page size (rounds down). */
81

82
        ps = page_size();
363✔
83
        assert(ps > 0);
363✔
84

85
        p = physical_memory() / ps;
363✔
86
        assert(p > 0);
363✔
87

88
        if (v > UINT64_MAX / p)
363✔
89
                return UINT64_MAX;
90

91
        m = p * v;
362✔
92
        m /= max;
362✔
93

94
        if (m > UINT64_MAX / ps)
362✔
95
                return UINT64_MAX;
96

97
        return m * ps;
362✔
98
}
99

100
uint64_t system_tasks_max(void) {
12,125✔
101
        uint64_t a = TASKS_MAX, b = TASKS_MAX, c = TASKS_MAX;
12,125✔
102
        _cleanup_free_ char *root = NULL;
12,125✔
103
        int r;
12,125✔
104

105
        /* Determine the maximum number of tasks that may run on this system. We check three sources to
106
         * determine this limit:
107
         *
108
         * a) kernel.threads-max sysctl: the maximum number of tasks (threads) the kernel allows.
109
         *
110
         *    This puts a direct limit on the number of concurrent tasks.
111
         *
112
         * b) kernel.pid_max sysctl: the maximum PID value.
113
         *
114
         *    This limits the numeric range PIDs can take, and thus indirectly also limits the number of
115
         *    concurrent threads. It's primarily a compatibility concept: some crappy old code used a signed
116
         *    16-bit type for PIDs, hence the kernel provides a way to ensure the PIDs never go beyond
117
         *    INT16_MAX by default.
118
         *
119
         *    Also note the weird definition: PIDs assigned will be kept below this value, which means
120
         *    the number of tasks that can be created is one lower, as PID 0 is not a valid process ID.
121
         *
122
         * c) pids.max on the root cgroup: the kernel's configured maximum number of tasks.
123
         *
124
         * and then pick the smallest of the three.
125
         *
126
         * By default pid_max is set to much lower values than threads-max, hence the limit people come into
127
         * contact with first, as it's the lowest boundary they need to bump when they want higher number of
128
         * processes.
129
         */
130

131
        r = procfs_get_threads_max(&a);
12,125✔
132
        if (r < 0)
12,125✔
UNCOV
133
                log_debug_errno(r, "Failed to read kernel.threads-max, ignoring: %m");
×
134

135
        r = procfs_get_pid_max(&b);
12,125✔
136
        if (r < 0)
12,125✔
UNCOV
137
                log_debug_errno(r, "Failed to read kernel.pid_max, ignoring: %m");
×
138
        else if (b > 0)
12,125✔
139
                /* Subtract one from pid_max, since PID 0 is not a valid PID */
140
                b--;
12,125✔
141

142
        r = cg_get_root_path(&root);
12,125✔
143
        if (r < 0)
12,125✔
UNCOV
144
                log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
×
145
        else {
146
                /* We'll have the "pids.max" attribute on the our root cgroup only if we are in a
147
                 * CLONE_NEWCGROUP namespace. On the top-level namespace this attribute is missing, hence
148
                 * suppress any message about that */
149
                r = cg_get_attribute_as_uint64(root, "pids.max", &c);
12,125✔
150
                if (r < 0 && r != -ENODATA)
12,125✔
UNCOV
151
                        log_debug_errno(r, "Failed to read pids.max attribute of root cgroup, ignoring: %m");
×
152
        }
153

154
        return MIN3(a, b, c);
12,125✔
155
}
156

157
uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
9,349✔
158
        uint64_t t, m;
9,349✔
159

160
        /* Shortcut two special cases */
161
        if (v == 0)
9,349✔
162
                return 0;
163
        if (v == max)
9,345✔
164
                return system_tasks_max();
4✔
165

166
        assert(max > 0);
9,341✔
167

168
        /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
169
         * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
170

171
        t = system_tasks_max();
9,341✔
172
        assert(t > 0);
9,341✔
173

174
        if (v > UINT64_MAX / t) /* overflow? */
9,341✔
175
                return UINT64_MAX;
176

177
        m = t * v;
9,340✔
178
        return m / max;
9,340✔
179
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc