src/share/vm/runtime/objectMonitor.cpp

Print this page
rev 4773 : 8005849: JEP 167: Event-Based JVM Tracing
Reviewed-by: acorn, coleenp, sla
Contributed-by: Karen Kinnear <karen.kinnear@oracle.com>, Bengt Rutisson <bengt.rutisson@oracle.com>, Calvin Cheung <calvin.cheung@oracle.com>, Erik Gahlin <erik.gahlin@oracle.com>, Erik Helin <erik.helin@oracle.com>, Jesper Wilhelmsson <jesper.wilhelmsson@oracle.com>, Keith McGuigan <keith.mcguigan@oracle.com>, Mattias Tobiasson <mattias.tobiasson@oracle.com>, Markus Gronlund <markus.gronlund@oracle.com>, Mikael Auno <mikael.auno@oracle.com>, Nils Eliasson <nils.eliasson@oracle.com>, Nils Loodin <nils.loodin@oracle.com>, Rickard Backman <rickard.backman@oracle.com>, Staffan Larsen <staffan.larsen@oracle.com>, Stefan Karlsson <stefan.karlsson@oracle.com>, Yekaterina Kantserova <yekaterina.kantserova@oracle.com>

@@ -34,11 +34,14 @@
 #include "runtime/objectMonitor.inline.hpp"
 #include "runtime/osThread.hpp"
 #include "runtime/stubRoutines.hpp"
 #include "runtime/thread.inline.hpp"
 #include "services/threadService.hpp"
+#include "trace/tracing.hpp"
+#include "trace/traceMacros.hpp"
 #include "utilities/dtrace.hpp"
+#include "utilities/macros.hpp"
 #include "utilities/preserveException.hpp"
 #ifdef TARGET_OS_FAMILY_linux
 # include "os_linux.inline.hpp"
 #endif
 #ifdef TARGET_OS_FAMILY_solaris

@@ -369,10 +372,12 @@
 
   // Prevent deflation at STW-time.  See deflate_idle_monitors() and is_busy().
   // Ensure the object-monitor relationship remains stable while there's contention.
   Atomic::inc_ptr(&_count);
 
+  EventJavaMonitorEnter event;
+
   { // Change java thread status to indicate blocked on monitor enter.
     JavaThreadBlockedOnMonitorEnterState jtbmes(jt, this);
 
     DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
     if (JvmtiExport::should_post_monitor_contended_enter()) {

@@ -400,11 +405,11 @@
       // the monitor while suspended because that would surprise the
       // thread that suspended us.
       //
           _recursions = 0 ;
       _succ = NULL ;
-      exit (Self) ;
+      exit (false, Self) ;
 
       jt->java_suspend_self();
     }
     Self->set_current_pending_monitor(NULL);
   }

@@ -433,10 +438,18 @@
 
   DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
   if (JvmtiExport::should_post_monitor_contended_entered()) {
     JvmtiExport::post_monitor_contended_entered(jt, this);
   }
+
+  if (event.should_commit()) {
+    event.set_klass(((oop)this->object())->klass());
+    event.set_previousOwner((TYPE_JAVALANGTHREAD)_previous_owner_tid);
+    event.set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr()));
+    event.commit();
+  }
+
   if (ObjectMonitor::_sync_ContendedLockAttempts != NULL) {
      ObjectMonitor::_sync_ContendedLockAttempts->inc() ;
   }
 }
 

@@ -915,11 +928,11 @@
 // any one time.  (more precisely, we want to minimize timer-seconds, which is
 // the integral of the # of active timers at any instant over time).
 // Both impinge on OS scalability.  Given that, at most one thread parked on
 // a monitor will use a timer.
 
-void ATTR ObjectMonitor::exit(TRAPS) {
+void ATTR ObjectMonitor::exit(bool not_suspended, TRAPS) {
    Thread * Self = THREAD ;
    if (THREAD != _owner) {
      if (THREAD->is_lock_owned((address) _owner)) {
        // Transmute _owner from a BasicLock pointer to a Thread address.
        // We don't need to hold _mutex for this transition.

@@ -952,10 +965,18 @@
    // a MEMBAR or other serializing instruction before fetching EntryList|cxq.
    if ((SyncFlags & 4) == 0) {
       _Responsible = NULL ;
    }
 
+#if INCLUDE_TRACE
+   // get the owner's thread id for the MonitorEnter event
+   // if it is enabled and the thread isn't suspended
+   if (not_suspended && Tracing::is_event_enabled(TraceJavaMonitorEnterEvent)) {
+     _previous_owner_tid = SharedRuntime::get_java_tid(Self);
+   }
+#endif
+
    for (;;) {
       assert (THREAD == _owner, "invariant") ;
 
 
       if (Knob_ExitPolicy == 0) {

@@ -1341,11 +1362,11 @@
    }
 
    guarantee(Self == _owner, "complete_exit not owner");
    intptr_t save = _recursions; // record the old recursion count
    _recursions = 0;        // set the recursion level to be 0
-   exit (Self) ;           // exit the monitor
+   exit (true, Self) ;           // exit the monitor
    guarantee (_owner != Self, "invariant");
    return save;
 }
 
 // reenter() enters a lock and sets recursion count

@@ -1395,10 +1416,24 @@
 static int Adjust (volatile int * adr, int dx) {
   int v ;
   for (v = *adr ; Atomic::cmpxchg (v + dx, adr, v) != v; v = *adr) ;
   return v ;
 }
+
+// helper method for posting a monitor wait event
+void ObjectMonitor::post_monitor_wait_event(EventJavaMonitorWait* event,
+                                                           jlong notifier_tid,
+                                                           jlong timeout,
+                                                           bool timedout) {
+  event->set_klass(((oop)this->object())->klass());
+  event->set_timeout((TYPE_ULONG)timeout);
+  event->set_address((TYPE_ADDRESS)(uintptr_t)(this->object_addr()));
+  event->set_notifier((TYPE_OSTHREAD)notifier_tid);
+  event->set_timedOut((TYPE_BOOLEAN)timedout);
+  event->commit();
+}
+
 // -----------------------------------------------------------------------------
 // Wait/Notify/NotifyAll
 //
 // Note: a subset of changes to ObjectMonitor::wait()
 // will need to be replicated in complete_exit above

@@ -1410,22 +1445,28 @@
    DeferredInitialize () ;
 
    // Throw IMSX or IEX.
    CHECK_OWNER();
 
+   EventJavaMonitorWait event;
+
    // check for a pending interrupt
    if (interruptible && Thread::is_interrupted(Self, true) && !HAS_PENDING_EXCEPTION) {
      // post monitor waited event.  Note that this is past-tense, we are done waiting.
      if (JvmtiExport::should_post_monitor_waited()) {
         // Note: 'false' parameter is passed here because the
         // wait was not timed out due to thread interrupt.
         JvmtiExport::post_monitor_waited(jt, this, false);
      }
+     if (event.should_commit()) {
+       post_monitor_wait_event(&event, 0, millis, false);
+     }
      TEVENT (Wait - Throw IEX) ;
      THROW(vmSymbols::java_lang_InterruptedException());
      return ;
    }
+
    TEVENT (Wait) ;
 
    assert (Self->_Stalled == 0, "invariant") ;
    Self->_Stalled = intptr_t(this) ;
    jt->set_current_waiting_monitor(this);

@@ -1453,11 +1494,11 @@
       _Responsible = NULL ;
    }
    intptr_t save = _recursions; // record the old recursion count
    _waiters++;                  // increment the number of waiters
    _recursions = 0;             // set the recursion level to be 1
-   exit (Self) ;                    // exit the monitor
+   exit (true, Self) ;                    // exit the monitor
    guarantee (_owner != Self, "invariant") ;
 
    // As soon as the ObjectMonitor's ownership is dropped in the exit()
    // call above, another thread can enter() the ObjectMonitor, do the
    // notify(), and exit() the ObjectMonitor. If the other thread's

@@ -1553,10 +1594,15 @@
 
      // post monitor waited event. Note that this is past-tense, we are done waiting.
      if (JvmtiExport::should_post_monitor_waited()) {
        JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
      }
+
+     if (event.should_commit()) {
+       post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT);
+     }
+
      OrderAccess::fence() ;
 
      assert (Self->_Stalled != 0, "invariant") ;
      Self->_Stalled = 0 ;
 

@@ -1632,10 +1678,12 @@
      guarantee (iterator->_notified == 0, "invariant") ;
      if (Policy != 4) {
         iterator->TState = ObjectWaiter::TS_ENTER ;
      }
      iterator->_notified = 1 ;
+     Thread * Self = THREAD;
+     iterator->_notifier_tid = Self->osthread()->thread_id();
 
      ObjectWaiter * List = _EntryList ;
      if (List != NULL) {
         assert (List->_prev == NULL, "invariant") ;
         assert (List->TState == ObjectWaiter::TS_ENTER, "invariant") ;

@@ -1756,10 +1804,12 @@
      // For now we use (a).
 
      guarantee (iterator->TState == ObjectWaiter::TS_WAIT, "invariant") ;
      guarantee (iterator->_notified == 0, "invariant") ;
      iterator->_notified = 1 ;
+     Thread * Self = THREAD;
+     iterator->_notifier_tid = Self->osthread()->thread_id();
      if (Policy != 4) {
         iterator->TState = ObjectWaiter::TS_ENTER ;
      }
 
      ObjectWaiter * List = _EntryList ;