[LTP] [PATCH v2 1/2] clone08: convert to new LTP API
Alexey Kodanev
alexey.kodanev@oracle.com
Thu Jun 8 11:57:30 CEST 2017
In addition:
* use tst_reap_children()
* remove usage of tst_tmpdir()
* change behaviour in CLONE_STOPPED test-case: set flag after
clone() and before kill() to make sure the thread updated
this flag after the signal is sent
* define clone functions with 'void *arg'
* exit forked children with _exit()
* add test-case for CLONE_CHILD_CLEARTID flag.
Set CLONE_CHILD_CLEARTID in 'CLONE_THREAD' test-case to
clear ctid when the child clone exits. Use futex to wait
for ctid to be changed.
Signed-off-by: Alexey Kodanev <alexey.kodanev@oracle.com>
---
v2: * move tst_res() to child function where possible
* merge the patch with CLEARTID test-case
* remove TCID field
testcases/kernel/syscalls/clone/clone08.c | 264 +++++++++++------------------
1 files changed, 97 insertions(+), 167 deletions(-)
diff --git a/testcases/kernel/syscalls/clone/clone08.c b/testcases/kernel/syscalls/clone/clone08.c
index 4c71db4..958755a 100644
--- a/testcases/kernel/syscalls/clone/clone08.c
+++ b/testcases/kernel/syscalls/clone/clone08.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved.
* Copyright (c) 2013 Fujitsu Ltd.
* Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com>
*
@@ -15,39 +16,36 @@
*/
#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
#include <errno.h>
#include <sched.h>
#include <sys/wait.h>
-#include "test.h"
+#include <linux/futex.h>
+
+#include "tst_test.h"
#include "clone_platform.h"
-#include "safe_macros.h"
#include "linux_syscall_numbers.h"
-char *TCID = "clone08";
-
static pid_t ptid, ctid, tgid;
static void *child_stack;
-static void setup(void);
-static void cleanup(void);
-
static void test_clone_parent(int t);
-static int child_clone_parent(void);
+static int child_clone_parent(void *);
static pid_t parent_ppid;
static void test_clone_tid(int t);
-static int child_clone_child_settid(void);
-static int child_clone_parent_settid(void);
+static int child_clone_child_settid(void *);
+static int child_clone_parent_settid(void *);
#ifdef CLONE_STOPPED
static void test_clone_stopped(int t);
-static int child_clone_stopped(void);
+static int child_clone_stopped(void *);
static int stopped_flag;
#endif
static void test_clone_thread(int t);
-static int child_clone_thread(void);
-static int tst_result;
+static int child_clone_thread(void *);
/*
* Children cloned with CLONE_VM should avoid using any functions that
@@ -61,7 +59,7 @@ static struct test_case {
char *name;
int flags;
void (*testfunc)(int);
- int (*do_child)();
+ int (*do_child)(void *);
} test_cases[] = {
{"CLONE_PARENT", CLONE_PARENT | SIGCHLD,
test_clone_parent, child_clone_parent},
@@ -73,154 +71,91 @@ static struct test_case {
{"CLONE_STOPPED", CLONE_STOPPED | CLONE_VM | SIGCHLD,
test_clone_stopped, child_clone_stopped},
#endif
- {"CLONE_THREAD", CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | SIGCHLD,
+ {"CLONE_THREAD", CLONE_THREAD | CLONE_SIGHAND | CLONE_VM |
+ CLONE_CHILD_CLEARTID | SIGCHLD,
test_clone_thread, child_clone_thread},
};
-int TST_TOTAL = ARRAY_SIZE(test_cases);
-
-int main(int ac, char **av)
+static void do_test(unsigned int i)
{
- int i, lc;
-
- tst_parse_opts(ac, av, NULL, NULL);
-
- setup();
- for (lc = 0; TEST_LOOPING(lc); lc++) {
- tst_count = 0;
- for (i = 0; i < TST_TOTAL; i++) {
- tst_resm(TINFO, "running %s", test_cases[i].name);
- test_cases[i].testfunc(i);
- }
- }
- cleanup();
- tst_exit();
+ tst_res(TINFO, "running %s", test_cases[i].name);
+ test_cases[i].testfunc(i);
}
static void setup(void)
{
- tst_sig(FORK, DEF_HANDLER, cleanup);
-
- TEST_PAUSE;
-
- tst_tmpdir();
-
- child_stack = SAFE_MALLOC(cleanup, CHILD_STACK_SIZE);
+ child_stack = SAFE_MALLOC(CHILD_STACK_SIZE);
}
static void cleanup(void)
{
free(child_stack);
-
- tst_rmdir();
}
-static long clone_child(const struct test_case *t, int use_tst)
+static long clone_child(const struct test_case *t)
{
TEST(ltp_clone7(t->flags, t->do_child, NULL, CHILD_STACK_SIZE,
child_stack, &ptid, NULL, &ctid));
if (TEST_RETURN == -1 && TTERRNO == ENOSYS)
- tst_brkm(TCONF, cleanup, "clone does not support 7 args");
-
- if (TEST_RETURN == -1) {
- if (use_tst) {
- tst_brkm(TBROK | TTERRNO, cleanup, "%s clone() failed",
- t->name);
- } else {
- printf("%s clone() failed, errno: %d",
- t->name, TEST_ERRNO);
- exit(1);
- }
- }
- return TEST_RETURN;
-}
+ tst_brk(TCONF, "clone does not support 7 args");
-static int wait4child(pid_t child)
-{
- int status;
+ if (TEST_RETURN == -1)
+ tst_brk(TBROK | TTERRNO, "%s clone() failed", t->name);
- if (waitpid(child, &status, 0) == -1)
- tst_resm(TBROK|TERRNO, "waitpid");
- if (WIFEXITED(status))
- return WEXITSTATUS(status);
- else
- return status;
+ return TEST_RETURN;
}
static void test_clone_parent(int t)
{
- int status;
pid_t child;
- fflush(stdout);
- child = FORK_OR_VFORK();
- switch (child) {
- case 0:
+ child = SAFE_FORK();
+ if (!child) {
parent_ppid = getppid();
- clone_child(&test_cases[t], 0);
- exit(0);
- case -1:
- tst_brkm(TBROK | TERRNO, NULL, "test_clone_parent fork");
- default:
- status = wait4child(child);
- if (status == 0) {
- /* wait for CLONE_PARENT child */
- status = wait4child(-1);
- if (status == 0) {
- tst_resm(TPASS, "test %s", test_cases[t].name);
- } else {
- tst_resm(TFAIL, "test %s, status: %d",
- test_cases[t].name, status);
- }
- } else {
- tst_resm(TFAIL, "test %s, status: %d",
- test_cases[t].name, status);
- }
- };
+ clone_child(&test_cases[t]);
+ _exit(0);
+ }
+ tst_reap_children();
}
-static int child_clone_parent(void)
+static int child_clone_parent(void *arg LTP_ATTRIBUTE_UNUSED)
{
- if (parent_ppid == getppid())
- exit(0);
- printf("FAIL: getppid != parent_ppid (%d != %d)\n",
- parent_ppid, getppid());
- exit(1);
+ if (parent_ppid == getppid()) {
+ tst_res(TPASS, "clone and forked child has the same parent");
+ } else {
+ tst_res(TFAIL, "getppid != parent_ppid (%d != %d)",
+ parent_ppid, getppid());
+ }
+ tst_syscall(__NR_exit, 0);
+ return 0;
}
static void test_clone_tid(int t)
{
- int status;
pid_t child;
- child = clone_child(&test_cases[t], 1);
- status = wait4child(child);
- if (status == 0) {
- tst_resm(TPASS, "test %s", test_cases[t].name);
- } else {
- tst_resm(TFAIL, "test %s, status: %d",
- test_cases[t].name, status);
- }
+ child = clone_child(&test_cases[t]);
+ tst_reap_children();
}
-static int child_clone_child_settid(void)
+static int child_clone_child_settid(void *arg LTP_ATTRIBUTE_UNUSED)
{
- if (ctid == ltp_syscall(__NR_getpid))
- ltp_syscall(__NR_exit, 0);
- printf("FAIL: ctid != getpid() (%d != %d)\n",
- ctid, getpid());
- ltp_syscall(__NR_exit, 1);
+ if (ctid == tst_syscall(__NR_getpid))
+ tst_res(TPASS, "clone() correctly set ctid");
+ else
+ tst_res(TFAIL, "ctid != getpid() (%d != %d)", ctid, getpid());
+ tst_syscall(__NR_exit, 0);
return 0;
}
-static int child_clone_parent_settid(void)
+static int child_clone_parent_settid(void *arg LTP_ATTRIBUTE_UNUSED)
{
- if (ptid == ltp_syscall(__NR_getpid))
- ltp_syscall(__NR_exit, 0);
- printf("FAIL: ptid != getpid() (%d != %d)\n",
- ptid, getpid());
- ltp_syscall(__NR_exit, 1);
+ if (ptid == tst_syscall(__NR_getpid))
+ tst_res(TPASS, "clone() correctly set ptid");
+ else
+ tst_res(TFAIL, "ptid != getpid() (%d != %d)", ptid, getpid());
+ tst_syscall(__NR_exit, 0);
return 0;
}
@@ -228,17 +163,14 @@ static int child_clone_parent_settid(void)
static void test_clone_stopped(int t)
{
int i;
- int status;
- int flag;
pid_t child;
if (tst_kvercmp(2, 6, 38) >= 0) {
- tst_resm(TINFO, "CLONE_STOPPED skipped for kernels >= 2.6.38");
+ tst_res(TCONF, "CLONE_STOPPED skipped for kernels >= 2.6.38");
return;
}
- stopped_flag = 0;
- child = clone_child(&test_cases[t], 1);
+ child = clone_child(&test_cases[t]);
/* give the kernel scheduler chance to run the CLONE_STOPPED thread*/
for (i = 0; i < 100; i++) {
@@ -246,23 +178,22 @@ static void test_clone_stopped(int t)
usleep(1000);
}
- flag = stopped_flag;
- if (kill(child, SIGCONT) != 0)
- tst_brkm(TBROK | TERRNO, cleanup, "kill SIGCONT failed");
+ stopped_flag = 0;
- status = wait4child(child);
- if (status == 0 && flag == 0) {
- tst_resm(TPASS, "test %s", test_cases[t].name);
- } else {
- tst_resm(TFAIL, "test %s, status: %d, flag: %d",
- test_cases[t].name, status, flag);
- }
+ SAFE_KILL(child, SIGCONT);
+
+ tst_reap_children();
+
+ if (stopped_flag == 1)
+ tst_res(TPASS, "clone stopped and resumed as expected");
+ else
+ tst_res(TFAIL, "clone not stopped, flag %d", stopped_flag);
}
-static int child_clone_stopped(void)
+static int child_clone_stopped(void *arg LTP_ATTRIBUTE_UNUSED)
{
stopped_flag = 1;
- ltp_syscall(__NR_exit, 0);
+ tst_syscall(__NR_exit, 0);
return 0;
}
#endif
@@ -270,42 +201,41 @@ static int child_clone_stopped(void)
static void test_clone_thread(int t)
{
pid_t child;
- int i, status;
-
- fflush(stdout);
- child = FORK_OR_VFORK();
- switch (child) {
- case 0:
- tgid = ltp_syscall(__NR_getpid);
- tst_result = -1;
- clone_child(&test_cases[t], 0);
-
- for (i = 0; i < 5000; i++) {
- sched_yield();
- usleep(1000);
- if (tst_result != -1)
- break;
- }
- ltp_syscall(__NR_exit, tst_result);
- case -1:
- tst_brkm(TBROK | TERRNO, NULL, "test_clone_thread fork");
- default:
- status = wait4child(child);
- if (status == 0) {
- tst_resm(TPASS, "test %s", test_cases[t].name);
- } else {
- tst_resm(TFAIL, "test %s, status: %d",
- test_cases[t].name, status);
- }
- };
+
+ child = SAFE_FORK();
+ if (!child) {
+ struct timespec timeout = { 5 /* sec */, 0 };
+
+ tgid = tst_syscall(__NR_getpid);
+ ctid = -1;
+
+ clone_child(&test_cases[t]);
+
+ if (syscall(SYS_futex, &ctid, FUTEX_WAIT, -1, &timeout))
+ tst_res(TFAIL | TERRNO, "futex failed");
+ else
+ tst_res(TPASS, "futex exit on ctid change");
+
+ _exit(0);
+ }
+
+ tst_reap_children();
}
-static int child_clone_thread(void)
+static int child_clone_thread(void *arg LTP_ATTRIBUTE_UNUSED)
{
- if (tgid == ltp_syscall(__NR_getpid))
- tst_result = TPASS;
+ if (tgid == tst_syscall(__NR_getpid))
+ tst_res(TPASS, "clone has the same thread id");
else
- tst_result = TFAIL;
- ltp_syscall(__NR_exit, 0);
+ tst_res(TFAIL, "clone's thread id not equal parent's id");
+ tst_syscall(__NR_exit, 0);
return 0;
}
+
+static struct tst_test test = {
+ .tcnt = ARRAY_SIZE(test_cases),
+ .test = do_test,
+ .setup = setup,
+ .cleanup = cleanup,
+ .forks_child = 1
+};
--
1.7.1
More information about the ltp
mailing list