int main(int argc, char **argv) { int lc, status; int *bufsz_arr; tst_parse_opts(argc, argv, options, &help); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; if (pipe(pipe_fd) < 0) tst_brkm(TBROK | TERRNO, cleanup, "pipe"); bufsz_arr = SAFE_MALLOC(cleanup, nr_iovecs * sizeof(int)); gen_random_arr(bufsz_arr, nr_iovecs); /* the start of child_alloc and child_invoke is already * synchronized via pipe */ pids[0] = fork(); switch (pids[0]) { case -1: tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); case 0: child_alloc(bufsz_arr); exit(0); } pids[1] = fork(); switch (pids[1]) { case -1: tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); case 0: child_invoke(bufsz_arr); exit(0); } /* wait until child_invoke reads from child_alloc's VM */ if (waitpid(pids[1], &status, 0) == -1) tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) tst_resm(TFAIL, "child 1 returns %d", status); /* child_alloc is free to exit now */ safe_semop(semid, 0, 1); if (waitpid(pids[0], &status, 0) == -1) tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) tst_resm(TFAIL, "child 0 returns %d", status); free(bufsz_arr); } cleanup(); tst_exit(); }
int main(int argc, char **argv) { int lc, status; char *msg; msg = parse_opts(argc, argv, NULL, NULL); if (msg != NULL) tst_brkm(TBROK, tst_exit, "OPTION PARSING ERROR - %s", msg); setup(); for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; len = strlen(tst_string); if (pipe(pipe_fd) < 0) tst_brkm(TBROK | TERRNO, cleanup, "pipe"); /* the start of child_alloc and child_invoke is already * synchronized via pipe */ pids[0] = fork(); switch (pids[0]) { case -1: tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); case 0: child_alloc(); exit(0); } pids[1] = fork(); switch (pids[1]) { case -1: tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); case 0: child_invoke(); exit(0); } /* wait until child_invoke reads from child_alloc's VM */ if (waitpid(pids[1], &status, 0) == -1) tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) tst_resm(TFAIL, "child 1 returns %d", status); /* child_alloc is free to exit now */ safe_semop(semid, 0, 1); if (waitpid(pids[0], &status, 0) == -1) tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) tst_resm(TFAIL, "child 0 returns %d", status); } cleanup(); tst_exit(); }
/* * oom - allocates memory according to specified testcase and checks * desired outcome (e.g. child killed, operation failed with ENOMEM) * @testcase: selects how child allocates memory * valid choices are: NORMAL, MLOCK and KSM * @lite: if non-zero, child makes only single TESTMEM+MB allocation * if zero, child keeps allocating memory until it gets killed * or some operation fails * @retcode: expected return code of child process * if matches child ret code, this function reports PASS, * otherwise it reports FAIL * @allow_sigkill: if zero and child is killed, this function reports FAIL * if non-zero, then if child is killed by SIGKILL * it is considered as PASS */ void oom(int testcase, int lite, int retcode, int allow_sigkill) { pid_t pid; int status, threads; switch (pid = fork()) { case -1: if (errno == retcode) { tst_resm(TPASS | TERRNO, "fork"); return; } tst_brkm(TBROK | TERRNO, cleanup, "fork"); case 0: threads = MAX(1, tst_ncpus() - 1); child_alloc(testcase, lite, threads); default: break; } tst_resm(TINFO, "expected victim is %d.", pid); if (waitpid(-1, &status, 0) == -1) tst_brkm(TBROK | TERRNO, cleanup, "waitpid"); if (WIFSIGNALED(status)) { if (allow_sigkill && WTERMSIG(status) == SIGKILL) { tst_resm(TPASS, "victim signalled: (%d) %s", SIGKILL, tst_strsig(SIGKILL)); } else { tst_resm(TFAIL, "victim signalled: (%d) %s", WTERMSIG(status), tst_strsig(WTERMSIG(status))); } } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) == retcode) { tst_resm(TPASS, "victim retcode: (%d) %s", retcode, strerror(retcode)); } else { tst_resm(TFAIL, "victim unexpectedly ended with " "retcode: %d, expected: %d", WEXITSTATUS(status), retcode); } } else { tst_resm(TFAIL, "victim unexpectedly ended"); } }
/* * oom - allocates memory according to specified testcase and checks * desired outcome (e.g. child killed, operation failed with ENOMEM) * @testcase: selects how child allocates memory * valid choices are: NORMAL, MLOCK and KSM * @lite: if non-zero, child makes only single TESTMEM+MB allocation * if zero, child keeps allocating memory until it gets killed * or some operation fails * @retcode: expected return code of child process * if matches child ret code, this function reports PASS, * otherwise it reports FAIL * @allow_sigkill: if zero and child is killed, this function reports FAIL * if non-zero, then if child is killed by SIGKILL * it is considered as PASS */ void oom(int testcase, int lite, int retcode, int allow_sigkill) { pid_t pid; int status, threads; switch (pid = SAFE_FORK()) { case 0: threads = MAX(1, tst_ncpus() - 1); child_alloc(testcase, lite, threads); default: break; } tst_res(TINFO, "expected victim is %d.", pid); SAFE_WAITPID(-1, &status, 0); if (WIFSIGNALED(status)) { if (allow_sigkill && WTERMSIG(status) == SIGKILL) { tst_res(TPASS, "victim signalled: (%d) %s", SIGKILL, tst_strsig(SIGKILL)); } else { tst_res(TFAIL, "victim signalled: (%d) %s", WTERMSIG(status), tst_strsig(WTERMSIG(status))); } } else if (WIFEXITED(status)) { if (WEXITSTATUS(status) == retcode) { tst_res(TPASS, "victim retcode: (%d) %s", retcode, strerror(retcode)); } else { tst_res(TFAIL, "victim unexpectedly ended with " "retcode: %d, expected: %d", WEXITSTATUS(status), retcode); } } else { tst_res(TFAIL, "victim unexpectedly ended"); } }