| // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s | |
| // Regression test for https://github.com/golang/go/issues/39186 | |
| // pthread barriers are not available on OS X | |
| // UNSUPPORTED: darwin | |
| #include "java.h" | |
| #include <string.h> | |
| struct Heap { | |
| uint64_t data; | |
| uint64_t ready; | |
| uint64_t finalized; | |
| uint64_t wg; | |
| pthread_barrier_t barrier_finalizer; | |
| pthread_barrier_t barrier_ballast; | |
| }; | |
| void *Thread1(void *p) { | |
| Heap* heap = (Heap*)p; | |
| pthread_barrier_wait(&heap->barrier_finalizer); | |
| __tsan_java_finalize(); | |
| __atomic_fetch_add(&heap->wg, 1, __ATOMIC_RELEASE); | |
| __atomic_store_n(&heap->finalized, 1, __ATOMIC_RELAXED); | |
| return 0; | |
| } | |
| void *Thread2(void *p) { | |
| Heap* heap = (Heap*)p; | |
| pthread_barrier_wait(&heap->barrier_finalizer); | |
| heap->data = 1; | |
| __atomic_store_n(&heap->ready, 1, __ATOMIC_RELEASE); | |
| return 0; | |
| } | |
| void *Thread3(void *p) { | |
| Heap* heap = (Heap*)p; | |
| pthread_barrier_wait(&heap->barrier_finalizer); | |
| while (__atomic_load_n(&heap->ready, __ATOMIC_ACQUIRE) != 1) | |
| pthread_yield(); | |
| while (__atomic_load_n(&heap->finalized, __ATOMIC_RELAXED) != 1) | |
| pthread_yield(); | |
| __atomic_fetch_add(&heap->wg, 1, __ATOMIC_RELEASE); | |
| return 0; | |
| } | |
| void *Ballast(void *p) { | |
| Heap* heap = (Heap*)p; | |
| pthread_barrier_wait(&heap->barrier_ballast); | |
| return 0; | |
| } | |
| int main() { | |
| Heap *heap = (Heap *)calloc(2, sizeof(Heap)) + 1; | |
| __tsan_java_init((jptr)heap, sizeof(*heap)); | |
| __tsan_java_alloc((jptr)heap, sizeof(*heap)); | |
| // Ballast threads merely make the bug a bit easier to trigger. | |
| const int kBallastThreads = 100; | |
| pthread_barrier_init(&heap->barrier_finalizer, 0, 4); | |
| pthread_barrier_init(&heap->barrier_ballast, 0, kBallastThreads + 1); | |
| pthread_t th[3]; | |
| pthread_create(&th[0], 0, Thread1, heap); | |
| pthread_create(&th[1], 0, Thread2, heap); | |
| pthread_t ballast[kBallastThreads]; | |
| for (int i = 0; i < kBallastThreads; i++) | |
| pthread_create(&ballast[i], 0, Ballast, heap); | |
| pthread_create(&th[2], 0, Thread3, heap); | |
| pthread_barrier_wait(&heap->barrier_ballast); | |
| for (int i = 0; i < kBallastThreads; i++) | |
| pthread_join(ballast[i], 0); | |
| pthread_barrier_wait(&heap->barrier_finalizer); | |
| while (__atomic_load_n(&heap->wg, __ATOMIC_ACQUIRE) != 2) | |
| pthread_yield(); | |
| if (heap->data != 1) | |
| exit(printf("no data\n")); | |
| for (int i = 0; i < 3; i++) | |
| pthread_join(th[i], 0); | |
| pthread_barrier_destroy(&heap->barrier_ballast); | |
| pthread_barrier_destroy(&heap->barrier_finalizer); | |
| __tsan_java_free((jptr)heap, sizeof(*heap)); | |
| fprintf(stderr, "DONE\n"); | |
| return __tsan_java_fini(); | |
| } | |
| // CHECK-NOT: WARNING: ThreadSanitizer: data race | |
| // CHECK: DONE |