1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) 2011  Red Hat, Inc.
4 * Copyright (C) 2021 Xie Ziyao <xieziyao@huawei.com>
5 */
6
7/*\
8 * [Description]
9 *
10 * Test ru_maxrss behaviors in struct rusage.
11 *
12 * This test program is backported from upstream commit: 1f10206cf8e9, which
13 * fills ru_maxrss value in struct rusage according to rss hiwater mark. To
14 * make sure this feature works correctly, a series of tests are executed in
15 * this program.
16 */
17
18#include <stdlib.h>
19#include <stdio.h>
20
21#include "tst_test.h"
22#include "getrusage03.h"
23
24#define TESTBIN "getrusage03_child"
25
26static struct rusage ru;
27static long maxrss_init;
28
29static const char *const resource[] = {
30	TESTBIN,
31	NULL,
32};
33
34static void inherit_fork1(void)
35{
36	SAFE_GETRUSAGE(RUSAGE_SELF, &ru);
37	maxrss_init = ru.ru_maxrss;
38
39	if (!SAFE_FORK()) {
40		SAFE_GETRUSAGE(RUSAGE_SELF, &ru);
41
42		if (is_in_delta(maxrss_init - ru.ru_maxrss))
43			tst_res(TPASS, "initial.self ~= child.self");
44		else
45			tst_res(TFAIL, "child.self = %li, expected %li",
46				ru.ru_maxrss, maxrss_init);
47		exit(0);
48	}
49	tst_reap_children();
50}
51
52static void inherit_fork2(void)
53{
54	SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
55
56	if (is_in_delta(ru.ru_maxrss - 102400))
57		tst_res(TPASS, "initial.children ~= 100MB");
58	else
59		tst_res(TFAIL, "initial.children = %li, expected %i",
60			ru.ru_maxrss, 102400);
61
62	if (!SAFE_FORK()) {
63		SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
64
65		if (!ru.ru_maxrss)
66			tst_res(TPASS, "child.children == 0");
67		else
68			tst_res(TFAIL, "child.children = %li, expected %i",
69				ru.ru_maxrss, 0);
70		exit(0);
71	}
72	tst_reap_children();
73}
74
75static void grandchild_maxrss(void)
76{
77	if (!SAFE_FORK())
78		SAFE_EXECLP("getrusage03_child", "getrusage03_child",
79			    "grand_consume", "300", NULL);
80	tst_reap_children();
81	SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
82
83	if (is_in_delta(ru.ru_maxrss - 307200))
84		tst_res(TPASS, "child.children ~= 300MB");
85	else
86		tst_res(TFAIL, "child.children = %li, expected %i",
87			ru.ru_maxrss, 307200);
88}
89
90static void zombie(void)
91{
92	SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
93	maxrss_init = ru.ru_maxrss;
94
95	pid_t pid = SAFE_FORK();
96
97	if (!pid)
98		SAFE_EXECLP("getrusage03_child", "getrusage03_child",
99			    "consume", "400", NULL);
100
101	TST_PROCESS_STATE_WAIT(pid, 'Z', 0);
102	SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
103	if (is_in_delta(ru.ru_maxrss - maxrss_init))
104		tst_res(TPASS, "initial.children ~= pre_wait.children");
105	else
106		tst_res(TFAIL, "pre_wait.children = %li, expected %li",
107			ru.ru_maxrss, maxrss_init);
108
109	tst_reap_children();
110	SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
111	if (is_in_delta(ru.ru_maxrss - 409600))
112		tst_res(TPASS, "post_wait.children ~= 400MB");
113	else
114		tst_res(TFAIL, "post_wait.children = %li, expected %i",
115			ru.ru_maxrss, 409600);
116}
117
118static void sig_ign(void)
119{
120	SAFE_SIGNAL(SIGCHLD, SIG_IGN);
121	SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
122	maxrss_init = ru.ru_maxrss;
123
124	pid_t pid = SAFE_FORK();
125
126	if (!pid)
127		SAFE_EXECLP("getrusage03_child", "getrusage03_child",
128			    "consume", "500", NULL);
129
130	TST_PROCESS_EXIT_WAIT(pid, 0);
131	SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
132	if (is_in_delta(ru.ru_maxrss - maxrss_init))
133		tst_res(TPASS, "initial.children ~= after_zombie.children");
134	else
135		tst_res(TFAIL, "after_zombie.children = %li, expected %li",
136			ru.ru_maxrss, maxrss_init);
137
138	SAFE_SIGNAL(SIGCHLD, SIG_DFL);
139}
140
141static void inherit_exec(void)
142{
143	if (!SAFE_FORK()) {
144		char str_maxrss_self[BUFSIZ], str_maxrss_child[BUFSIZ];
145
146		SAFE_GETRUSAGE(RUSAGE_SELF, &ru);
147		sprintf(str_maxrss_self, "%ld", ru.ru_maxrss);
148		SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru);
149		sprintf(str_maxrss_child, "%ld", ru.ru_maxrss);
150
151		SAFE_EXECLP("getrusage03_child", "getrusage03_child",
152			    "compare", str_maxrss_self, str_maxrss_child, NULL);
153	}
154	tst_reap_children();
155}
156
157void (*testfunc_list[])(void) = {
158	inherit_fork1, inherit_fork2, grandchild_maxrss,
159	zombie, sig_ign, inherit_exec
160};
161
162static void run(unsigned int i)
163{
164	if (!SAFE_FORK()) {
165		if (!SAFE_FORK()) {
166			consume_mb(100);
167			exit(0);
168		}
169
170		SAFE_WAIT(NULL);
171
172		testfunc_list[i]();
173	}
174}
175
176static struct tst_test test = {
177	.forks_child = 1,
178	.child_needs_reinit = 1,
179	.resource_files = resource,
180	.min_mem_avail = 512,
181	.tags = (const struct tst_tag[]) {
182		{"linux-git", "1f10206cf8e9"},
183		{}
184	},
185	.test = run,
186	.tcnt = ARRAY_SIZE(testfunc_list),
187	.caps = (struct tst_cap []) {
188		TST_CAP(TST_CAP_REQ, CAP_IPC_LOCK),
189		{}
190	},
191};
192