< prev index next >

src/hotspot/share/runtime/synchronizer.cpp

Print this page
*** 609,10 ***
--- 609,18 ---
  //  2) wait on lock2
  //  3) when notified on lock2, unlock lock2
  //  4) reenter lock1 with original recursion count
  //  5) lock lock2
  // NOTE: must use heavy weight monitor to handle complete_exit/reenter()
+ // NOTE(TSAN): We cannot instrument complete_exit/reenter in ObjectSynchronizer
+ //             in a manner similar to wait and waitUninterruptibly, because
+ //             (1) recursion count stored by inflated monitor is different from
+ //             the absolute recursion count tracked by Tsan, and (2) in the
+ //             general case, we cannot merely store Tsan's recursion count
+ //             once: we must track it for *each invocation* of complete_exit.
+ //             Hence, the best place to instrument for Tsan is at the call site
+ //             for complete_exit/reenter. Luckily, there is only one call site.
  intx ObjectSynchronizer::complete_exit(Handle obj, TRAPS) {
    if (UseBiasedLocking) {
      BiasedLocking::revoke(obj, THREAD);
      assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
    }

*** 643,10 ***
--- 651,11 ---
      assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
    }
    THREAD->set_current_pending_monitor_is_from_java(false);
    inflate(THREAD, obj(), inflate_cause_jni_enter)->enter(THREAD);
    THREAD->set_current_pending_monitor_is_from_java(true);
+   TSAN_RUNTIME_ONLY(SharedRuntime::tsan_oop_lock(THREAD, obj()));
  }
  
  // NOTE: must use heavy weight monitor to handle jni monitor exit
  void ObjectSynchronizer::jni_exit(oop obj, Thread* THREAD) {
    if (UseBiasedLocking) {

*** 659,10 ***
--- 668,11 ---
    ObjectMonitor* monitor = inflate(THREAD, obj, inflate_cause_jni_exit);
    // If this thread has locked the object, exit the monitor. We
    // intentionally do not use CHECK here because we must exit the
    // monitor even if an exception is pending.
    if (monitor->check_owner(THREAD)) {
+     TSAN_RUNTIME_ONLY(SharedRuntime::tsan_oop_unlock(THREAD, obj));
      monitor->exit(true, THREAD);
    }
  }
  
  // -----------------------------------------------------------------------------

*** 674,15 ***
--- 684,17 ---
    _thread->check_for_valid_safepoint_state();
    _obj = obj;
  
    if (_dolock) {
      ObjectSynchronizer::enter(_obj, &_lock, _thread);
+     TSAN_RUNTIME_ONLY(SharedRuntime::tsan_oop_lock(_thread, _obj()));
    }
  }
  
  ObjectLocker::~ObjectLocker() {
    if (_dolock) {
+     TSAN_RUNTIME_ONLY(SharedRuntime::tsan_oop_unlock(_thread, _obj()));
      ObjectSynchronizer::exit(_obj(), &_lock, _thread);
    }
  }
  
  

*** 698,12 ***
--- 710,21 ---
      THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
    }
    ObjectMonitor* monitor = inflate(THREAD, obj(), inflate_cause_wait);
  
    DTRACE_MONITOR_WAIT_PROBE(monitor, obj(), THREAD, millis);
+ 
+   TSAN_ONLY(int tsan_rec = 0;)
+   TSAN_RUNTIME_ONLY(
+     tsan_rec = SharedRuntime::tsan_oop_rec_unlock(THREAD, obj());
+     assert(tsan_rec > 0, "tsan: unlocking unlocked mutex");
+   );
+ 
    monitor->wait(millis, true, THREAD);
  
+   TSAN_RUNTIME_ONLY(SharedRuntime::tsan_oop_rec_lock(THREAD, obj(), tsan_rec));
+ 
    // This dummy call is in place to get around dtrace bug 6254741.  Once
    // that's fixed we can uncomment the following line, remove the call
    // and change this function back into a "void" func.
    // DTRACE_MONITOR_PROBE(waited, monitor, obj(), THREAD);
    return dtrace_waited_probe(monitor, obj, THREAD);

*** 715,11 ***
      assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
    }
    if (millis < 0) {
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
    }
!   inflate(THREAD, obj(), inflate_cause_wait)->wait(millis, false, THREAD);
  }
  
  void ObjectSynchronizer::notify(Handle obj, TRAPS) {
    if (UseBiasedLocking) {
      BiasedLocking::revoke(obj, THREAD);
--- 736,18 ---
      assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
    }
    if (millis < 0) {
      THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "timeout value is negative");
    }
!   ObjectMonitor* monitor = inflate(THREAD, obj(), inflate_cause_wait);
+   TSAN_ONLY(int tsan_rec;)
+   TSAN_RUNTIME_ONLY(
+     tsan_rec = SharedRuntime::tsan_oop_rec_unlock(THREAD, obj());
+     assert(tsan_rec > 0, "tsan: unlocking unlocked mutex");
+   );
+   monitor->wait(millis, false, THREAD);
+   TSAN_RUNTIME_ONLY(SharedRuntime::tsan_oop_rec_lock(THREAD, obj(), tsan_rec));
  }
  
  void ObjectSynchronizer::notify(Handle obj, TRAPS) {
    if (UseBiasedLocking) {
      BiasedLocking::revoke(obj, THREAD);

*** 2089,10 ***
--- 2117,14 ---
  
   public:
    ReleaseJavaMonitorsClosure(Thread* thread) : THREAD(thread) {}
    void do_monitor(ObjectMonitor* mid) {
      if (mid->owner() == THREAD) {
+       // Note well -- this occurs ONLY on thread exit, and is a last ditch
+       // effort to release all locks. Hence, we don't need to record tsan's
+       // recursion count -- it will never be locked again.
+       TSAN_RUNTIME_ONLY(SharedRuntime::tsan_oop_rec_unlock(THREAD, (oop)mid->object()));
        (void)mid->complete_exit(CHECK);
      }
    }
  };
  
< prev index next >