[compiler-rt] r182088 - tsan: introduce recursive mutex lock/unlock java interface

Dmitry Vyukov dvyukov at google.com
Fri May 17 05:03:46 PDT 2013


Author: dvyukov
Date: Fri May 17 07:03:46 2013
New Revision: 182088

URL: http://llvm.org/viewvc/llvm-project?rev=182088&view=rev
Log:
tsan: introduce recursive mutex lock/unlock  java interface
this is required to handle Object.Wait()

Added:
    compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec.cc
    compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec_race.cc
Modified:
    compiler-rt/trunk/lib/tsan/lit_tests/java.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc
    compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
    compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc

Modified: compiler-rt/trunk/lib/tsan/lit_tests/java.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/java.h?rev=182088&r1=182087&r2=182088&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/java.h (original)
+++ compiler-rt/trunk/lib/tsan/lit_tests/java.h Fri May 17 07:03:46 2013
@@ -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);
 }

Added: compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec.cc?rev=182088&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec.cc Fri May 17 07:03:46 2013
@@ -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

Added: compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec_race.cc?rev=182088&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec_race.cc (added)
+++ compiler-rt/trunk/lib/tsan/lit_tests/java_lock_rec_race.cc Fri May 17 07:03:46 2013
@@ -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

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc?rev=182088&r1=182087&r2=182088&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.cc Fri May 17 07:03:46 2013
@@ -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 ad
   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
 
   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);
+}

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h?rev=182088&r1=182087&r2=182088&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_interface_java.h Fri May 17 07:03:46 2013
@@ -55,8 +55,7 @@ void __tsan_java_move(jptr src, jptr dst
 
 // 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)
 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"

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h?rev=182088&r1=182087&r2=182088&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl.h Fri May 17 07:03:46 2013
@@ -691,8 +691,8 @@ void ProcessPendingSignals(ThreadState *
 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);

Modified: compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc?rev=182088&r1=182087&r2=182088&view=diff
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc (original)
+++ compiler-rt/trunk/lib/tsan/rtl/tsan_rtl_mutex.cc Fri May 17 07:03:46 2013
@@ -79,9 +79,10 @@ void MutexDestroy(ThreadState *thr, uptr
   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
   } 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
       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
   }
   thr->mset.Del(s->GetId(), true);
   s->mtx.Unlock();
+  return rec;
 }
 
 void MutexReadLock(ThreadState *thr, uptr pc, uptr addr) {





More information about the llvm-commits mailing list