1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2011 Red Hat, Inc.
4 * Copyright (C) 2021 Xie Ziyao <[email protected]>
5 */
6
7 /*\
8 * [Description]
9 *
10 * Test ru_maxrss behaviors in struct rusage.
11 *
12 * This test program is backported from upstream commit: 1f10206cf8e9, which
13 * fills ru_maxrss value in struct rusage according to rss hiwater mark. To
14 * make sure this feature works correctly, a series of tests are executed in
15 * this program.
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20
21 #include "tst_test.h"
22 #include "getrusage03.h"
23
24 #define TESTBIN "getrusage03_child"
25
26 static struct rusage ru;
27 static long maxrss_init;
28
29 static const char *const resource[] = {
30 TESTBIN,
31 NULL,
32 };
33
inherit_fork1(void)34 static void inherit_fork1(void)
35 {
36 SAFE_GETRUSAGE(RUSAGE_SELF, &ru);
37 maxrss_init = ru.ru_maxrss;
38
39 if (!SAFE_FORK()) {
40 SAFE_GETRUSAGE(RUSAGE_SELF, &ru);
41
42 if (is_in_delta(maxrss_init - ru.ru_maxrss))
43 tst_res(TPASS, "initial.self ~= child.self");
44 else
45 tst_res(TFAIL, "child.self = %li, expected %li",
46 ru.ru_maxrss, maxrss_init);
47 exit(0);
48 }
49 tst_reap_children();
50 }
51
inherit_fork2(void)52 static void inherit_fork2(void)
53 {
54 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
55
56 if (is_in_delta(ru.ru_maxrss - 102400))
57 tst_res(TPASS, "initial.children ~= 100MB");
58 else
59 tst_res(TFAIL, "initial.children = %li, expected %i",
60 ru.ru_maxrss, 102400);
61
62 if (!SAFE_FORK()) {
63 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
64
65 if (!ru.ru_maxrss)
66 tst_res(TPASS, "child.children == 0");
67 else
68 tst_res(TFAIL, "child.children = %li, expected %i",
69 ru.ru_maxrss, 0);
70 exit(0);
71 }
72 tst_reap_children();
73 }
74
grandchild_maxrss(void)75 static void grandchild_maxrss(void)
76 {
77 if (!SAFE_FORK())
78 SAFE_EXECLP("getrusage03_child", "getrusage03_child",
79 "grand_consume", "300", NULL);
80 tst_reap_children();
81 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
82
83 if (is_in_delta(ru.ru_maxrss - 307200))
84 tst_res(TPASS, "child.children ~= 300MB");
85 else
86 tst_res(TFAIL, "child.children = %li, expected %i",
87 ru.ru_maxrss, 307200);
88 }
89
zombie(void)90 static void zombie(void)
91 {
92 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
93 maxrss_init = ru.ru_maxrss;
94
95 pid_t pid = SAFE_FORK();
96
97 if (!pid)
98 SAFE_EXECLP("getrusage03_child", "getrusage03_child",
99 "consume", "400", NULL);
100
101 TST_PROCESS_STATE_WAIT(pid, 'Z', 0);
102 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
103 if (is_in_delta(ru.ru_maxrss - maxrss_init))
104 tst_res(TPASS, "initial.children ~= pre_wait.children");
105 else
106 tst_res(TFAIL, "pre_wait.children = %li, expected %li",
107 ru.ru_maxrss, maxrss_init);
108
109 tst_reap_children();
110 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
111 if (is_in_delta(ru.ru_maxrss - 409600))
112 tst_res(TPASS, "post_wait.children ~= 400MB");
113 else
114 tst_res(TFAIL, "post_wait.children = %li, expected %i",
115 ru.ru_maxrss, 409600);
116 }
117
sig_ign(void)118 static void sig_ign(void)
119 {
120 SAFE_SIGNAL(SIGCHLD, SIG_IGN);
121 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
122 maxrss_init = ru.ru_maxrss;
123
124 pid_t pid = SAFE_FORK();
125
126 if (!pid)
127 SAFE_EXECLP("getrusage03_child", "getrusage03_child",
128 "consume", "500", NULL);
129
130 TST_PROCESS_EXIT_WAIT(pid, 0);
131 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
132 if (is_in_delta(ru.ru_maxrss - maxrss_init))
133 tst_res(TPASS, "initial.children ~= after_zombie.children");
134 else
135 tst_res(TFAIL, "after_zombie.children = %li, expected %li",
136 ru.ru_maxrss, maxrss_init);
137
138 SAFE_SIGNAL(SIGCHLD, SIG_DFL);
139 }
140
inherit_exec(void)141 static void inherit_exec(void)
142 {
143 if (!SAFE_FORK()) {
144 char str_maxrss_self[BUFSIZ], str_maxrss_child[BUFSIZ];
145
146 SAFE_GETRUSAGE(RUSAGE_SELF, &ru);
147 sprintf(str_maxrss_self, "%ld", ru.ru_maxrss);
148 SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
149 sprintf(str_maxrss_child, "%ld", ru.ru_maxrss);
150
151 SAFE_EXECLP("getrusage03_child", "getrusage03_child",
152 "compare", str_maxrss_self, str_maxrss_child, NULL);
153 }
154 tst_reap_children();
155 }
156
157 void (*testfunc_list[])(void) = {
158 inherit_fork1, inherit_fork2, grandchild_maxrss,
159 zombie, sig_ign, inherit_exec
160 };
161
run(unsigned int i)162 static void run(unsigned int i)
163 {
164 if (!SAFE_FORK()) {
165 if (!SAFE_FORK()) {
166 consume_mb(100);
167 exit(0);
168 }
169
170 SAFE_WAIT(NULL);
171
172 testfunc_list[i]();
173 }
174 }
175
176 static struct tst_test test = {
177 .forks_child = 1,
178 .child_needs_reinit = 1,
179 .resource_files = resource,
180 .min_mem_avail = 512,
181 .tags = (const struct tst_tag[]) {
182 {"linux-git", "1f10206cf8e9"},
183 {}
184 },
185 .test = run,
186 .tcnt = ARRAY_SIZE(testfunc_list),
187 .caps = (struct tst_cap []) {
188 TST_CAP(TST_CAP_REQ, CAP_IPC_LOCK),
189 {}
190 },
191 };
192