1 /* 2 * Copyright (c) 2013 Fujitsu Ltd. 3 * Author: Zeng Linggang <zenglg.jy (at) 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 17 #define _GNU_SOURCE 18 #include <errno.h> 19 #include <sched.h> 20 #include <sys/wait.h> 21 #include "test.h" 22 #include "clone_platform.h" 23 #include "safe_macros.h" 24 #include "linux_syscall_numbers.h" 25 26 char *TCID = "clone08"; 27 28 static pid_t ptid, ctid, tgid; 29 static void *child_stack; 30 31 static void setup(void); 32 static void cleanup(void); 33 34 static void test_clone_parent(int t); 35 static int child_clone_parent(void); 36 static pid_t parent_ppid; 37 38 static void test_clone_tid(int t); 39 static int child_clone_child_settid(void); 40 static int child_clone_parent_settid(void); 41 42 #ifdef CLONE_STOPPED 43 static void test_clone_stopped(int t); 44 static int child_clone_stopped(void); 45 static int stopped_flag; 46 #endif 47 48 static void test_clone_thread(int t); 49 static int child_clone_thread(void); 50 static 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 */ 60 static 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 80 int TST_TOTAL = ARRAY_SIZE(test_cases); 81 82 int main(int ac, char **av) 83 { 84 int i, lc; 85 86 tst_parse_opts(ac, av, NULL, NULL); 87 88 setup(); 89 for (lc = 0; TEST_LOOPING(lc); lc++) { 90 tst_count = 0; 91 for (i = 0; i < TST_TOTAL; i++) { 92 tst_resm(TINFO, "running %s", test_cases[i].name); 93 test_cases[i].testfunc(i); 94 } 95 } 96 cleanup(); 97 tst_exit(); 98 } 99 100 static void setup(void) 101 { 102 tst_sig(FORK, DEF_HANDLER, cleanup); 103 104 TEST_PAUSE; 105 106 tst_tmpdir(); 107 108 child_stack = SAFE_MALLOC(cleanup, CHILD_STACK_SIZE); 109 } 110 111 static void cleanup(void) 112 { 113 free(child_stack); 114 115 tst_rmdir(); 116 } 117 118 static long clone_child(const struct test_case *t, int use_tst) 119 { 120 TEST(ltp_clone7(t->flags, t->do_child, NULL, CHILD_STACK_SIZE, 121 child_stack, &ptid, NULL, &ctid)); 122 123 if (TEST_RETURN == -1 && TTERRNO == ENOSYS) 124 tst_brkm(TCONF, cleanup, "clone does not support 7 args"); 125 126 if (TEST_RETURN == -1) { 127 if (use_tst) { 128 tst_brkm(TBROK | TTERRNO, cleanup, "%s clone() failed", 129 t->name); 130 } else { 131 printf("%s clone() failed, errno: %d", 132 t->name, TEST_ERRNO); 133 exit(1); 134 } 135 } 136 return TEST_RETURN; 137 } 138 139 static int wait4child(pid_t child) 140 { 141 int status; 142 143 if (waitpid(child, &status, 0) == -1) 144 tst_resm(TBROK|TERRNO, "waitpid"); 145 if (WIFEXITED(status)) 146 return WEXITSTATUS(status); 147 else 148 return status; 149 } 150 151 static void test_clone_parent(int t) 152 { 153 int status; 154 pid_t child; 155 156 fflush(stdout); 157 child = FORK_OR_VFORK(); 158 switch (child) { 159 case 0: 160 parent_ppid = getppid(); 161 clone_child(&test_cases[t], 0); 162 exit(0); 163 case -1: 164 tst_brkm(TBROK | TERRNO, NULL, "test_clone_parent fork"); 165 default: 166 status = wait4child(child); 167 if (status == 0) { 168 /* wait for CLONE_PARENT child */ 169 status = wait4child(-1); 170 if (status == 0) { 171 tst_resm(TPASS, "test %s", test_cases[t].name); 172 } else { 173 tst_resm(TFAIL, "test %s, status: %d", 174 test_cases[t].name, status); 175 } 176 } else { 177 tst_resm(TFAIL, "test %s, status: %d", 178 test_cases[t].name, status); 179 } 180 }; 181 } 182 183 static int child_clone_parent(void) 184 { 185 if (parent_ppid == getppid()) 186 exit(0); 187 printf("FAIL: getppid != parent_ppid (%d != %d)\n", 188 parent_ppid, getppid()); 189 exit(1); 190 } 191 192 static void test_clone_tid(int t) 193 { 194 int status; 195 pid_t child; 196 197 child = clone_child(&test_cases[t], 1); 198 status = wait4child(child); 199 if (status == 0) { 200 tst_resm(TPASS, "test %s", test_cases[t].name); 201 } else { 202 tst_resm(TFAIL, "test %s, status: %d", 203 test_cases[t].name, status); 204 } 205 } 206 207 static int child_clone_child_settid(void) 208 { 209 if (ctid == ltp_syscall(__NR_getpid)) 210 ltp_syscall(__NR_exit, 0); 211 printf("FAIL: ctid != getpid() (%d != %d)\n", 212 ctid, getpid()); 213 ltp_syscall(__NR_exit, 1); 214 return 0; 215 } 216 217 static int child_clone_parent_settid(void) 218 { 219 if (ptid == ltp_syscall(__NR_getpid)) 220 ltp_syscall(__NR_exit, 0); 221 printf("FAIL: ptid != getpid() (%d != %d)\n", 222 ptid, getpid()); 223 ltp_syscall(__NR_exit, 1); 224 return 0; 225 } 226 227 #ifdef CLONE_STOPPED 228 static void test_clone_stopped(int t) 229 { 230 int i; 231 int status; 232 int flag; 233 pid_t child; 234 235 if (tst_kvercmp(2, 6, 38) >= 0) { 236 tst_resm(TINFO, "CLONE_STOPPED skipped for kernels >= 2.6.38"); 237 return; 238 } 239 240 stopped_flag = 0; 241 child = clone_child(&test_cases[t], 1); 242 243 /* give the kernel scheduler chance to run the CLONE_STOPPED thread*/ 244 for (i = 0; i < 100; i++) { 245 sched_yield(); 246 usleep(1000); 247 } 248 249 flag = stopped_flag; 250 if (kill(child, SIGCONT) != 0) 251 tst_brkm(TBROK | TERRNO, cleanup, "kill SIGCONT failed"); 252 253 status = wait4child(child); 254 if (status == 0 && flag == 0) { 255 tst_resm(TPASS, "test %s", test_cases[t].name); 256 } else { 257 tst_resm(TFAIL, "test %s, status: %d, flag: %d", 258 test_cases[t].name, status, flag); 259 } 260 } 261 262 static int child_clone_stopped(void) 263 { 264 stopped_flag = 1; 265 ltp_syscall(__NR_exit, 0); 266 return 0; 267 } 268 #endif 269 270 static void test_clone_thread(int t) 271 { 272 pid_t child; 273 int i, status; 274 275 fflush(stdout); 276 child = FORK_OR_VFORK(); 277 switch (child) { 278 case 0: 279 tgid = ltp_syscall(__NR_getpid); 280 tst_result = -1; 281 clone_child(&test_cases[t], 0); 282 283 for (i = 0; i < 5000; i++) { 284 sched_yield(); 285 usleep(1000); 286 if (tst_result != -1) 287 break; 288 } 289 ltp_syscall(__NR_exit, tst_result); 290 case -1: 291 tst_brkm(TBROK | TERRNO, NULL, "test_clone_thread fork"); 292 default: 293 status = wait4child(child); 294 if (status == 0) { 295 tst_resm(TPASS, "test %s", test_cases[t].name); 296 } else { 297 tst_resm(TFAIL, "test %s, status: %d", 298 test_cases[t].name, status); 299 } 300 }; 301 } 302 303 static int child_clone_thread(void) 304 { 305 if (tgid == ltp_syscall(__NR_getpid)) 306 tst_result = TPASS; 307 else 308 tst_result = TFAIL; 309 ltp_syscall(__NR_exit, 0); 310 return 0; 311 } 312