1 /*
2  * getrusage03_child.c - a child program executed by getrusage03
3  *
4  * Copyright (C) 2011  Red Hat, Inc.
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU General Public
7  * License as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12  *
13  * Further, this software is distributed without any warranty that it
14  * is free of the rightful claim of any third person regarding
15  * infringement or the like.  Any license provided herein, whether
16  * implied or otherwise, applies only to this software file.  Patent
17  * licenses, if any, provided herein do not apply to combinations of
18  * this program with other software, or any other product whatsoever.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23  * 02110-1301, USA.
24  */
25 #include <sys/types.h>
26 #include <sys/resource.h>
27 #include <sys/time.h>
28 #include <sys/wait.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "test.h"
36 #include "safe_macros.h"
37 
38 char *TCID = "getrusage03_child";
39 int TST_TOTAL = 1;
40 
41 #define DELTA_MAX	10240
42 
43 static int opt_consume, opt_grand, opt_show, opt_self, opt_child;
44 static char *consume_str, *grand_consume_str, *self_str, *child_str;
45 
46 option_t child_options[] = {
47 	{"n:", &opt_consume, &consume_str},
48 	{"g:", &opt_grand, &grand_consume_str},
49 	{"v", &opt_show, NULL},
50 	{"s:", &opt_self, &self_str},
51 	{"l:", &opt_child, &child_str},
52 	{NULL, NULL, NULL}
53 };
54 
55 static void usage(void);
56 static void consume(int mega);
57 static void setup(void);
58 static void cleanup(void);
59 
main(int argc,char * argv[])60 int main(int argc, char *argv[])
61 {
62 	int lc;
63 	pid_t pid;
64 	long maxrss_self, maxrss_children, delta;
65 	long consume_nr, grand_consume_nr, self_nr, child_nr;
66 	struct rusage ru;
67 
68 	tst_parse_opts(argc, argv, child_options, usage);
69 
70 	setup();
71 
72 	for (lc = 0; TEST_LOOPING(lc); lc++) {
73 		tst_count = 0;
74 
75 		if (opt_consume) {
76 			consume_nr = SAFE_STRTOL(cleanup,
77 						 consume_str, 0, LONG_MAX);
78 			tst_resm(TINFO, "child allocate %ldMB", consume_nr);
79 			consume(consume_nr);
80 		}
81 
82 		if (opt_grand) {
83 			grand_consume_nr = SAFE_STRTOL(cleanup,
84 						       grand_consume_str, 0,
85 						       LONG_MAX);
86 			tst_resm(TINFO, "grandchild allocate %ldMB",
87 				 grand_consume_nr);
88 			switch (pid = fork()) {
89 			case -1:
90 				tst_brkm(TBROK, cleanup, "fork");
91 			case 0:
92 				consume(grand_consume_nr);
93 				exit(0);
94 			default:
95 				break;
96 			}
97 			while (waitpid(-1, &pid, WUNTRACED | WCONTINUED) > 0)
98 				if (WEXITSTATUS(pid) != 0)
99 					tst_brkm(TBROK | TERRNO, cleanup,
100 						 "child exit status is not 0");
101 		}
102 
103 		if (opt_show) {
104 			SAFE_GETRUSAGE(cleanup, RUSAGE_SELF, &ru);
105 			maxrss_self = ru.ru_maxrss;
106 			SAFE_GETRUSAGE(cleanup, RUSAGE_CHILDREN, &ru);
107 			maxrss_children = ru.ru_maxrss;
108 			tst_resm(TINFO, "exec.self = %ld, exec.children = %ld",
109 				 maxrss_self, maxrss_children);
110 			if (opt_self) {
111 				self_nr = SAFE_STRTOL(cleanup,
112 						      self_str, 0, LONG_MAX);
113 				delta = maxrss_self - self_nr;
114 				if (delta >= -DELTA_MAX && delta <= DELTA_MAX)
115 					tst_resm(TPASS,
116 						 "initial.self ~= exec.self");
117 				else
118 					tst_resm(TFAIL,
119 						 "initial.self !~= exec.self");
120 			}
121 			if (opt_child) {
122 				child_nr = SAFE_STRTOL(cleanup,
123 						       child_str, 0, LONG_MAX);
124 				delta = maxrss_children - child_nr;
125 				if (delta >= -DELTA_MAX && delta <= DELTA_MAX)
126 					tst_resm(TPASS,
127 						 "initial.children ~= exec.children");
128 				else
129 					tst_resm(TFAIL,
130 						 "initial.children !~= exec.children");
131 			}
132 		}
133 	}
134 
135 	cleanup();
136 	tst_exit();
137 }
138 
usage(void)139 static void usage(void)
140 {
141 	printf("  -n NUM  consume NUM MB size\n");
142 	printf("  -g NUM  grandchild consume NUM MB size\n");
143 	printf("  -v      verbose mode, show rusage info\n");
144 	printf("  -s NUM  compare rusage_self.maxrss with given NUM\n");
145 	printf("  -l NUM  compare rusage_children.maxrss with given NUM\n");
146 }
147 
consume(int mega)148 static void consume(int mega)
149 {
150 	size_t sz;
151 	void *ptr;
152 
153 	sz = mega * 1024 * 1024;
154 	ptr = SAFE_MALLOC(cleanup, sz);
155 	memset(ptr, 0, sz);
156 }
157 
setup(void)158 static void setup(void)
159 {
160 	tst_sig(FORK, DEF_HANDLER, cleanup);
161 
162 	TEST_PAUSE;
163 }
164 
cleanup(void)165 static void cleanup(void)
166 {
167 }
168