Home | History | Annotate | Download | only in getrusage
      1 /*
      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"
     43 #include "safe_macros.h"
     44 
     45 char *TCID = "getrusage03";
     46 int TST_TOTAL = 1;
     47 
     48 #define DELTA_MAX	10240
     49 
     50 static struct rusage ru;
     51 static long maxrss_init;
     52 static int retval, status;
     53 static pid_t pid;
     54 
     55 static void inherit_fork(void);
     56 static void inherit_fork2(void);
     57 static void fork_malloc(void);
     58 static void grandchild_maxrss(void);
     59 static void zombie(void);
     60 static void sig_ign(void);
     61 static void exec_without_fork(void);
     62 static void check_return(int status, char *pass_msg, char *fail_msg);
     63 static int is_in_delta(long value);
     64 static void consume(int mega);
     65 static void setup(void);
     66 static void cleanup(void);
     67 
     68 int main(int argc, char *argv[])
     69 {
     70 	int lc;
     71 
     72 	tst_parse_opts(argc, argv, NULL, NULL);
     73 
     74 	setup();
     75 
     76 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     77 		tst_count = 0;
     78 
     79 		tst_resm(TINFO, "allocate 100MB");
     80 		consume(100);
     81 
     82 		inherit_fork();
     83 		inherit_fork2();
     84 		fork_malloc();
     85 		grandchild_maxrss();
     86 		zombie();
     87 		sig_ign();
     88 		exec_without_fork();
     89 	}
     90 	cleanup();
     91 	tst_exit();
     92 }
     93 
     94 /* Testcase #01: fork inherit
     95  * expect: initial.self ~= child.self */
     96 static void inherit_fork(void)
     97 {
     98 	tst_resm(TINFO, "Testcase #01: fork inherit");
     99 
    100 	SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
    101 	tst_resm(TINFO, "initial.self = %ld", ru.ru_maxrss);
    102 
    103 	switch (pid = fork()) {
    104 	case -1:
    105 		tst_brkm(TBROK | TERRNO, cleanup, "fork #1");
    106 	case 0:
    107 		maxrss_init = ru.ru_maxrss;
    108 		SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
    109 		tst_resm(TINFO, "child.self = %ld", ru.ru_maxrss);
    110 		exit(is_in_delta(maxrss_init - ru.ru_maxrss));
    111 	default:
    112 		break;
    113 	}
    114 
    115 	SAFE_WAITPID(cleanup, pid, &status, WUNTRACED | WCONTINUED);
    116 	check_return(WEXITSTATUS(status), "initial.self ~= child.self",
    117 		     "initial.self !~= child.self");
    118 }
    119 
    120 /* Testcase #02: fork inherit (cont.)
    121  * expect: initial.children ~= 100MB, child.children = 0 */
    122 static void inherit_fork2(void)
    123 {
    124 	tst_resm(TINFO, "Testcase #02: fork inherit(cont.)");
    125 
    126 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    127 	tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
    128 	if (is_in_delta(ru.ru_maxrss - 102400))
    129 		tst_resm(TPASS, "initial.children ~= 100MB");
    130 	else
    131 		tst_resm(TFAIL, "initial.children !~= 100MB");
    132 
    133 	switch (pid = fork()) {
    134 	case -1:
    135 		tst_brkm(TBROK | TERRNO, cleanup, "fork #2");
    136 	case 0:
    137 		SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    138 		tst_resm(TINFO, "child.children = %ld", ru.ru_maxrss);
    139 		exit(ru.ru_maxrss == 0);
    140 	default:
    141 		break;
    142 	}
    143 
    144 	SAFE_WAITPID(cleanup, pid, &status, WUNTRACED | WCONTINUED);
    145 	check_return(WEXITSTATUS(status), "child.children == 0",
    146 		     "child.children != 0");
    147 }
    148 
    149 /* Testcase #03: fork + malloc
    150  * expect: initial.self + 50MB ~= child.self */
    151 static void fork_malloc(void)
    152 {
    153 	tst_resm(TINFO, "Testcase #03: fork + malloc");
    154 
    155 	SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
    156 	tst_resm(TINFO, "initial.self = %ld", ru.ru_maxrss);
    157 
    158 	switch (pid = fork()) {
    159 	case -1:
    160 		tst_brkm(TBROK | TERRNO, cleanup, "fork #3");
    161 	case 0:
    162 		maxrss_init = ru.ru_maxrss;
    163 		tst_resm(TINFO, "child allocate +50MB");
    164 		consume(50);
    165 		SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
    166 		tst_resm(TINFO, "child.self = %ld", ru.ru_maxrss);
    167 		exit(is_in_delta(maxrss_init + 51200 - ru.ru_maxrss));
    168 	default:
    169 		break;
    170 	}
    171 
    172 	SAFE_WAITPID(cleanup, pid, &status, WUNTRACED | WCONTINUED);
    173 	check_return(WEXITSTATUS(status), "initial.self + 50MB ~= child.self",
    174 		     "initial.self + 50MB !~= child.self");
    175 }
    176 
    177 /* Testcase #04: grandchild maxrss
    178  * expect: post_wait.children ~= 300MB */
    179 static void grandchild_maxrss(void)
    180 {
    181 	tst_resm(TINFO, "Testcase #04: grandchild maxrss");
    182 
    183 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    184 	tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
    185 
    186 	switch (pid = fork()) {
    187 	case -1:
    188 		tst_brkm(TBROK | TERRNO, cleanup, "fork #4");
    189 	case 0:
    190 		retval = system("getrusage03_child -g 300");
    191 		if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0))
    192 			tst_brkm(TBROK | TERRNO, cleanup, "system");
    193 		exit(0);
    194 	default:
    195 		break;
    196 	}
    197 
    198 	SAFE_WAITPID(cleanup, pid, &status, WUNTRACED | WCONTINUED);
    199 	if (WEXITSTATUS(status) != 0)
    200 		tst_brkm(TBROK | TERRNO, cleanup, "child exit status is not 0");
    201 
    202 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    203 	tst_resm(TINFO, "post_wait.children = %ld", ru.ru_maxrss);
    204 	if (is_in_delta(ru.ru_maxrss - 307200))
    205 		tst_resm(TPASS, "child.children ~= 300MB");
    206 	else
    207 		tst_resm(TFAIL, "child.children !~= 300MB");
    208 }
    209 
    210 /* Testcase #05: zombie
    211  * expect: initial ~= pre_wait, post_wait ~= 400MB */
    212 static void zombie(void)
    213 {
    214 	tst_resm(TINFO, "Testcase #05: zombie");
    215 
    216 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    217 	tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
    218 	maxrss_init = ru.ru_maxrss;
    219 
    220 	switch (pid = fork()) {
    221 	case -1:
    222 		tst_brkm(TBROK, cleanup, "fork #5");
    223 	case 0:
    224 		retval = system("getrusage03_child -n 400");
    225 		if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0))
    226 			tst_brkm(TBROK | TERRNO, cleanup, "system");
    227 		exit(0);
    228 	default:
    229 		break;
    230 	}
    231 
    232 	sleep(1);		/* children become zombie */
    233 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    234 	tst_resm(TINFO, "pre_wait.children = %ld", ru.ru_maxrss);
    235 	if (is_in_delta(ru.ru_maxrss - maxrss_init))
    236 		tst_resm(TPASS, "initial.children ~= pre_wait.children");
    237 	else
    238 		tst_resm(TFAIL, "initial.children !~= pre_wait.children");
    239 
    240 	SAFE_WAITPID(cleanup, pid, &status, WUNTRACED | WCONTINUED);
    241 	if (WEXITSTATUS(status) != 0)
    242 		tst_brkm(TBROK | TERRNO, cleanup, "child exit status is not 0");
    243 
    244 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    245 	tst_resm(TINFO, "post_wait.children = %ld", ru.ru_maxrss);
    246 	if (is_in_delta(ru.ru_maxrss - 409600))
    247 		tst_resm(TPASS, "post_wait.children ~= 400MB");
    248 	else
    249 		tst_resm(TFAIL, "post_wait.children !~= 400MB");
    250 }
    251 
    252 /* Testcase #06: SIG_IGN
    253  * expect: initial ~= after_zombie */
    254 static void sig_ign(void)
    255 {
    256 	tst_resm(TINFO, "Testcase #06: SIG_IGN");
    257 
    258 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    259 	tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss);
    260 	signal(SIGCHLD, SIG_IGN);
    261 	maxrss_init = ru.ru_maxrss;
    262 
    263 	switch (pid = fork()) {
    264 	case -1:
    265 		tst_brkm(TBROK, cleanup, "fork #6");
    266 	case 0:
    267 		retval = system("getrusage03_child -n 500");
    268 		if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0))
    269 			tst_brkm(TBROK | TERRNO, cleanup, "system");
    270 		exit(0);
    271 	default:
    272 		break;
    273 	}
    274 
    275 	sleep(1);		/* children become zombie */
    276 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    277 	tst_resm(TINFO, "after_zombie.children = %ld", ru.ru_maxrss);
    278 	if (is_in_delta(ru.ru_maxrss - maxrss_init))
    279 		tst_resm(TPASS, "initial.children ~= after_zombie.children");
    280 	else
    281 		tst_resm(TFAIL, "initial.children !~= after_zombie.children");
    282 	signal(SIGCHLD, SIG_DFL);
    283 }
    284 
    285 /* Testcase #07: exec without fork
    286  * expect: initial ~= fork */
    287 static void exec_without_fork(void)
    288 {
    289 	char str_maxrss_self[BUFSIZ], str_maxrss_child[BUFSIZ];
    290 	long maxrss_self, maxrss_child;
    291 
    292 	tst_resm(TINFO, "Testcase #07: exec without fork");
    293 
    294 	SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
    295 	maxrss_self = ru.ru_maxrss;
    296 	SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
    297 	maxrss_child = ru.ru_maxrss;
    298 	tst_resm(TINFO, "initial.self = %ld, initial.children = %ld",
    299 		 maxrss_self, maxrss_child);
    300 
    301 	sprintf(str_maxrss_self, "%ld", maxrss_self);
    302 	sprintf(str_maxrss_child, "%ld", maxrss_child);
    303 	if (execlp("getrusage03_child", "getrusage03_child", "-v",
    304 		   "-s", str_maxrss_self, "-l", str_maxrss_child, NULL) == -1)
    305 		tst_brkm(TBROK | TERRNO, cleanup, "execlp");
    306 }
    307 
    308 static int is_in_delta(long value)
    309 {
    310 	return (value >= -DELTA_MAX && value <= DELTA_MAX);
    311 }
    312 
    313 static void check_return(int status, char *pass_msg, char *fail_msg)
    314 {
    315 	switch (status) {
    316 	case 1:
    317 		tst_resm(TPASS, "%s", pass_msg);
    318 		break;
    319 	case 0:
    320 		tst_resm(TFAIL, "%s", fail_msg);
    321 		break;
    322 	default:
    323 		tst_resm(TFAIL, "child exit status is %d", status);
    324 		break;
    325 	}
    326 }
    327 
    328 static void consume(int mega)
    329 {
    330 	size_t sz;
    331 	void *ptr;
    332 
    333 	sz = mega * 1024 * 1024;
    334 	ptr = SAFE_MALLOC(cleanup, sz);
    335 	memset(ptr, 0, sz);
    336 }
    337 
    338 static void setup(void)
    339 {
    340 	/* Disable test if the version of the kernel is less than 2.6.32 */
    341 	if ((tst_kvercmp(2, 6, 32)) < 0) {
    342 		tst_resm(TCONF, "This ru_maxrss field is not supported");
    343 		tst_brkm(TCONF, NULL, "before kernel 2.6.32");
    344 	}
    345 
    346 	tst_sig(FORK, DEF_HANDLER, cleanup);
    347 
    348 	TEST_PAUSE;
    349 }
    350 
    351 static void cleanup(void)
    352 {
    353 }
    354