Merge "Add raw_monitor_enter_no_suspend extension"
diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc
index 5b1a16c..c61d6e5 100644
--- a/openjdkjvmti/ti_extension.cc
+++ b/openjdkjvmti/ti_extension.cc
@@ -39,6 +39,7 @@
#include "ti_class.h"
#include "ti_ddms.h"
#include "ti_heap.h"
+#include "ti_monitor.h"
#include "thread-inl.h"
namespace openjdkjvmti {
@@ -252,6 +253,25 @@
if (error != ERR(NONE)) {
return error;
}
+
+ // Raw monitors no suspend
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(MonitorUtil::RawMonitorEnterNoSuspend),
+ "com.android.art.concurrent.raw_monitor_enter_no_suspend",
+ "Normally entering a monitor will not return until both the monitor is locked and the"
+ " current thread is not suspended. This method will return once the monitor is locked"
+ " even if the thread is suspended. Note that using rawMonitorWait will wait until the"
+ " thread is not suspended again on wakeup and so should be avoided.",
+ {
+ { "raw_monitor", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CVOID, false },
+ },
+ {
+ ERR(NULL_POINTER),
+ ERR(INVALID_MONITOR),
+ });
+ if (error != ERR(NONE)) {
+ return error;
+ }
// Copy into output buffer.
*extension_count_ptr = ext_vector.size();
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc
index 1cfc64a..6d3a37e 100644
--- a/openjdkjvmti/ti_monitor.cc
+++ b/openjdkjvmti/ti_monitor.cc
@@ -75,14 +75,16 @@
return true;
}
- void MonitorEnter(art::Thread* self) NO_THREAD_SAFETY_ANALYSIS {
+ void MonitorEnter(art::Thread* self, bool suspend) NO_THREAD_SAFETY_ANALYSIS {
// Perform a suspend-check. The spec doesn't require this but real-world agents depend on this
// behavior. We do this by performing a suspend-check then retrying if the thread is suspended
// before or after locking the internal mutex.
do {
- ThreadUtil::SuspendCheck(self);
- if (ThreadUtil::WouldSuspendForUserCode(self)) {
- continue;
+ if (suspend) {
+ ThreadUtil::SuspendCheck(self);
+ if (ThreadUtil::WouldSuspendForUserCode(self)) {
+ continue;
+ }
}
// Check for recursive enter.
@@ -100,7 +102,7 @@
// Lock with sleep. We will need to check for suspension after this to make sure that agents
// won't deadlock.
mutex_.lock();
- if (!ThreadUtil::WouldSuspendForUserCode(self)) {
+ if (!suspend || !ThreadUtil::WouldSuspendForUserCode(self)) {
break;
} else {
// We got suspended in the middle of waiting for the mutex. We should release the mutex
@@ -187,7 +189,8 @@
}
// Reaquire the mutex/monitor, also go to sleep if we were suspended.
- MonitorEnter(self);
+ // TODO Give an extension to wait without suspension as well.
+ MonitorEnter(self, /*suspend*/ true);
CHECK(owner_.load(std::memory_order_relaxed) == self);
DCHECK_EQ(1u, count_);
// Reset the count.
@@ -249,6 +252,19 @@
return ERR(NONE);
}
+jvmtiError MonitorUtil::RawMonitorEnterNoSuspend(jvmtiEnv* env ATTRIBUTE_UNUSED, jrawMonitorID id) {
+ if (id == nullptr) {
+ return ERR(INVALID_MONITOR);
+ }
+
+ JvmtiMonitor* monitor = DecodeMonitor(id);
+ art::Thread* self = art::Thread::Current();
+
+ monitor->MonitorEnter(self, /*suspend*/false);
+
+ return ERR(NONE);
+}
+
jvmtiError MonitorUtil::RawMonitorEnter(jvmtiEnv* env ATTRIBUTE_UNUSED, jrawMonitorID id) {
if (id == nullptr) {
return ERR(INVALID_MONITOR);
@@ -257,7 +273,7 @@
JvmtiMonitor* monitor = DecodeMonitor(id);
art::Thread* self = art::Thread::Current();
- monitor->MonitorEnter(self);
+ monitor->MonitorEnter(self, /*suspend*/true);
return ERR(NONE);
}
diff --git a/openjdkjvmti/ti_monitor.h b/openjdkjvmti/ti_monitor.h
index e0a865b..5c361b4 100644
--- a/openjdkjvmti/ti_monitor.h
+++ b/openjdkjvmti/ti_monitor.h
@@ -43,6 +43,8 @@
static jvmtiError DestroyRawMonitor(jvmtiEnv* env, jrawMonitorID monitor);
+ static jvmtiError RawMonitorEnterNoSuspend(jvmtiEnv* env, jrawMonitorID monitor);
+
static jvmtiError RawMonitorEnter(jvmtiEnv* env, jrawMonitorID monitor);
static jvmtiError RawMonitorExit(jvmtiEnv* env, jrawMonitorID monitor);
diff --git a/test/1951-monitor-enter-no-suspend/expected.txt b/test/1951-monitor-enter-no-suspend/expected.txt
new file mode 100644
index 0000000..3582111
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/expected.txt
@@ -0,0 +1 @@
+Success
diff --git a/test/1951-monitor-enter-no-suspend/info.txt b/test/1951-monitor-enter-no-suspend/info.txt
new file mode 100644
index 0000000..a608834
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/info.txt
@@ -0,0 +1 @@
+Tests the jvmti-extension to lock a monitor without regards to suspension.
diff --git a/test/1951-monitor-enter-no-suspend/raw_monitor.cc b/test/1951-monitor-enter-no-suspend/raw_monitor.cc
new file mode 100644
index 0000000..0425e35
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/raw_monitor.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <atomic>
+
+#include "jvmti.h"
+
+// Test infrastructure
+#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "test_env.h"
+
+namespace art {
+namespace Test1951MonitorEnterNoSuspend {
+
+typedef jvmtiError (*RawMonitorEnterNoSuspend)(jvmtiEnv* env, jrawMonitorID mon);
+
+template <typename T>
+static void Dealloc(T* t) {
+ jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(t));
+}
+
+template <typename T, typename ...Rest>
+static void Dealloc(T* t, Rest... rs) {
+ Dealloc(t);
+ Dealloc(rs...);
+}
+static void DeallocParams(jvmtiParamInfo* params, jint n_params) {
+ for (jint i = 0; i < n_params; i++) {
+ Dealloc(params[i].name);
+ }
+}
+
+RawMonitorEnterNoSuspend GetNoSuspendFunction(JNIEnv* env) {
+ // Get the extensions.
+ jint n_ext = 0;
+ jvmtiExtensionFunctionInfo* infos = nullptr;
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetExtensionFunctions(&n_ext, &infos))) {
+ return nullptr;
+ }
+ RawMonitorEnterNoSuspend result = nullptr;
+ for (jint i = 0; i < n_ext; i++) {
+ jvmtiExtensionFunctionInfo* cur_info = &infos[i];
+ if (strcmp("com.android.art.concurrent.raw_monitor_enter_no_suspend", cur_info->id) == 0) {
+ result = reinterpret_cast<RawMonitorEnterNoSuspend>(cur_info->func);
+ }
+ // Cleanup the cur_info
+ DeallocParams(cur_info->params, cur_info->param_count);
+ Dealloc(cur_info->id, cur_info->short_description, cur_info->params, cur_info->errors);
+ }
+ // Cleanup the array.
+ Dealloc(infos);
+ return result;
+}
+
+static std::atomic<bool> started(false);
+static std::atomic<bool> resumed(false);
+static std::atomic<bool> progress(false);
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1951_otherThreadStart(JNIEnv* env, jclass) {
+ jrawMonitorID mon;
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->CreateRawMonitor("test 1951", &mon))) {
+ return;
+ }
+ RawMonitorEnterNoSuspend enter_func = GetNoSuspendFunction(env);
+ if (enter_func == nullptr) {
+ return;
+ }
+ started = true;
+ while (!resumed) {}
+ jvmtiError err = enter_func(jvmti_env, mon);
+ CHECK_EQ(err, JVMTI_ERROR_NONE);
+ progress = true;
+ err = jvmti_env->RawMonitorExit(mon);
+ CHECK_EQ(err, JVMTI_ERROR_NONE);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1951_waitForStart(JNIEnv*, jclass) {
+ while (!started) {}
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Test1951_otherThreadResume(JNIEnv*, jclass) {
+ resumed = true;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_art_Test1951_otherThreadProgressed(JNIEnv*, jclass) {
+ return progress;
+}
+
+} // namespace Test1951MonitorEnterNoSuspend
+} // namespace art
diff --git a/test/1951-monitor-enter-no-suspend/run b/test/1951-monitor-enter-no-suspend/run
new file mode 100755
index 0000000..c6e62ae
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/1951-monitor-enter-no-suspend/src/Main.java b/test/1951-monitor-enter-no-suspend/src/Main.java
new file mode 100644
index 0000000..3c5e1a2
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) throws Exception {
+ art.Test1951.run();
+ }
+}
diff --git a/test/1951-monitor-enter-no-suspend/src/art/Main.java b/test/1951-monitor-enter-no-suspend/src/art/Main.java
new file mode 100644
index 0000000..aa5498b
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/src/art/Main.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+// Binder class so the agent's C code has something that can be bound and exposed to tests.
+// In a package to separate cleanly and work around CTS reference issues (though this class
+// should be replaced in the CTS version).
+public class Main {
+ // Load the given class with the given classloader, and bind all native methods to corresponding
+ // C methods in the agent. Will abort if any of the steps fail.
+ public static native void bindAgentJNI(String className, ClassLoader classLoader);
+ // Same as above, giving the class directly.
+ public static native void bindAgentJNIForClass(Class<?> klass);
+
+ // Common infrastructure.
+ public static native void setTag(Object o, long tag);
+ public static native long getTag(Object o);
+}
diff --git a/test/1951-monitor-enter-no-suspend/src/art/Suspension.java b/test/1951-monitor-enter-no-suspend/src/art/Suspension.java
new file mode 100644
index 0000000..16e62cc
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/src/art/Suspension.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+public class Suspension {
+ // Suspends a thread using jvmti.
+ public native static void suspend(Thread thr);
+
+ // Resumes a thread using jvmti.
+ public native static void resume(Thread thr);
+
+ public native static boolean isSuspended(Thread thr);
+
+ public native static int[] suspendList(Thread... threads);
+ public native static int[] resumeList(Thread... threads);
+}
diff --git a/test/1951-monitor-enter-no-suspend/src/art/Test1951.java b/test/1951-monitor-enter-no-suspend/src/art/Test1951.java
new file mode 100644
index 0000000..dc7ed9e
--- /dev/null
+++ b/test/1951-monitor-enter-no-suspend/src/art/Test1951.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package art;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Semaphore;
+
+public class Test1951 {
+
+ // Wait up to 1 minute for the other thread to make progress.
+ public static final long WAIT_TIME_MILLIS = 1000 * 60;
+ public static void run() throws Exception {
+ Thread t = new Thread(Test1951::otherThreadStart);
+ t.setDaemon(true);
+ t.start();
+ waitForStart();
+ Suspension.suspend(t);
+ otherThreadResume();
+ long endTime = System.currentTimeMillis() + WAIT_TIME_MILLIS;
+ boolean otherProgressed = false;
+ while (true) {
+ if (otherThreadProgressed()) {
+ otherProgressed = true;
+ break;
+ } else if (System.currentTimeMillis() > endTime) {
+ break;
+ } else {
+ Thread.yield();
+ }
+ }
+ Suspension.resume(t);
+ if (otherProgressed) {
+ t.join(1000);
+ }
+ if (otherProgressed) {
+ System.out.println("Success");
+ } else {
+ System.out.println(
+ "Failure: other thread did not make progress in " + WAIT_TIME_MILLIS + " ms");
+ }
+ return;
+ }
+
+ public static native void otherThreadStart();
+ public static native void waitForStart();
+ public static native void otherThreadResume();
+ public static native boolean otherThreadProgressed();
+}
diff --git a/test/Android.bp b/test/Android.bp
index 5d2ea1a..a3de382 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -289,6 +289,7 @@
"1943-suspend-raw-monitor-wait/native_suspend_monitor.cc",
"1946-list-descriptors/descriptors.cc",
"1950-unprepared-transform/unprepared_transform.cc",
+ "1951-monitor-enter-no-suspend/raw_monitor.cc",
],
// Use NDK-compatible headers for ctstiagent.
header_libs: [
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 065706c..ce4ebd7 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -968,7 +968,8 @@
"677-fsi2",
"678-quickening",
"679-locks",
- "999-redefine-hiddenapi"],
+ "999-redefine-hiddenapi",
+ "1951-monitor-enter-no-suspend"],
"variant": "jvm",
"description": ["Doesn't run on RI."]
},