blob: 82ac1fcee4bb0381e269659731b894ead5ba6494 [file] [log] [blame]
Caspar Zhang817c7822011-06-30 01:50:33 +08001/*
2 * getrusage03 - test ru_maxrss behaviors in struct rusage
3 *
4 * This test program is backported from upstream commit:
5 * 1f10206cf8e945220f7220a809d8bfc15c21f9a5, which fills ru_maxrss
6 * value in struct rusage according to rss hiwater mark. To make sure
7 * this feature works correctly, a series of tests are executed in
8 * this program.
9 *
10 * Copyright (C) 2011 Red Hat, Inc.
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU General Public
13 * License as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it would be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
18 *
19 * Further, this software is distributed without any warranty that it
20 * is free of the rightful claim of any third person regarding
21 * infringement or the like. Any license provided herein, whether
22 * implied or otherwise, applies only to this software file. Patent
23 * licenses, if any, provided herein do not apply to combinations of
24 * this program with other software, or any other product whatsoever.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write the Free Software
28 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29 * 02110-1301, USA.
30 */
31#include <sys/types.h>
32#include <sys/mman.h>
33#include <sys/resource.h>
34#include <sys/time.h>
35#include <sys/wait.h>
36#include <unistd.h>
37#include <signal.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41
42#include "test.h"
Caspar Zhang817c7822011-06-30 01:50:33 +080043#include "safe_macros.h"
44
45char *TCID = "getrusage03";
46int TST_TOTAL = 1;
47
48#define DELTA_MAX 10240
49
50static struct rusage ru;
51static long maxrss_init;
52static int retval, status;
53static pid_t pid;
54
55static void inherit_fork(void);
56static void inherit_fork2(void);
57static void fork_malloc(void);
58static void grandchild_maxrss(void);
59static void zombie(void);
60static void sig_ign(void);
61static void exec_without_fork(void);
62static void check_return(int status, char *pass_msg, char *fail_msg);
63static int is_in_delta(long value);
64static void consume(int mega);
65static void setup(void);
66static void cleanup(void);
67
68int main(int argc, char *argv[])
69{
70 int lc;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +020071 const char *msg;
Caspar Zhang817c7822011-06-30 01:50:33 +080072
73 msg = parse_opts(argc, argv, NULL, NULL);
74 if (msg != NULL)
75 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
76
77 setup();
78
79 for (lc = 0; TEST_LOOPING(lc); lc++) {
Caspar Zhangd59a6592013-03-07 14:59:12 +080080 tst_count = 0;
Caspar Zhang817c7822011-06-30 01:50:33 +080081
82 tst_resm(TINFO, "allocate 100MB");
83 consume(100);
84
85 inherit_fork();
86 inherit_fork2();
87 fork_malloc();
88 grandchild_maxrss();
89 zombie();
90 sig_ign();
91 exec_without_fork();
92 }
93 cleanup();
94 tst_exit();
95}
96
97/* Testcase #01: fork inherit
98 * expect: initial.self ~= child.self */
99static void inherit_fork(void)
100{
101 tst_resm(TINFO, "Testcase #01: fork inherit");
102
103 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
104 tst_resm(TINFO, "initial.self = %ld", ru.ru_maxrss);
105
106 switch (pid = fork()) {
107 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800108 tst_brkm(TBROK | TERRNO, cleanup, "fork #1");
Caspar Zhang817c7822011-06-30 01:50:33 +0800109 case 0:
110 maxrss_init = ru.ru_maxrss;
111 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
112 tst_resm(TINFO, "child.self = %ld", ru.ru_maxrss);
113 exit(is_in_delta(maxrss_init - ru.ru_maxrss));
114 default:
115 break;
116 }
117
Wanlong Gao354ebb42012-12-07 10:10:04 +0800118 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1)
119 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Caspar Zhang817c7822011-06-30 01:50:33 +0800120 check_return(WEXITSTATUS(status), "initial.self ~= child.self",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800121 "initial.self !~= child.self");
Caspar Zhang817c7822011-06-30 01:50:33 +0800122}
123
124/* Testcase #02: fork inherit (cont.)
125 * expect: initial.children ~= 100MB, child.children = 0 */
126static void inherit_fork2(void)
127{
128 tst_resm(TINFO, "Testcase #02: fork inherit(cont.)");
129
130 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
131 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
132 if (is_in_delta(ru.ru_maxrss - 102400))
133 tst_resm(TPASS, "initial.children ~= 100MB");
134 else
135 tst_resm(TFAIL, "initial.children !~= 100MB");
136
137 switch (pid = fork()) {
138 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800139 tst_brkm(TBROK | TERRNO, cleanup, "fork #2");
Caspar Zhang817c7822011-06-30 01:50:33 +0800140 case 0:
141 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
142 tst_resm(TINFO, "child.children = %ld", ru.ru_maxrss);
143 exit(ru.ru_maxrss == 0);
144 default:
145 break;
146 }
147
Wanlong Gao354ebb42012-12-07 10:10:04 +0800148 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1)
149 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Caspar Zhang817c7822011-06-30 01:50:33 +0800150 check_return(WEXITSTATUS(status), "child.children == 0",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800151 "child.children != 0");
Caspar Zhang817c7822011-06-30 01:50:33 +0800152}
153
154/* Testcase #03: fork + malloc
155 * expect: initial.self + 50MB ~= child.self */
156static void fork_malloc(void)
157{
158 tst_resm(TINFO, "Testcase #03: fork + malloc");
159
160 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
161 tst_resm(TINFO, "initial.self = %ld", ru.ru_maxrss);
162
163 switch (pid = fork()) {
164 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800165 tst_brkm(TBROK | TERRNO, cleanup, "fork #3");
Caspar Zhang817c7822011-06-30 01:50:33 +0800166 case 0:
167 maxrss_init = ru.ru_maxrss;
168 tst_resm(TINFO, "child allocate +50MB");
169 consume(50);
170 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
171 tst_resm(TINFO, "child.self = %ld", ru.ru_maxrss);
172 exit(is_in_delta(maxrss_init + 51200 - ru.ru_maxrss));
173 default:
174 break;
175 }
176
Wanlong Gao354ebb42012-12-07 10:10:04 +0800177 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1)
178 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Caspar Zhang817c7822011-06-30 01:50:33 +0800179 check_return(WEXITSTATUS(status), "initial.self + 50MB ~= child.self",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800180 "initial.self + 50MB !~= child.self");
Caspar Zhang817c7822011-06-30 01:50:33 +0800181}
182
183/* Testcase #04: grandchild maxrss
184 * expect: post_wait.children ~= 300MB */
185static void grandchild_maxrss(void)
186{
187 tst_resm(TINFO, "Testcase #04: grandchild maxrss");
188
189 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
190 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
191
192 switch (pid = fork()) {
193 case -1:
Wanlong Gao354ebb42012-12-07 10:10:04 +0800194 tst_brkm(TBROK | TERRNO, cleanup, "fork #4");
Caspar Zhang817c7822011-06-30 01:50:33 +0800195 case 0:
196 retval = system("getrusage03_child -g 300");
197 if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0))
Wanlong Gao354ebb42012-12-07 10:10:04 +0800198 tst_brkm(TBROK | TERRNO, cleanup, "system");
Caspar Zhang817c7822011-06-30 01:50:33 +0800199 exit(0);
200 default:
201 break;
202 }
203
Wanlong Gao354ebb42012-12-07 10:10:04 +0800204 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1)
205 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Caspar Zhang817c7822011-06-30 01:50:33 +0800206 if (WEXITSTATUS(status) != 0)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800207 tst_brkm(TBROK | TERRNO, cleanup, "child exit status is not 0");
Caspar Zhang817c7822011-06-30 01:50:33 +0800208
209 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
210 tst_resm(TINFO, "post_wait.children = %ld", ru.ru_maxrss);
211 if (is_in_delta(ru.ru_maxrss - 307200))
212 tst_resm(TPASS, "child.children ~= 300MB");
213 else
214 tst_resm(TFAIL, "child.children !~= 300MB");
215}
216
217/* Testcase #05: zombie
218 * expect: initial ~= pre_wait, post_wait ~= 400MB */
219static void zombie(void)
220{
221 tst_resm(TINFO, "Testcase #05: zombie");
222
223 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
224 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
225 maxrss_init = ru.ru_maxrss;
226
227 switch (pid = fork()) {
228 case -1:
229 tst_brkm(TBROK, cleanup, "fork #5");
230 case 0:
231 retval = system("getrusage03_child -n 400");
232 if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0))
Wanlong Gao354ebb42012-12-07 10:10:04 +0800233 tst_brkm(TBROK | TERRNO, cleanup, "system");
Caspar Zhang817c7822011-06-30 01:50:33 +0800234 exit(0);
235 default:
236 break;
237 }
238
Wanlong Gao354ebb42012-12-07 10:10:04 +0800239 sleep(1); /* children become zombie */
Caspar Zhang817c7822011-06-30 01:50:33 +0800240 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
241 tst_resm(TINFO, "pre_wait.children = %ld", ru.ru_maxrss);
242 if (is_in_delta(ru.ru_maxrss - maxrss_init))
243 tst_resm(TPASS, "initial.children ~= pre_wait.children");
244 else
245 tst_resm(TFAIL, "initial.children !~= pre_wait.children");
246
Wanlong Gao354ebb42012-12-07 10:10:04 +0800247 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1)
248 tst_brkm(TBROK | TERRNO, cleanup, "waitpid");
Caspar Zhang817c7822011-06-30 01:50:33 +0800249 if (WEXITSTATUS(status) != 0)
Wanlong Gao354ebb42012-12-07 10:10:04 +0800250 tst_brkm(TBROK | TERRNO, cleanup, "child exit status is not 0");
Caspar Zhang817c7822011-06-30 01:50:33 +0800251
252 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
253 tst_resm(TINFO, "post_wait.children = %ld", ru.ru_maxrss);
254 if (is_in_delta(ru.ru_maxrss - 409600))
255 tst_resm(TPASS, "post_wait.children ~= 400MB");
256 else
257 tst_resm(TFAIL, "post_wait.children !~= 400MB");
258}
259
260/* Testcase #06: SIG_IGN
261 * expect: initial ~= after_zombie */
262static void sig_ign(void)
263{
264 tst_resm(TINFO, "Testcase #06: SIG_IGN");
265
266 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
267 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
268 signal(SIGCHLD, SIG_IGN);
269 maxrss_init = ru.ru_maxrss;
270
271 switch (pid = fork()) {
272 case -1:
273 tst_brkm(TBROK, cleanup, "fork #6");
274 case 0:
275 retval = system("getrusage03_child -n 500");
276 if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0))
Wanlong Gao354ebb42012-12-07 10:10:04 +0800277 tst_brkm(TBROK | TERRNO, cleanup, "system");
Caspar Zhang817c7822011-06-30 01:50:33 +0800278 exit(0);
279 default:
280 break;
281 }
282
Wanlong Gao354ebb42012-12-07 10:10:04 +0800283 sleep(1); /* children become zombie */
Caspar Zhang817c7822011-06-30 01:50:33 +0800284 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
285 tst_resm(TINFO, "after_zombie.children = %ld", ru.ru_maxrss);
286 if (is_in_delta(ru.ru_maxrss - maxrss_init))
287 tst_resm(TPASS, "initial.children ~= after_zombie.children");
288 else
289 tst_resm(TFAIL, "initial.children !~= after_zombie.children");
290 signal(SIGCHLD, SIG_DFL);
291}
292
293/* Testcase #07: exec without fork
294 * expect: initial ~= fork */
295static void exec_without_fork(void)
296{
297 char str_maxrss_self[BUFSIZ], str_maxrss_child[BUFSIZ];
298 long maxrss_self, maxrss_child;
299
300 tst_resm(TINFO, "Testcase #07: exec without fork");
301
302 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
303 maxrss_self = ru.ru_maxrss;
304 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
305 maxrss_child = ru.ru_maxrss;
306 tst_resm(TINFO, "initial.self = %ld, initial.children = %ld",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800307 maxrss_self, maxrss_child);
Caspar Zhang817c7822011-06-30 01:50:33 +0800308
309 sprintf(str_maxrss_self, "%ld", maxrss_self);
310 sprintf(str_maxrss_child, "%ld", maxrss_child);
311 if (execlp("getrusage03_child", "getrusage03_child", "-v",
Wanlong Gao354ebb42012-12-07 10:10:04 +0800312 "-s", str_maxrss_self, "-l", str_maxrss_child, NULL) == -1)
313 tst_brkm(TBROK | TERRNO, cleanup, "execlp");
Caspar Zhang817c7822011-06-30 01:50:33 +0800314}
315
316static int is_in_delta(long value)
317{
318 return (value >= -DELTA_MAX && value <= DELTA_MAX);
319}
320
321static void check_return(int status, char *pass_msg, char *fail_msg)
322{
323 switch (status) {
324 case 1:
325 tst_resm(TPASS, "%s", pass_msg);
326 break;
327 case 0:
328 tst_resm(TFAIL, "%s", fail_msg);
329 break;
330 default:
331 tst_resm(TFAIL, "child exit status is %d", status);
332 break;
333 }
334}
335
336static void consume(int mega)
337{
338 size_t sz;
339 void *ptr;
340
Wanlong Gao354ebb42012-12-07 10:10:04 +0800341 sz = mega * 1024 * 1024;
Caspar Zhang817c7822011-06-30 01:50:33 +0800342 ptr = SAFE_MALLOC(cleanup, sz);
343 memset(ptr, 0, sz);
344}
345
346static void setup(void)
347{
Wanlong Gaobcf24e62013-06-25 09:33:50 +0800348 /* Disable test if the version of the kernel is less than 2.6.32 */
349 if ((tst_kvercmp(2, 6, 32)) < 0) {
350 tst_resm(TCONF, "This ru_maxrss field is not supported");
Cyril Hrubis526fdf82014-12-04 14:35:01 +0100351 tst_brkm(TCONF, NULL, "before kernel 2.6.32");
Wanlong Gaobcf24e62013-06-25 09:33:50 +0800352 }
353
Caspar Zhang817c7822011-06-30 01:50:33 +0800354 tst_sig(FORK, DEF_HANDLER, cleanup);
355
356 TEST_PAUSE;
357}
358
359static void cleanup(void)
360{
Caspar Zhang817c7822011-06-30 01:50:33 +0800361}