| // SPDX-License-Identifier: GPL-2.0 |
| /* |
| * Copyright (C) 2011 Red Hat, Inc. |
| * Copyright (C) 2021 Xie Ziyao <xieziyao@huawei.com> |
| */ |
| |
| /*\ |
| * [Description] |
| * |
| * Test ru_maxrss behaviors in struct rusage. |
| * |
| * This test program is backported from upstream commit: 1f10206cf8e9, which |
| * fills ru_maxrss value in struct rusage according to rss hiwater mark. To |
| * make sure this feature works correctly, a series of tests are executed in |
| * this program. |
| */ |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| |
| #include "tst_test.h" |
| #include "getrusage03.h" |
| |
| #define TESTBIN "getrusage03_child" |
| |
| static struct rusage ru; |
| static long maxrss_init; |
| |
| static const char *const resource[] = { |
| TESTBIN, |
| NULL, |
| }; |
| |
| static void inherit_fork1(void) |
| { |
| SAFE_GETRUSAGE(RUSAGE_SELF, &ru); |
| maxrss_init = ru.ru_maxrss; |
| |
| if (!SAFE_FORK()) { |
| SAFE_GETRUSAGE(RUSAGE_SELF, &ru); |
| |
| if (is_in_delta(maxrss_init - ru.ru_maxrss)) |
| tst_res(TPASS, "initial.self ~= child.self"); |
| else |
| tst_res(TFAIL, "child.self = %li, expected %li", |
| ru.ru_maxrss, maxrss_init); |
| exit(0); |
| } |
| tst_reap_children(); |
| } |
| |
| static void inherit_fork2(void) |
| { |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| |
| if (is_in_delta(ru.ru_maxrss - 102400)) |
| tst_res(TPASS, "initial.children ~= 100MB"); |
| else |
| tst_res(TFAIL, "initial.children = %li, expected %i", |
| ru.ru_maxrss, 102400); |
| |
| if (!SAFE_FORK()) { |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| |
| if (!ru.ru_maxrss) |
| tst_res(TPASS, "child.children == 0"); |
| else |
| tst_res(TFAIL, "child.children = %li, expected %i", |
| ru.ru_maxrss, 0); |
| exit(0); |
| } |
| tst_reap_children(); |
| } |
| |
| static void grandchild_maxrss(void) |
| { |
| if (!SAFE_FORK()) |
| SAFE_EXECLP("getrusage03_child", "getrusage03_child", |
| "grand_consume", "300", NULL); |
| tst_reap_children(); |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| |
| if (is_in_delta(ru.ru_maxrss - 307200)) |
| tst_res(TPASS, "child.children ~= 300MB"); |
| else |
| tst_res(TFAIL, "child.children = %li, expected %i", |
| ru.ru_maxrss, 307200); |
| } |
| |
| static void zombie(void) |
| { |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| maxrss_init = ru.ru_maxrss; |
| |
| pid_t pid = SAFE_FORK(); |
| |
| if (!pid) |
| SAFE_EXECLP("getrusage03_child", "getrusage03_child", |
| "consume", "400", NULL); |
| |
| TST_PROCESS_STATE_WAIT(pid, 'Z', 0); |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| if (is_in_delta(ru.ru_maxrss - maxrss_init)) |
| tst_res(TPASS, "initial.children ~= pre_wait.children"); |
| else |
| tst_res(TFAIL, "pre_wait.children = %li, expected %li", |
| ru.ru_maxrss, maxrss_init); |
| |
| tst_reap_children(); |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| if (is_in_delta(ru.ru_maxrss - 409600)) |
| tst_res(TPASS, "post_wait.children ~= 400MB"); |
| else |
| tst_res(TFAIL, "post_wait.children = %li, expected %i", |
| ru.ru_maxrss, 409600); |
| } |
| |
| static void sig_ign(void) |
| { |
| SAFE_SIGNAL(SIGCHLD, SIG_IGN); |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| maxrss_init = ru.ru_maxrss; |
| |
| pid_t pid = SAFE_FORK(); |
| |
| if (!pid) |
| SAFE_EXECLP("getrusage03_child", "getrusage03_child", |
| "consume", "500", NULL); |
| |
| TST_PROCESS_EXIT_WAIT(pid, 0); |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| if (is_in_delta(ru.ru_maxrss - maxrss_init)) |
| tst_res(TPASS, "initial.children ~= after_zombie.children"); |
| else |
| tst_res(TFAIL, "after_zombie.children = %li, expected %li", |
| ru.ru_maxrss, maxrss_init); |
| |
| SAFE_SIGNAL(SIGCHLD, SIG_DFL); |
| } |
| |
| static void inherit_exec(void) |
| { |
| if (!SAFE_FORK()) { |
| char str_maxrss_self[BUFSIZ], str_maxrss_child[BUFSIZ]; |
| |
| SAFE_GETRUSAGE(RUSAGE_SELF, &ru); |
| sprintf(str_maxrss_self, "%ld", ru.ru_maxrss); |
| SAFE_GETRUSAGE(RUSAGE_CHILDREN, &ru); |
| sprintf(str_maxrss_child, "%ld", ru.ru_maxrss); |
| |
| SAFE_EXECLP("getrusage03_child", "getrusage03_child", |
| "compare", str_maxrss_self, str_maxrss_child, NULL); |
| } |
| tst_reap_children(); |
| } |
| |
| void (*testfunc_list[])(void) = { |
| inherit_fork1, inherit_fork2, grandchild_maxrss, |
| zombie, sig_ign, inherit_exec |
| }; |
| |
| static void run(unsigned int i) |
| { |
| if (!SAFE_FORK()) { |
| if (!SAFE_FORK()) { |
| consume_mb(100); |
| exit(0); |
| } |
| |
| SAFE_WAIT(NULL); |
| |
| testfunc_list[i](); |
| } |
| } |
| |
| static void setup(void) |
| { |
| long long mem_avail = tst_available_mem(); |
| |
| if (mem_avail < 512L*1024) |
| tst_brk(TCONF, "Needed > 512MB available, only have: %ld kB", mem_avail); |
| } |
| |
| static struct tst_test test = { |
| .forks_child = 1, |
| .child_needs_reinit = 1, |
| .resource_files = resource, |
| .min_kver = "2.6.32", |
| .tags = (const struct tst_tag[]) { |
| {"linux-git", "1f10206cf8e9"}, |
| {} |
| }, |
| .setup = setup, |
| .test = run, |
| .tcnt = ARRAY_SIZE(testfunc_list), |
| }; |