diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2013-05-17 12:03:46 +0000 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2013-05-17 12:03:46 +0000 |
| commit | c9af8185153178abc5649196c472d5325d0389ee (patch) | |
| tree | fce306cf761a582dea6b9ec08952dd867e73c7b6 | |
| parent | 69c544d857ad7dbc0521d861bd90c7a124de8b0e (diff) | |
| download | bcm5719-llvm-c9af8185153178abc5649196c472d5325d0389ee.tar.gz bcm5719-llvm-c9af8185153178abc5649196c472d5325d0389ee.zip | |
tsan: introduce recursive mutex lock/unlock java interface
this is required to handle Object.Wait()
llvm-svn: 182088
| -rw-r--r-- | compiler-rt/lib/tsan/lit_tests/java.h | 2 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/lit_tests/java_lock_rec.cc | 54 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/lit_tests/java_lock_rec_race.cc | 48 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_interface_java.cc | 24 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_interface_java.h | 13 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl.h | 4 | ||||
| -rw-r--r-- | compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc | 16 |
7 files changed, 151 insertions, 10 deletions
diff --git a/compiler-rt/lib/tsan/lit_tests/java.h b/compiler-rt/lib/tsan/lit_tests/java.h index 7d61f580286..04094197edb 100644 --- a/compiler-rt/lib/tsan/lit_tests/java.h +++ b/compiler-rt/lib/tsan/lit_tests/java.h @@ -14,4 +14,6 @@ void __tsan_java_mutex_lock(jptr addr); void __tsan_java_mutex_unlock(jptr addr); 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); } diff --git a/compiler-rt/lib/tsan/lit_tests/java_lock_rec.cc b/compiler-rt/lib/tsan/lit_tests/java_lock_rec.cc new file mode 100644 index 00000000000..5cc80d4a33e --- /dev/null +++ b/compiler-rt/lib/tsan/lit_tests/java_lock_rec.cc @@ -0,0 +1,54 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s +#include "java.h" +#include <unistd.h> + +jptr varaddr; +jptr lockaddr; + +void *Thread(void *p) { + __tsan_java_mutex_lock(lockaddr); + __tsan_java_mutex_lock(lockaddr); + *(int*)varaddr = 42; + int rec = __tsan_java_mutex_unlock_rec(lockaddr); + if (rec != 2) { + printf("FAILED 0 rec=%d\n", rec); + exit(1); + } + sleep(2); + __tsan_java_mutex_lock_rec(lockaddr, rec); + if (*(int*)varaddr != 43) { + printf("FAILED 3 var=%d\n", *(int*)varaddr); + exit(1); + } + __tsan_java_mutex_unlock(lockaddr); + __tsan_java_mutex_unlock(lockaddr); + return 0; +} + +int main() { + int const kHeapSize = 1024 * 1024; + void *jheap = malloc(kHeapSize); + __tsan_java_init((jptr)jheap, kHeapSize); + const int kBlockSize = 16; + __tsan_java_alloc((jptr)jheap, kBlockSize); + varaddr = (jptr)jheap; + *(int*)varaddr = 0; + lockaddr = (jptr)jheap + 8; + pthread_t th; + pthread_create(&th, 0, Thread, 0); + sleep(1); + __tsan_java_mutex_lock(lockaddr); + if (*(int*)varaddr != 42) { + printf("FAILED 1 var=%d\n", *(int*)varaddr); + exit(1); + } + *(int*)varaddr = 43; + __tsan_java_mutex_unlock(lockaddr); + pthread_join(th, 0); + __tsan_java_free((jptr)jheap, kBlockSize); + printf("OK\n"); + return __tsan_java_fini(); +} + +// CHECK-NOT: WARNING: ThreadSanitizer: data race +// CHECK-NOT: FAILED diff --git a/compiler-rt/lib/tsan/lit_tests/java_lock_rec_race.cc b/compiler-rt/lib/tsan/lit_tests/java_lock_rec_race.cc new file mode 100644 index 00000000000..61626aaddc0 --- /dev/null +++ b/compiler-rt/lib/tsan/lit_tests/java_lock_rec_race.cc @@ -0,0 +1,48 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %t 2>&1 | FileCheck %s +#include "java.h" +#include <unistd.h> + +jptr varaddr; +jptr lockaddr; + +void *Thread(void *p) { + __tsan_java_mutex_lock(lockaddr); + __tsan_java_mutex_lock(lockaddr); + __tsan_java_mutex_lock(lockaddr); + int rec = __tsan_java_mutex_unlock_rec(lockaddr); + if (rec != 3) { + printf("FAILED 0 rec=%d\n", rec); + exit(1); + } + *(int*)varaddr = 42; + sleep(2); + __tsan_java_mutex_lock_rec(lockaddr, rec); + __tsan_java_mutex_unlock(lockaddr); + __tsan_java_mutex_unlock(lockaddr); + __tsan_java_mutex_unlock(lockaddr); + return 0; +} + +int main() { + int const kHeapSize = 1024 * 1024; + void *jheap = malloc(kHeapSize); + __tsan_java_init((jptr)jheap, kHeapSize); + const int kBlockSize = 16; + __tsan_java_alloc((jptr)jheap, kBlockSize); + varaddr = (jptr)jheap; + *(int*)varaddr = 0; + lockaddr = (jptr)jheap + 8; + pthread_t th; + pthread_create(&th, 0, Thread, 0); + sleep(1); + __tsan_java_mutex_lock(lockaddr); + *(int*)varaddr = 43; + __tsan_java_mutex_unlock(lockaddr); + pthread_join(th, 0); + __tsan_java_free((jptr)jheap, kBlockSize); + printf("OK\n"); + return __tsan_java_fini(); +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK-NOT: FAILED diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc index ee1200107d1..71e0747c364 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.cc @@ -271,6 +271,7 @@ void __tsan_java_mutex_lock(jptr addr) { CHECK_GE(addr, jctx->heap_begin); CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); + MutexCreate(thr, pc, addr, true, true, true); MutexLock(thr, pc, addr); } @@ -291,6 +292,7 @@ void __tsan_java_mutex_read_lock(jptr addr) { CHECK_GE(addr, jctx->heap_begin); CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); + MutexCreate(thr, pc, addr, true, true, true); MutexReadLock(thr, pc, addr); } @@ -303,3 +305,25 @@ void __tsan_java_mutex_read_unlock(jptr addr) { MutexReadUnlock(thr, pc, addr); } + +void __tsan_java_mutex_lock_rec(jptr addr, int rec) { + SCOPED_JAVA_FUNC(__tsan_java_mutex_lock_rec); + DPrintf("#%d: java_mutex_lock_rec(%p, %d)\n", thr->tid, addr, rec); + CHECK_NE(jctx, 0); + CHECK_GE(addr, jctx->heap_begin); + CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); + CHECK_GT(rec, 0); + + MutexCreate(thr, pc, addr, true, true, true); + MutexLock(thr, pc, addr, rec); +} + +int __tsan_java_mutex_unlock_rec(jptr addr) { + SCOPED_JAVA_FUNC(__tsan_java_mutex_unlock_rec); + DPrintf("#%d: java_mutex_unlock_rec(%p)\n", thr->tid, addr); + CHECK_NE(jctx, 0); + CHECK_GE(addr, jctx->heap_begin); + CHECK_LT(addr, jctx->heap_begin + jctx->heap_size); + + return MutexUnlock(thr, pc, addr, true); +} diff --git a/compiler-rt/lib/tsan/rtl/tsan_interface_java.h b/compiler-rt/lib/tsan/rtl/tsan_interface_java.h index 241483aaa01..9ac78e074bb 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_interface_java.h +++ b/compiler-rt/lib/tsan/rtl/tsan_interface_java.h @@ -55,8 +55,7 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) INTERFACE_ATTRIBUTE; // Mutex lock. // Addr is any unique address associated with the mutex. -// Must not be called on recursive reentry. -// Object.wait() is handled as a pair of unlock/lock. +// Can be called on recursive reentry. void __tsan_java_mutex_lock(jptr addr) INTERFACE_ATTRIBUTE; // Mutex unlock. void __tsan_java_mutex_unlock(jptr addr) INTERFACE_ATTRIBUTE; @@ -64,6 +63,16 @@ void __tsan_java_mutex_unlock(jptr addr) INTERFACE_ATTRIBUTE; void __tsan_java_mutex_read_lock(jptr addr) INTERFACE_ATTRIBUTE; // Mutex read unlock. void __tsan_java_mutex_read_unlock(jptr addr) INTERFACE_ATTRIBUTE; +// Recursive mutex lock, intended for handling of Object.wait(). +// The 'rec' value must be obtained from the previous +// __tsan_java_mutex_unlock_rec(). +void __tsan_java_mutex_lock_rec(jptr addr, int rec) INTERFACE_ATTRIBUTE; +// Recursive mutex unlock, intended for handling of Object.wait(). +// The return value says how many times this thread called lock() +// w/o a pairing unlock() (i.e. how many recursive levels it unlocked). +// It must be passed back to __tsan_java_mutex_lock_rec() to restore +// the same recursion level. +int __tsan_java_mutex_unlock_rec(jptr addr) INTERFACE_ATTRIBUTE; #ifdef __cplusplus } // extern "C" diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h index efd6b140e49..f1a73e45733 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h @@ -691,8 +691,8 @@ void ProcessPendingSignals(ThreadState *thr); void MutexCreate(ThreadState *thr, uptr pc, uptr addr, bool rw, bool recursive, bool linker_init); void MutexDestroy(ThreadState *thr, uptr pc, uptr addr); -void MutexLock(ThreadState *thr, uptr pc, uptr addr); -void MutexUnlock(ThreadState *thr, uptr pc, uptr addr); +void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1); +int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false); void MutexReadLock(ThreadState *thr, uptr pc, uptr addr); void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr); void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr); diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc index 1f3c7ac9d25..cf2e44dd09e 100644 --- a/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc +++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_mutex.cc @@ -79,9 +79,10 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) { DestroyAndFree(s); } -void MutexLock(ThreadState *thr, uptr pc, uptr addr) { +void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec) { CHECK_GT(thr->in_rtl, 0); - DPrintf("#%d: MutexLock %zx\n", thr->tid, addr); + DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec); + CHECK_GT(rec, 0); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true); @@ -107,19 +108,20 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr) { } else if (!s->is_recursive) { StatInc(thr, StatMutexRecLock); } - s->recursion++; + s->recursion += rec; thr->mset.Add(s->GetId(), true, thr->fast_state.epoch()); s->mtx.Unlock(); } -void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) { +int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) { CHECK_GT(thr->in_rtl, 0); - DPrintf("#%d: MutexUnlock %zx\n", thr->tid, addr); + DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all); if (IsAppMem(addr)) MemoryReadAtomic(thr, pc, addr, kSizeLog1); SyncVar *s = CTX()->synctab.GetOrCreateAndLock(thr, pc, addr, true); thr->fast_state.IncrementEpoch(); TraceAddEvent(thr, thr->fast_state, EventTypeUnlock, s->GetId()); + int rec = 0; if (s->recursion == 0) { if (!s->is_broken) { s->is_broken = true; @@ -133,7 +135,8 @@ void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) { PrintCurrentStack(thr, pc); } } else { - s->recursion--; + rec = all ? s->recursion : 1; + s->recursion -= rec; if (s->recursion == 0) { StatInc(thr, StatMutexUnlock); s->owner_tid = SyncVar::kInvalidTid; @@ -147,6 +150,7 @@ void MutexUnlock(ThreadState *thr, uptr pc, uptr addr) { } thr->mset.Del(s->GetId(), true); s->mtx.Unlock(); + return rec; } void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) { |

