blob: 66fc22f21aa5abc0ec63958fa759087a8d18ef1d [file] [log] [blame]
zenglg.jy853f9812013-12-18 17:32:15 +08001/*
2 * Copyright (c) 2013 Fujitsu Ltd.
3 * Author: Zeng Linggang <zenglg.jy@cn.fujitsu.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program.
15 */
16
Cyril Hrubis50a1afe2014-01-09 13:54:56 +010017#define _GNU_SOURCE
zenglg.jy853f9812013-12-18 17:32:15 +080018#include <errno.h>
zenglg.jy853f9812013-12-18 17:32:15 +080019#include <sched.h>
20#include <sys/wait.h>
21#include "test.h"
zenglg.jy853f9812013-12-18 17:32:15 +080022#include "clone_platform.h"
23#include "safe_macros.h"
24#include "linux_syscall_numbers.h"
25
Zeng Linggang1db62662014-01-09 20:10:11 +080026char *TCID = "clone08";
27
zenglg.jy853f9812013-12-18 17:32:15 +080028static pid_t ptid, ctid, tgid;
29static void *child_stack;
30
31static void setup(void);
32static void cleanup(void);
33
34static void test_clone_parent(int t);
35static int child_clone_parent(void);
36static pid_t parent_ppid;
37
38static void test_clone_tid(int t);
39static int child_clone_child_settid(void);
40static int child_clone_parent_settid(void);
41
42#ifdef CLONE_STOPPED
43static void test_clone_stopped(int t);
44static int child_clone_stopped(void);
45static int stopped_flag;
46#endif
47
48static void test_clone_thread(int t);
49static int child_clone_thread(void);
50static int tst_result;
51
52/*
53 * Children cloned with CLONE_VM should avoid using any functions that
54 * might require dl_runtime_resolve, because they share thread-local
55 * storage with parent. If both try to resolve symbols at same time you
56 * can crash, likely at _dl_x86_64_restore_sse().
57 * See this thread for relevant discussion:
58 * http://www.mail-archive.com/utrace-devel@redhat.com/msg01944.html
59 */
60static struct test_case {
61 char *name;
62 int flags;
63 void (*testfunc)(int);
64 int (*do_child)();
65} test_cases[] = {
66 {"CLONE_PARENT", CLONE_PARENT | SIGCHLD,
67 test_clone_parent, child_clone_parent},
68 {"CLONE_CHILD_SETTID", CLONE_CHILD_SETTID | SIGCHLD,
69 test_clone_tid, child_clone_child_settid},
70 {"CLONE_PARENT_SETTID", CLONE_PARENT_SETTID | CLONE_VM | SIGCHLD,
71 test_clone_tid, child_clone_parent_settid},
72#ifdef CLONE_STOPPED
73 {"CLONE_STOPPED", CLONE_STOPPED | CLONE_VM | SIGCHLD,
74 test_clone_stopped, child_clone_stopped},
75#endif
76 {"CLONE_THREAD", CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | SIGCHLD,
77 test_clone_thread, child_clone_thread},
78};
79
zenglg.jy853f9812013-12-18 17:32:15 +080080int TST_TOTAL = ARRAY_SIZE(test_cases);
81
82int main(int ac, char **av)
83{
Cyril Hrubis0b9589f2014-05-27 17:40:33 +020084 const char *msg;
zenglg.jy853f9812013-12-18 17:32:15 +080085 int i, lc;
86
87 msg = parse_opts(ac, av, NULL, NULL);
88 if (msg != NULL)
89 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
90
91 setup();
92 for (lc = 0; TEST_LOOPING(lc); lc++) {
93 tst_count = 0;
94 for (i = 0; i < TST_TOTAL; i++) {
95 tst_resm(TINFO, "running %s", test_cases[i].name);
96 test_cases[i].testfunc(i);
97 }
98 }
99 cleanup();
100 tst_exit();
101}
102
103static void setup(void)
104{
105 tst_sig(FORK, DEF_HANDLER, cleanup);
106
107 TEST_PAUSE;
108
109 tst_tmpdir();
110
111 child_stack = SAFE_MALLOC(cleanup, CHILD_STACK_SIZE);
112}
113
114static void cleanup(void)
115{
116 free(child_stack);
117
118 tst_rmdir();
zenglg.jy853f9812013-12-18 17:32:15 +0800119}
120
121static long clone_child(const struct test_case *t, int use_tst)
122{
Zeng Linggang1db62662014-01-09 20:10:11 +0800123 TEST(ltp_clone7(t->flags, t->do_child, NULL, CHILD_STACK_SIZE,
zenglg.jy853f9812013-12-18 17:32:15 +0800124 child_stack, &ptid, NULL, &ctid));
Zeng Linggang1db62662014-01-09 20:10:11 +0800125
126 if (TEST_RETURN == -1 && TTERRNO == ENOSYS)
127 tst_brkm(TCONF, cleanup, "clone does not support 7 args");
128
zenglg.jy853f9812013-12-18 17:32:15 +0800129 if (TEST_RETURN == -1) {
130 if (use_tst) {
131 tst_brkm(TBROK | TTERRNO, cleanup, "%s clone() failed",
132 t->name);
133 } else {
134 printf("%s clone() failed, errno: %d",
135 t->name, TEST_ERRNO);
136 exit(1);
137 }
138 }
139 return TEST_RETURN;
140}
141
142static int wait4child(pid_t child)
143{
144 int status;
145
146 if (waitpid(child, &status, 0) == -1)
147 tst_resm(TBROK|TERRNO, "waitpid");
148 if (WIFEXITED(status))
149 return WEXITSTATUS(status);
150 else
151 return status;
152}
153
154static void test_clone_parent(int t)
155{
156 int status;
157 pid_t child;
158
159 fflush(stdout);
160 child = FORK_OR_VFORK();
161 switch (child) {
162 case 0:
163 parent_ppid = getppid();
164 clone_child(&test_cases[t], 0);
165 exit(0);
166 case -1:
167 tst_brkm(TBROK | TERRNO, NULL, "test_clone_parent fork");
168 default:
169 status = wait4child(child);
170 if (status == 0) {
171 /* wait for CLONE_PARENT child */
172 status = wait4child(-1);
173 if (status == 0) {
174 tst_resm(TPASS, "test %s", test_cases[t].name);
175 } else {
176 tst_resm(TFAIL, "test %s, status: %d",
177 test_cases[t].name, status);
178 }
179 } else {
180 tst_resm(TFAIL, "test %s, status: %d",
181 test_cases[t].name, status);
182 }
183 };
184}
185
186static int child_clone_parent(void)
187{
188 if (parent_ppid == getppid())
189 exit(0);
190 printf("FAIL: getppid != parent_ppid (%d != %d)\n",
191 parent_ppid, getppid());
192 exit(1);
193}
194
195static void test_clone_tid(int t)
196{
197 int status;
198 pid_t child;
199
200 child = clone_child(&test_cases[t], 1);
201 status = wait4child(child);
202 if (status == 0) {
203 tst_resm(TPASS, "test %s", test_cases[t].name);
204 } else {
205 tst_resm(TFAIL, "test %s, status: %d",
206 test_cases[t].name, status);
207 }
208}
209
210static int child_clone_child_settid(void)
211{
212 if (ctid == ltp_syscall(__NR_getpid))
213 ltp_syscall(__NR_exit, 0);
214 printf("FAIL: ctid != getpid() (%d != %d)\n",
215 ctid, getpid());
216 ltp_syscall(__NR_exit, 1);
217 return 0;
218}
219
220static int child_clone_parent_settid(void)
221{
222 if (ptid == ltp_syscall(__NR_getpid))
223 ltp_syscall(__NR_exit, 0);
224 printf("FAIL: ptid != getpid() (%d != %d)\n",
225 ptid, getpid());
226 ltp_syscall(__NR_exit, 1);
227 return 0;
228}
229
230#ifdef CLONE_STOPPED
231static void test_clone_stopped(int t)
232{
233 int i;
234 int status;
235 int flag;
236 pid_t child;
237
Shuang Qiudc054fb2014-04-30 14:53:45 +0800238 if (tst_kvercmp(2, 6, 38) >= 0) {
239 tst_resm(TINFO, "CLONE_STOPPED skipped for kernels >= 2.6.38");
240 return;
241 }
242
zenglg.jy853f9812013-12-18 17:32:15 +0800243 stopped_flag = 0;
244 child = clone_child(&test_cases[t], 1);
245
246 /* give the kernel scheduler chance to run the CLONE_STOPPED thread*/
247 for (i = 0; i < 100; i++) {
248 sched_yield();
249 usleep(1000);
250 }
251
252 flag = stopped_flag;
253 if (kill(child, SIGCONT) != 0)
254 tst_brkm(TBROK | TERRNO, cleanup, "kill SIGCONT failed");
255
256 status = wait4child(child);
257 if (status == 0 && flag == 0) {
258 tst_resm(TPASS, "test %s", test_cases[t].name);
259 } else {
260 tst_resm(TFAIL, "test %s, status: %d, flag: %d",
261 test_cases[t].name, status, flag);
262 }
263}
264
265static int child_clone_stopped(void)
266{
267 stopped_flag = 1;
268 ltp_syscall(__NR_exit, 0);
269 return 0;
270}
271#endif
272
273static void test_clone_thread(int t)
274{
275 pid_t child;
276 int i, status;
277
278 fflush(stdout);
279 child = FORK_OR_VFORK();
280 switch (child) {
281 case 0:
282 tgid = ltp_syscall(__NR_getpid);
283 tst_result = -1;
284 clone_child(&test_cases[t], 0);
285
286 for (i = 0; i < 5000; i++) {
287 sched_yield();
288 usleep(1000);
289 if (tst_result != -1)
290 break;
291 }
292 ltp_syscall(__NR_exit, tst_result);
293 case -1:
294 tst_brkm(TBROK | TERRNO, NULL, "test_clone_thread fork");
295 default:
296 status = wait4child(child);
297 if (status == 0) {
298 tst_resm(TPASS, "test %s", test_cases[t].name);
299 } else {
300 tst_resm(TFAIL, "test %s, status: %d",
301 test_cases[t].name, status);
302 }
303 };
304}
305
306static int child_clone_thread(void)
307{
308 if (tgid == ltp_syscall(__NR_getpid))
309 tst_result = TPASS;
310 else
311 tst_result = TFAIL;
312 ltp_syscall(__NR_exit, 0);
313 return 0;
314}