From 732b128129cf317468dc366c412be19f6a3ed01e Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 22 Dec 2014 09:44:56 +0000 Subject: [PATCH] tsan: add acquire/release functions to java interface they are required to handle synchronization on volatile/final fields llvm-svn: 224697 --- compiler-rt/lib/tsan/rtl/tsan_interface_java.cc | 30 ++++++++++++++++++ compiler-rt/lib/tsan/rtl/tsan_interface_java.h | 8 +++++ compiler-rt/test/tsan/java.h | 3 ++ compiler-rt/test/tsan/java_volatile.cc | 42 +++++++++++++++++++++++++ 4 files changed, 83 insertions(+) create mode 100644 compiler-rt/test/tsan/java_volatile.cc diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc index 8615349..0aea63d1 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc @@ -219,3 +219,33 @@ int __tsan_java_mutex_unlock_rec(jptr addr) { return MutexUnlock(thr, pc, addr, true); } + +void __tsan_java_acquire(jptr addr) { + SCOPED_JAVA_FUNC(__tsan_java_acquire); + DPrintf("#%d: java_acquire(%p)\n", thr->tid, addr); + CHECK_NE(jctx, 0); + CHECK_GE(addr, jctx->heap_begin); + CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); + + Acquire(thr, caller_pc, addr); +} + +void __tsan_java_release(jptr addr) { + SCOPED_JAVA_FUNC(__tsan_java_release); + DPrintf("#%d: java_release(%p)\n", thr->tid, addr); + CHECK_NE(jctx, 0); + CHECK_GE(addr, jctx->heap_begin); + CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); + + Release(thr, caller_pc, addr); +} + +void __tsan_java_release_store(jptr addr) { + SCOPED_JAVA_FUNC(__tsan_java_release); + DPrintf("#%d: java_release_store(%p)\n", thr->tid, addr); + CHECK_NE(jctx, 0); + CHECK_GE(addr, jctx->heap_begin); + CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); + + ReleaseStore(thr, caller_pc, addr); +} diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.h b/compiler-rt/lib/tsan/rtl/tsan_interface_java.h index 1f793df..30153a1 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.h @@ -79,6 +79,14 @@ void __tsan_java_mutex_lock_rec(jptr addr, int rec) INTERFACE_ATTRIBUTE; // the same recursion level. int __tsan_java_mutex_unlock_rec(jptr addr) INTERFACE_ATTRIBUTE; +// Raw acquire/release primitives. +// Can be used to establish happens-before edges on volatile/final fields, +// in atomic operations, etc. release_store is the same as release, but it +// breaks release sequence on addr (see C++ standard 1.10/7 for details). +void __tsan_java_acquire(jptr addr) INTERFACE_ATTRIBUTE; +void __tsan_java_release(jptr addr) INTERFACE_ATTRIBUTE; +void __tsan_java_release_store(jptr addr) INTERFACE_ATTRIBUTE; + #ifdef __cplusplus } // extern "C" #endif diff --git a/compiler-rt/test/tsan/java.h b/compiler-rt/test/tsan/java.h index d986d08..66f4623 100644 --- a/compiler-rt/test/tsan/java.h +++ b/compiler-rt/test/tsan/java.h @@ -18,4 +18,7 @@ void __tsan_java_mutex_read_lock(jptr addr); void __tsan_java_mutex_read_unlock(jptr addr); void __tsan_java_mutex_lock_rec(jptr addr, int rec); int __tsan_java_mutex_unlock_rec(jptr addr); +int __tsan_java_acquire(jptr addr); +int __tsan_java_release(jptr addr); +int __tsan_java_release_store(jptr addr); } diff --git a/compiler-rt/test/tsan/java_volatile.cc b/compiler-rt/test/tsan/java_volatile.cc new file mode 100644 index 0000000..56f4c2d --- /dev/null +++ b/compiler-rt/test/tsan/java_volatile.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "java.h" +#include + +jptr varaddr; +jptr lockaddr; + +void *Thread(void *p) { + while (__atomic_load_n((int*)lockaddr, __ATOMIC_RELAXED) == 0) + usleep(1000); + __tsan_java_acquire(lockaddr); + *(int*)varaddr = 42; + return 0; +} + +int main() { + int const kHeapSize = 1024 * 1024; + jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; + __tsan_java_init(jheap, kHeapSize); + const int kBlockSize = 16; + __tsan_java_alloc(jheap, kBlockSize); + varaddr = jheap; + lockaddr = jheap + 8; + pthread_t th; + pthread_create(&th, 0, Thread, 0); + *(int*)varaddr = 43; + __tsan_java_release(lockaddr); + __atomic_store_n((int*)lockaddr, 1, __ATOMIC_RELAXED); + pthread_join(th, 0); + *(int*)lockaddr = 0; + pthread_create(&th, 0, Thread, 0); + *(int*)varaddr = 43; + __tsan_java_release_store(lockaddr); + __atomic_store_n((int*)lockaddr, 1, __ATOMIC_RELAXED); + pthread_join(th, 0); + __tsan_java_free(jheap, kBlockSize); + fprintf(stderr, "DONE\n"); + return __tsan_java_fini(); +} + +// CHECK-NOT: WARNING: ThreadSanitizer: data race +// CHECK: DONE -- 2.7.4