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