From 6cef6e726a6a844bb5dea6ab3841bf30b9dba122 Mon Sep 17 00:00:00 2001 From: Yuriy Vasiliev Date: Tue, 18 Jan 2022 14:35:55 +0100 Subject: [PATCH] zdtm: add tests for SIGTSTP stopped03 check that stopped by SIGTSTP tasks are restored correctly. stopped04 check that stopped by SIGSTOP tasks which have blocked SIGTSTP and have SIGTSTP pending are restored correctly. Signed-off-by: Yuriy Vasiliev --- test/zdtm/static/Makefile | 2 + test/zdtm/static/stopped03.c | 161 +++++++++++++++++++++++++++++++++++ test/zdtm/static/stopped04.c | 135 +++++++++++++++++++++++++++++ 3 files changed, 298 insertions(+) create mode 100644 test/zdtm/static/stopped03.c create mode 100644 test/zdtm/static/stopped04.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index a3c1ccf4b..5a8a5f75c 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -184,6 +184,8 @@ TST_NOFILE := \ stopped01 \ stopped02 \ stopped12 \ + stopped03 \ + stopped04 \ rtc \ clean_mntns \ mntns_rw_ro_rw \ diff --git a/test/zdtm/static/stopped03.c b/test/zdtm/static/stopped03.c new file mode 100644 index 000000000..85c7177f7 --- /dev/null +++ b/test/zdtm/static/stopped03.c @@ -0,0 +1,161 @@ +#include +#include +#include + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Check, that stopped by SIGTSTP tasks are restored correctly"; +const char *test_author = "Yuriy Vasiliev "; + +#define STOP_SIGNO SIGTSTP +const char *stop_sigstr = "SIGTSTP"; +enum { + FUTEX_INITIALIZED = 0, + TEST_CRIU, + TEST_CHECK, + TEST_DONE, + TEST_EXIT, + TEST_EMERGENCY_ABORT, +}; + +struct shared { + futex_t fstate; + int status; + int code; +} * sh; + +static int new_pgrp(void) +{ + siginfo_t infop; + int ret = 1; + pid_t pid; + + /* + * Set the PGID to avoid creating an orphaned process group, + * which is not to be affected by terminal-generated stop signals. + */ + setpgid(0, 0); + + pid = test_fork(); + if (pid < 0) + goto err_cr; + + if (pid == 0) { + /* wait for TEST_EXIT or TEST_EMERGENCY_ABORT*/ + futex_wait_while_lt(&sh->fstate, TEST_EXIT); + exit(0); + } + + if (kill(pid, STOP_SIGNO)) { + pr_perror("Unable to send %s", stop_sigstr); + goto err_cr; + } + + if (waitid(P_PID, pid, &infop, WNOWAIT | WSTOPPED) < 0) { + pr_perror("Unable to waitid %d", pid); + goto err_cont; + } + + sh->code = infop.si_code; + sh->status = infop.si_status; + + /* Return the control back to MAIN worker to do C/R */ + futex_set_and_wake(&sh->fstate, TEST_CRIU); + futex_wait_while_lt(&sh->fstate, TEST_CHECK); + + infop.si_code = 0; + infop.si_status = 0; + + if (waitid(P_PID, pid, &infop, WNOWAIT | WSTOPPED) < 0) { + pr_perror("Unable to waitid %d", pid); + goto err_cont; + } + + sh->code = infop.si_code; + sh->status = infop.si_status; + + futex_set_and_wake(&sh->fstate, TEST_DONE); + futex_wait_while_lt(&sh->fstate, TEST_EXIT); + + ret = 0; +err_cont: + kill(pid, SIGCONT); +err_cr: + if (ret) + futex_set_and_wake(&sh->fstate, TEST_EMERGENCY_ABORT); + if (pid > 0) + wait(NULL); + + return ret; +} + +int main(int argc, char **argv) +{ + int fail = 0; + pid_t pid; + + test_init(argc, argv); + + sh = mmap(NULL, sizeof(struct shared), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (sh == MAP_FAILED) { + pr_perror("Failed to alloc shared region"); + return 1; + } + + futex_set(&sh->fstate, FUTEX_INITIALIZED); + + pid = test_fork(); + if (pid < 0) { + fail = 1; + goto out; + } + + if (pid == 0) + exit(new_pgrp()); + + /* Wait until pgrp is ready to C/R */ + futex_wait_while_lt(&sh->fstate, TEST_CRIU); + if (futex_get(&sh->fstate) == TEST_EMERGENCY_ABORT) { + pr_err("Fail in child worker before C/R\n"); + fail = 1; + goto out; + } + + if (sh->code != CLD_STOPPED || sh->status != STOP_SIGNO) { + pr_err("Process is not in correct state before C/R." + " Expected stop signo: %d. Get stop signo: %d\n", + STOP_SIGNO, sh->status); + fail = 1; + goto out; + } + + test_daemon(); + test_waitsig(); + + futex_set_and_wake(&sh->fstate, TEST_CHECK); + futex_wait_while_lt(&sh->fstate, TEST_DONE); + if (futex_get(&sh->fstate) == TEST_EMERGENCY_ABORT) { + pr_err("Fail in child worker after C/R\n"); + goto out; + } + + if (sh->code != CLD_STOPPED || sh->status != STOP_SIGNO) { + fail = 1; + pr_err("Process is not in correct state after C/R." + " Expected stop signo: %d. Get stop signo: %d\n", + STOP_SIGNO, sh->status); + } + + if (!fail) + pass(); + + futex_set_and_wake(&sh->fstate, TEST_EXIT); +out: + if (pid > 0) + wait(NULL); + + munmap(sh, sizeof(struct shared)); + + return fail; +} diff --git a/test/zdtm/static/stopped04.c b/test/zdtm/static/stopped04.c new file mode 100644 index 000000000..237094ca4 --- /dev/null +++ b/test/zdtm/static/stopped04.c @@ -0,0 +1,135 @@ +#include +#include +#include + +#include "zdtmtst.h" +#include "lock.h" + +const char *test_doc = "Check, that stopped by SIGTSTP tasks are restored correctly"; +const char *test_author = "Yuriy Vasiliev "; + +const char *stop_sigstr = "SIGTSTP"; +enum { + FUTEX_INITIALIZED = 0, + TEST_CRIU, + TEST_DONE, + TEST_EXIT, + TEST_EMERGENCY_ABORT, +}; + +struct shared { + futex_t fstate; + int status; + int code; +} * sh; + +static int new_pgrp(void) +{ + sigset_t sigset; + siginfo_t infop; + int ret = 1; + pid_t pid; + + /* + * Set the PGID to avoid creating an orphaned process group, + * which is not to be affected by terminal-generated stop signals. + */ + setpgid(0, 0); + + sigemptyset(&sigset); + sigaddset(&sigset, SIGTSTP); + sigprocmask(SIG_BLOCK, &sigset, NULL); + + pid = test_fork(); + if (pid < 0) + goto err_cr; + + if (pid == 0) { + /* wait for TEST_EXIT or TEST_EMERGENCY_ABORT*/ + futex_wait_while_lt(&sh->fstate, TEST_EXIT); + exit(0); + } + + if (kill(pid, SIGSTOP)) { + pr_perror("Unable to send %s", stop_sigstr); + goto err_cr; + } + + if (waitid(P_PID, pid, &infop, WNOWAIT | WSTOPPED) < 0) { + pr_perror("Unable to waitid %d", pid); + goto err_cont; + } + + if (kill(pid, SIGTSTP)) { + pr_perror("Unable to send %s", stop_sigstr); + goto err_cr; + } + + /* Return the control back to MAIN worker to do C/R */ + futex_set_and_wake(&sh->fstate, TEST_CRIU); + futex_wait_while_lt(&sh->fstate, TEST_EXIT); + + ret = 0; +err_cont: + kill(pid, SIGCONT); +err_cr: + if (ret) + futex_set_and_wake(&sh->fstate, TEST_EMERGENCY_ABORT); + if (pid > 0) + wait(NULL); + + return ret; +} + +int main(int argc, char **argv) +{ + int fail = 0; + pid_t pid; + + test_init(argc, argv); + + sh = mmap(NULL, sizeof(struct shared), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + if (sh == MAP_FAILED) { + pr_perror("Failed to alloc shared region"); + return 1; + } + + futex_set(&sh->fstate, FUTEX_INITIALIZED); + + pid = test_fork(); + if (pid < 0) { + fail = 1; + goto out; + } + + if (pid == 0) + exit(new_pgrp()); + + /* Wait until pgrp is ready to C/R */ + futex_wait_while_lt(&sh->fstate, TEST_CRIU); + if (futex_get(&sh->fstate) == TEST_EMERGENCY_ABORT) { + pr_err("Fail in child worker before C/R\n"); + fail = 1; + goto out; + } + + test_daemon(); + test_waitsig(); + + if (futex_get(&sh->fstate) == TEST_EMERGENCY_ABORT) { + pr_err("Fail in child worker after C/R\n"); + goto out; + } + + if (!fail) + pass(); + + futex_set_and_wake(&sh->fstate, TEST_EXIT); +out: + if (pid > 0) + wait(NULL); + + munmap(sh, sizeof(struct shared)); + + return fail; +}