16a395824SDmitry Vyukov // RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=atexit_sleep_ms=0 %run %t 2>&1 | FileCheck %s
26a395824SDmitry Vyukov 
36a395824SDmitry Vyukov // This test models what happens on Mac when fork
46a395824SDmitry Vyukov // calls malloc/free inside of our atfork callbacks.
56a395824SDmitry Vyukov // and ensures that we don't deadlock on malloc/free calls.
66a395824SDmitry Vyukov 
76a395824SDmitry Vyukov #include "../test.h"
86a395824SDmitry Vyukov #include "syscall.h"
96a395824SDmitry Vyukov #include <errno.h>
106a395824SDmitry Vyukov #include <string.h>
116a395824SDmitry Vyukov #include <sys/types.h>
126a395824SDmitry Vyukov #include <sys/wait.h>
136a395824SDmitry Vyukov 
14*be77afe4SAlexander Potapenko // disable_sanitizer_instrumentation on __tsan_test_only_on_fork is not
15*be77afe4SAlexander Potapenko // transitive, so we must apply it here as well.
16*be77afe4SAlexander Potapenko // Instrumenting alloc_free_blocks() will result in deadlocks in TSan.
alloc_free_blocks()17*be77afe4SAlexander Potapenko __attribute__((disable_sanitizer_instrumentation)) void alloc_free_blocks() {
186a395824SDmitry Vyukov   // Allocate a bunch of blocks to drain local allocator cache
196a395824SDmitry Vyukov   // and provoke it to lock allocator global mutexes.
206a395824SDmitry Vyukov   const int kBlocks = 1000;
216a395824SDmitry Vyukov   void *blocks[kBlocks];
226a395824SDmitry Vyukov   for (int i = 0; i < kBlocks; i++) {
236a395824SDmitry Vyukov     void *p = malloc(10);
246a395824SDmitry Vyukov     *(volatile char *)p = 0;
256a395824SDmitry Vyukov     blocks[i] = p;
266a395824SDmitry Vyukov   }
276a395824SDmitry Vyukov   for (int i = 0; i < kBlocks; i++)
286a395824SDmitry Vyukov     free(blocks[i]);
296a395824SDmitry Vyukov }
306a395824SDmitry Vyukov 
316a395824SDmitry Vyukov __attribute__((disable_sanitizer_instrumentation)) extern "C" void
__tsan_test_only_on_fork()326a395824SDmitry Vyukov __tsan_test_only_on_fork() {
336a395824SDmitry Vyukov   const char *msg = "__tsan_test_only_on_fork\n";
346a395824SDmitry Vyukov   write(2, msg, strlen(msg));
356a395824SDmitry Vyukov   alloc_free_blocks();
366a395824SDmitry Vyukov }
376a395824SDmitry Vyukov 
background(void * p)386a395824SDmitry Vyukov static void *background(void *p) {
396a395824SDmitry Vyukov   for (;;)
406a395824SDmitry Vyukov     alloc_free_blocks();
416a395824SDmitry Vyukov   return 0;
426a395824SDmitry Vyukov }
436a395824SDmitry Vyukov 
main()446a395824SDmitry Vyukov int main() {
456a395824SDmitry Vyukov   pthread_t th;
466a395824SDmitry Vyukov   pthread_create(&th, 0, background, 0);
476a395824SDmitry Vyukov   pthread_detach(th);
486a395824SDmitry Vyukov   for (int i = 0; i < 10; i++) {
496a395824SDmitry Vyukov     int pid = myfork();
506a395824SDmitry Vyukov     if (pid < 0) {
516a395824SDmitry Vyukov       fprintf(stderr, "failed to fork (%d)\n", errno);
526a395824SDmitry Vyukov       exit(1);
536a395824SDmitry Vyukov     }
546a395824SDmitry Vyukov     if (pid == 0) {
556a395824SDmitry Vyukov       // child
566a395824SDmitry Vyukov       exit(0);
576a395824SDmitry Vyukov     }
586a395824SDmitry Vyukov     // parent
596a395824SDmitry Vyukov     while (wait(0) < 0) {
606a395824SDmitry Vyukov     }
616a395824SDmitry Vyukov   }
626a395824SDmitry Vyukov   fprintf(stderr, "DONE\n");
636a395824SDmitry Vyukov }
646a395824SDmitry Vyukov 
656a395824SDmitry Vyukov // CHECK: __tsan_test_only_on_fork
666a395824SDmitry Vyukov // CHECK: DONE
67