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 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; 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 */ 96static 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 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1) 116 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 117 check_return(WEXITSTATUS(status), "initial.self ~= child.self", 118 "initial.self !~= child.self"); 119} 120 121/* Testcase #02: fork inherit (cont.) 122 * expect: initial.children ~= 100MB, child.children = 0 */ 123static void inherit_fork2(void) 124{ 125 tst_resm(TINFO, "Testcase #02: fork inherit(cont.)"); 126 127 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 128 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss); 129 if (is_in_delta(ru.ru_maxrss - 102400)) 130 tst_resm(TPASS, "initial.children ~= 100MB"); 131 else 132 tst_resm(TFAIL, "initial.children !~= 100MB"); 133 134 switch (pid = fork()) { 135 case -1: 136 tst_brkm(TBROK | TERRNO, cleanup, "fork #2"); 137 case 0: 138 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 139 tst_resm(TINFO, "child.children = %ld", ru.ru_maxrss); 140 exit(ru.ru_maxrss == 0); 141 default: 142 break; 143 } 144 145 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1) 146 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 147 check_return(WEXITSTATUS(status), "child.children == 0", 148 "child.children != 0"); 149} 150 151/* Testcase #03: fork + malloc 152 * expect: initial.self + 50MB ~= child.self */ 153static void fork_malloc(void) 154{ 155 tst_resm(TINFO, "Testcase #03: fork + malloc"); 156 157 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru); 158 tst_resm(TINFO, "initial.self = %ld", ru.ru_maxrss); 159 160 switch (pid = fork()) { 161 case -1: 162 tst_brkm(TBROK | TERRNO, cleanup, "fork #3"); 163 case 0: 164 maxrss_init = ru.ru_maxrss; 165 tst_resm(TINFO, "child allocate +50MB"); 166 consume(50); 167 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru); 168 tst_resm(TINFO, "child.self = %ld", ru.ru_maxrss); 169 exit(is_in_delta(maxrss_init + 51200 - ru.ru_maxrss)); 170 default: 171 break; 172 } 173 174 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1) 175 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 176 check_return(WEXITSTATUS(status), "initial.self + 50MB ~= child.self", 177 "initial.self + 50MB !~= child.self"); 178} 179 180/* Testcase #04: grandchild maxrss 181 * expect: post_wait.children ~= 300MB */ 182static void grandchild_maxrss(void) 183{ 184 tst_resm(TINFO, "Testcase #04: grandchild maxrss"); 185 186 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 187 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss); 188 189 switch (pid = fork()) { 190 case -1: 191 tst_brkm(TBROK | TERRNO, cleanup, "fork #4"); 192 case 0: 193 retval = system("getrusage03_child -g 300"); 194 if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0)) 195 tst_brkm(TBROK | TERRNO, cleanup, "system"); 196 exit(0); 197 default: 198 break; 199 } 200 201 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1) 202 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 203 if (WEXITSTATUS(status) != 0) 204 tst_brkm(TBROK | TERRNO, cleanup, "child exit status is not 0"); 205 206 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 207 tst_resm(TINFO, "post_wait.children = %ld", ru.ru_maxrss); 208 if (is_in_delta(ru.ru_maxrss - 307200)) 209 tst_resm(TPASS, "child.children ~= 300MB"); 210 else 211 tst_resm(TFAIL, "child.children !~= 300MB"); 212} 213 214/* Testcase #05: zombie 215 * expect: initial ~= pre_wait, post_wait ~= 400MB */ 216static void zombie(void) 217{ 218 tst_resm(TINFO, "Testcase #05: zombie"); 219 220 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 221 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss); 222 maxrss_init = ru.ru_maxrss; 223 224 switch (pid = fork()) { 225 case -1: 226 tst_brkm(TBROK, cleanup, "fork #5"); 227 case 0: 228 retval = system("getrusage03_child -n 400"); 229 if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0)) 230 tst_brkm(TBROK | TERRNO, cleanup, "system"); 231 exit(0); 232 default: 233 break; 234 } 235 236 sleep(1); /* children become zombie */ 237 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 238 tst_resm(TINFO, "pre_wait.children = %ld", ru.ru_maxrss); 239 if (is_in_delta(ru.ru_maxrss - maxrss_init)) 240 tst_resm(TPASS, "initial.children ~= pre_wait.children"); 241 else 242 tst_resm(TFAIL, "initial.children !~= pre_wait.children"); 243 244 if (waitpid(pid, &status, WUNTRACED | WCONTINUED) == -1) 245 tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); 246 if (WEXITSTATUS(status) != 0) 247 tst_brkm(TBROK | TERRNO, cleanup, "child exit status is not 0"); 248 249 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 250 tst_resm(TINFO, "post_wait.children = %ld", ru.ru_maxrss); 251 if (is_in_delta(ru.ru_maxrss - 409600)) 252 tst_resm(TPASS, "post_wait.children ~= 400MB"); 253 else 254 tst_resm(TFAIL, "post_wait.children !~= 400MB"); 255} 256 257/* Testcase #06: SIG_IGN 258 * expect: initial ~= after_zombie */ 259static void sig_ign(void) 260{ 261 tst_resm(TINFO, "Testcase #06: SIG_IGN"); 262 263 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 264 tst_resm(TINFO, "initial.children = %ld", ru.ru_maxrss); 265 signal(SIGCHLD, SIG_IGN); 266 maxrss_init = ru.ru_maxrss; 267 268 switch (pid = fork()) { 269 case -1: 270 tst_brkm(TBROK, cleanup, "fork #6"); 271 case 0: 272 retval = system("getrusage03_child -n 500"); 273 if ((WIFEXITED(retval) && WEXITSTATUS(retval) != 0)) 274 tst_brkm(TBROK | TERRNO, cleanup, "system"); 275 exit(0); 276 default: 277 break; 278 } 279 280 sleep(1); /* children become zombie */ 281 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 282 tst_resm(TINFO, "after_zombie.children = %ld", ru.ru_maxrss); 283 if (is_in_delta(ru.ru_maxrss - maxrss_init)) 284 tst_resm(TPASS, "initial.children ~= after_zombie.children"); 285 else 286 tst_resm(TFAIL, "initial.children !~= after_zombie.children"); 287 signal(SIGCHLD, SIG_DFL); 288} 289 290/* Testcase #07: exec without fork 291 * expect: initial ~= fork */ 292static void exec_without_fork(void) 293{ 294 char str_maxrss_self[BUFSIZ], str_maxrss_child[BUFSIZ]; 295 long maxrss_self, maxrss_child; 296 297 tst_resm(TINFO, "Testcase #07: exec without fork"); 298 299 SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru); 300 maxrss_self = ru.ru_maxrss; 301 SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru); 302 maxrss_child = ru.ru_maxrss; 303 tst_resm(TINFO, "initial.self = %ld, initial.children = %ld", 304 maxrss_self, maxrss_child); 305 306 sprintf(str_maxrss_self, "%ld", maxrss_self); 307 sprintf(str_maxrss_child, "%ld", maxrss_child); 308 if (execlp("getrusage03_child", "getrusage03_child", "-v", 309 "-s", str_maxrss_self, "-l", str_maxrss_child, NULL) == -1) 310 tst_brkm(TBROK | TERRNO, cleanup, "execlp"); 311} 312 313static int is_in_delta(long value) 314{ 315 return (value >= -DELTA_MAX && value <= DELTA_MAX); 316} 317 318static void check_return(int status, char *pass_msg, char *fail_msg) 319{ 320 switch (status) { 321 case 1: 322 tst_resm(TPASS, "%s", pass_msg); 323 break; 324 case 0: 325 tst_resm(TFAIL, "%s", fail_msg); 326 break; 327 default: 328 tst_resm(TFAIL, "child exit status is %d", status); 329 break; 330 } 331} 332 333static void consume(int mega) 334{ 335 size_t sz; 336 void *ptr; 337 338 sz = mega * 1024 * 1024; 339 ptr = SAFE_MALLOC(cleanup, sz); 340 memset(ptr, 0, sz); 341} 342 343static void setup(void) 344{ 345 /* Disable test if the version of the kernel is less than 2.6.32 */ 346 if ((tst_kvercmp(2, 6, 32)) < 0) { 347 tst_resm(TCONF, "This ru_maxrss field is not supported"); 348 tst_brkm(TCONF, NULL, "before kernel 2.6.32"); 349 } 350 351 tst_sig(FORK, DEF_HANDLER, cleanup); 352 353 TEST_PAUSE; 354} 355 356static void cleanup(void) 357{ 358} 359