1 // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 66 2>&1 | FileCheck %s -check-prefix=CHECK-DIE 2 // RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=die_after_fork=0 %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-NODIE 3 #include "test.h" 4 #include <errno.h> 5 #include <sys/types.h> 6 #include <sys/wait.h> 7 8 static void *sleeper(void *p) { 9 barrier_wait(&barrier); 10 return 0; 11 } 12 13 static void *nop(void *p) { 14 return 0; 15 } 16 17 int main(int argc, const char **argv) { 18 barrier_init(&barrier, 3); 19 const int kSleeperThreads = 2; 20 barrier_init(&barrier, kSleeperThreads + 1); 21 pthread_t th0[kSleeperThreads]; 22 for (int i = 0; i < kSleeperThreads; i++) 23 pthread_create(&th0[i], 0, sleeper, 0); 24 const int kNopThreads = 5; 25 pthread_t th1[kNopThreads]; 26 for (int i = 0; i < kNopThreads; i++) 27 pthread_create(&th1[i], 0, nop, 0); 28 for (int i = 0; i < kNopThreads; i++) 29 pthread_join(th1[i], 0); 30 int pid = fork(); 31 if (pid < 0) { 32 fprintf(stderr, "failed to fork (%d)\n", errno); 33 exit(1); 34 } 35 if (pid == 0) { 36 // child 37 const int kChildThreads = 4; 38 pthread_t th2[kChildThreads]; 39 for (int i = 0; i < kChildThreads; i++) 40 pthread_create(&th2[i], 0, nop, 0); 41 for (int i = 0; i < kChildThreads; i++) 42 pthread_join(th2[i], 0); 43 exit(0); 44 return 0; 45 } 46 // parent 47 int expect = argc > 1 ? atoi(argv[1]) : 0; 48 int status = 0; 49 while (waitpid(pid, &status, 0) != pid) { 50 } 51 if (!WIFEXITED(status) || WEXITSTATUS(status) != expect) { 52 fprintf(stderr, "subprocess exited with %d, expected %d\n", status, expect); 53 exit(1); 54 } 55 barrier_wait(&barrier); 56 for (int i = 0; i < kSleeperThreads; i++) 57 pthread_join(th0[i], 0); 58 fprintf(stderr, "OK\n"); 59 return 0; 60 } 61 62 // CHECK-DIE: ThreadSanitizer: starting new threads after multi-threaded fork is not supported 63 64 // CHECK-NODIE-NOT: ThreadSanitizer: 65 // CHECK-NODIE: OK 66 // CHECK-NODIE-NOT: ThreadSanitizer: 67