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