1 // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t > %t.out
2 // RUN: FileCheck %s --check-prefixes=CHECK,PARENT --input-file %t.out
3 // RUN: FileCheck %s --check-prefixes=CHECK,CHILD --input-file %t.out
5 // https://groups.google.com/g/thread-sanitizer/c/TQrr4-9PRYo/m/HFR4FMi6AQAJ
10 #include <sys/types.h>
15 void *worker(void *main
) {
17 // synchronize with main
18 barrier_wait(&barrier
);
19 // synchronize with atfork
20 barrier_wait(&barrier
);
21 pthread_kill((pthread_t
)main
, SIGPROF
);
22 barrier_wait(&barrier
);
23 // synchronize with afterfork
24 barrier_wait(&barrier
);
25 pthread_kill((pthread_t
)main
, SIGPROF
);
26 barrier_wait(&barrier
);
31 barrier_wait(&barrier
);
32 barrier_wait(&barrier
);
33 write(2, "in atfork\n", strlen("in atfork\n"));
34 static volatile long a
;
35 __atomic_fetch_add(&a
, 1, __ATOMIC_RELEASE
);
39 barrier_wait(&barrier
);
40 barrier_wait(&barrier
);
41 write(2, "in afterfork\n", strlen("in afterfork\n"));
42 static volatile long a
;
43 __atomic_fetch_add(&a
, 1, __ATOMIC_RELEASE
);
46 void afterfork_child() {
47 write(2, "in afterfork_child\n", strlen("in afterfork_child\n"));
51 void handler(int sig
) {
52 write(2, "in handler\n", strlen("in handler\n"));
57 barrier_init(&barrier
, 2);
58 struct sigaction act
= {};
59 act
.sa_handler
= &handler
;
60 if (sigaction(SIGPROF
, &act
, 0)) {
64 pthread_atfork(atfork
, afterfork
, afterfork_child
);
66 pthread_create(&t
, NULL
, worker
, (void *)pthread_self());
67 barrier_wait(&barrier
);
70 fprintf(stderr
, "fork failed: %d\n", errno
);
74 fprintf(stderr
, "CHILD\n");
77 if (pid
!= waitpid(pid
, NULL
, 0)) {
78 fprintf(stderr
, "waitpid failed: %d\n", errno
);
81 pthread_join(t
, NULL
);
82 fprintf(stderr
, "PARENT\n");
88 // CHECK: ThreadSanitizer: data race
89 // CHECK: Write of size 8
91 // CHECK: Previous write of size 8
95 // CHILD: afterfork_child