staticint alloc_noexit(unsignedlong nr_pages, int pipefd)
{ int ppid = getppid(); int timeout = 10; /* 10sec timeout to get killed */ unsignedlong i; char *buf;
for (i = 0; i < nr_pages; i++)
*((unsignedlong *)(buf + (i * psize()))) = i;
/* Signal the parent that the child is ready */ if (write(pipefd, "", 1) < 0)
ksft_exit_fail_msg("write: %s\n", strerror(errno));
/* Wait to be killed (when reparenting happens) */ while (getppid() == ppid && timeout > 0) {
sleep(1);
timeout--;
}
munmap(buf, nr_pages * psize());
return (timeout > 0) ? KSFT_PASS : KSFT_FAIL;
}
/* The process_mrelease calls in this test are expected to fail */ staticvoid run_negative_tests(int pidfd)
{ /* Test invalid flags. Expect to fail with EINVAL error code. */ if (!syscall(__NR_process_mrelease, pidfd, (unsignedint)-1) ||
errno != EINVAL) {
ksft_exit_fail_msg("process_mrelease with wrong flags: %s\n", strerror(errno));
} /* * Test reaping while process is alive with no pending SIGKILL. * Expect to fail with EINVAL error code.
*/ if (!syscall(__NR_process_mrelease, pidfd, 0) || errno != EINVAL)
ksft_exit_fail_msg("process_mrelease on a live process: %s\n", strerror(errno));
}
staticint child_main(int pipefd[], size_t size)
{ int res;
/* Allocate and fault-in memory and wait to be killed */
close(pipefd[0]);
res = alloc_noexit(MB(size) / psize(), pipefd[1]);
close(pipefd[1]); return res;
}
int main(void)
{ int pipefd[2], pidfd; bool success, retry;
size_t size;
pid_t pid; char byte; int res;
ksft_print_header();
ksft_set_plan(1);
/* Test a wrong pidfd */ if (!syscall(__NR_process_mrelease, -1, 0) || errno != EBADF) { if (errno == ENOSYS) {
ksft_test_result_skip("process_mrelease not implemented\n");
ksft_finished();
} else {
ksft_exit_fail_msg("process_mrelease with wrong pidfd: %s",
strerror(errno));
}
}
/* Start the test with 1MB child memory allocation */
size = 1;
retry: /* * Pipe for the child to signal when it's done allocating * memory
*/ if (pipe(pipefd))
ksft_exit_fail_msg("pipe: %s\n", strerror(errno));
if (pid == 0) { /* Child main routine */
res = child_main(pipefd, size); exit(res);
}
/* * Parent main routine: * Wait for the child to finish allocations, then kill and reap
*/
close(pipefd[1]); /* Block until the child is ready */
res = read(pipefd[0], &byte, 1);
close(pipefd[0]); if (res < 0) { if (!kill(pid, SIGKILL))
waitpid(pid, NULL, 0);
ksft_exit_fail_msg("read: %s\n", strerror(errno));
}
pidfd = syscall(__NR_pidfd_open, pid, 0); if (pidfd < 0) { if (!kill(pid, SIGKILL))
waitpid(pid, NULL, 0);
ksft_exit_fail_msg("pidfd_open: %s\n", strerror(errno));
}
/* Run negative tests which require a live child */
run_negative_tests(pidfd);
if (kill(pid, SIGKILL))
ksft_exit_fail_msg("kill: %s\n", strerror(errno));
success = (syscall(__NR_process_mrelease, pidfd, 0) == 0); if (!success) { /* * If we failed to reap because the child exited too soon, * before we could call process_mrelease. Double child's memory * which causes it to spend more time on cleanup and increases * our chances of reaping its memory before it exits. * Retry until we succeed or reach MAX_SIZE_MB.
*/ if (errno == ESRCH) {
retry = (size <= MAX_SIZE_MB);
} else {
waitpid(pid, NULL, 0);
ksft_exit_fail_msg("process_mrelease: %s\n", strerror(errno));
}
}
/* Cleanup to prevent zombies */ if (waitpid(pid, NULL, 0) < 0)
ksft_exit_fail_msg("waitpid: %s\n", strerror(errno));
close(pidfd);
if (!success) { if (retry) {
size *= 2; goto retry;
}
ksft_exit_fail_msg("All process_mrelease attempts failed!\n");
}
ksft_test_result_pass("Success reaping a child with %zuMB of memory allocations\n",
size);
ksft_finished();
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.