Add support for JVMTI monitor events.
Adds support for the JVMTI can_generate_monitor_events capability and
all associated events. This adds support for the
JVMTI_EVENT_MONITOR_WAIT, JVMTI_EVENT_MONITOR_WAITED,
JVMTI_EVENT_MONITOR_CONTENDED_ENTER, and
JVMTI_EVENT_MONITOR_CONTENDED_ENTERED events.
Bug: 65558434
Bug: 62821960
Bug: 34415266
Test: ./test.py --host -j50
Change-Id: I0fe8038e6c4249e77d37a67e5056b5d2a94b6f48
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index ac2ed9e..ef17258 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -22,6 +22,7 @@
#include <initializer_list>
#include <memory>
+#include <mutex>
#include <string>
#include "jni.h"
@@ -29,12 +30,14 @@
#include "art_method-inl.h"
#include "base/mutex.h"
#include "class_linker.h"
+#include "class_reference.h"
#include "common_runtime_test.h"
#include "handle.h"
#include "handle_scope-inl.h"
#include "mem_map.h"
#include "mirror/class-inl.h"
#include "mirror/class_loader.h"
+#include "monitor.h"
#include "nativehelper/ScopedLocalRef.h"
#include "obj_ptr.h"
#include "runtime.h"
@@ -433,4 +436,87 @@
ASSERT_EQ(1u, cb_.death_seen);
}
+class MonitorWaitCallbacksTest : public RuntimeCallbacksTest {
+ protected:
+ void AddListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
+ Runtime::Current()->GetRuntimeCallbacks()->AddMonitorCallback(&cb_);
+ }
+ void RemoveListener() OVERRIDE REQUIRES(Locks::mutator_lock_) {
+ Runtime::Current()->GetRuntimeCallbacks()->RemoveMonitorCallback(&cb_);
+ }
+
+ struct Callback : public MonitorCallback {
+ bool IsInterestingObject(mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ if (!obj->IsClass()) {
+ return false;
+ }
+ std::lock_guard<std::mutex> lock(ref_guard_);
+ mirror::Class* k = obj->AsClass();
+ ClassReference test = { &k->GetDexFile(), k->GetDexClassDefIndex() };
+ return ref_ == test;
+ }
+
+ void SetInterestingObject(mirror::Object* obj) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+ std::lock_guard<std::mutex> lock(ref_guard_);
+ mirror::Class* k = obj->AsClass();
+ ref_ = { &k->GetDexFile(), k->GetDexClassDefIndex() };
+ }
+
+ void MonitorContendedLocking(Monitor* mon ATTRIBUTE_UNUSED)
+ REQUIRES_SHARED(Locks::mutator_lock_) { }
+
+ void MonitorContendedLocked(Monitor* mon ATTRIBUTE_UNUSED)
+ REQUIRES_SHARED(Locks::mutator_lock_) { }
+
+ void ObjectWaitStart(Handle<mirror::Object> obj, int64_t millis ATTRIBUTE_UNUSED)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (IsInterestingObject(obj.Get())) {
+ saw_wait_start_ = true;
+ }
+ }
+
+ void MonitorWaitFinished(Monitor* m, bool timed_out ATTRIBUTE_UNUSED)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (IsInterestingObject(m->GetObject())) {
+ saw_wait_finished_ = true;
+ }
+ }
+
+ std::mutex ref_guard_;
+ ClassReference ref_ = {nullptr, 0};
+ bool saw_wait_start_ = false;
+ bool saw_wait_finished_ = false;
+ };
+
+ Callback cb_;
+};
+
+// TODO It would be good to have more tests for this but due to the multi-threaded nature of the
+// callbacks this is difficult. For now the run-tests 1931 & 1932 should be sufficient.
+TEST_F(MonitorWaitCallbacksTest, WaitUnlocked) {
+ ASSERT_FALSE(cb_.saw_wait_finished_);
+ ASSERT_FALSE(cb_.saw_wait_start_);
+ {
+ Thread* self = Thread::Current();
+ self->TransitionFromSuspendedToRunnable();
+ bool started = runtime_->Start();
+ ASSERT_TRUE(started);
+ {
+ ScopedObjectAccess soa(self);
+ cb_.SetInterestingObject(
+ soa.Decode<mirror::Class>(WellKnownClasses::java_util_Collections).Ptr());
+ Monitor::Wait(
+ self,
+ // Just a random class
+ soa.Decode<mirror::Class>(WellKnownClasses::java_util_Collections).Ptr(),
+ /*ms*/0,
+ /*ns*/0,
+ /*interruptShouldThrow*/false,
+ /*why*/kWaiting);
+ }
+ }
+ ASSERT_TRUE(cb_.saw_wait_start_);
+ ASSERT_FALSE(cb_.saw_wait_finished_);
+}
+
} // namespace art