diff options
20 files changed, 492 insertions, 13 deletions
diff --git a/openjdkjvmti/ti_monitor.cc b/openjdkjvmti/ti_monitor.cc index 7db0566a2e..94408ba186 100644 --- a/openjdkjvmti/ti_monitor.cc +++ b/openjdkjvmti/ti_monitor.cc @@ -169,6 +169,7 @@ class JvmtiMonitor { } size_t old_count = count_; + DCHECK_GT(old_count, 0u); count_ = 0; owner_.store(nullptr, std::memory_order_relaxed); @@ -176,12 +177,19 @@ class JvmtiMonitor { { std::unique_lock<std::mutex> lk(mutex_, std::adopt_lock); how_to_wait(lk); - lk.release(); // Do not unlock the mutex. + // Here we release the mutex. We will get it back below. We first need to do a suspend-check + // without holding it however. This is done in the MonitorEnter function. + // TODO We could do this more efficiently. + // We hold the mutex_ but the overall monitor is not owned at this point. + CHECK(owner_.load(std::memory_order_relaxed) == nullptr); + DCHECK_EQ(0u, count_); } - DCHECK(owner_.load(std::memory_order_relaxed) == nullptr); - owner_.store(self, std::memory_order_relaxed); - DCHECK_EQ(0u, count_); + // Reaquire the mutex/monitor, also go to sleep if we were suspended. + MonitorEnter(self); + CHECK(owner_.load(std::memory_order_relaxed) == self); + DCHECK_EQ(1u, count_); + // Reset the count. count_ = old_count; return true; diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 37ba9e473d..42f724ad4f 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -290,7 +290,12 @@ Runtime::~Runtime() { Thread* self = Thread::Current(); const bool attach_shutdown_thread = self == nullptr; if (attach_shutdown_thread) { - CHECK(AttachCurrentThread("Shutdown thread", false, nullptr, false)); + // We can only create a peer if the runtime is actually started. This is only not true during + // some tests. + CHECK(AttachCurrentThread("Shutdown thread", + false, + GetSystemThreadGroup(), + /* Create peer */IsStarted())); self = Thread::Current(); } else { LOG(WARNING) << "Current thread not detached in Runtime shutdown"; diff --git a/test/1942-suspend-raw-monitor-exit/expected.txt b/test/1942-suspend-raw-monitor-exit/expected.txt new file mode 100644 index 0000000000..182e197c05 --- /dev/null +++ b/test/1942-suspend-raw-monitor-exit/expected.txt @@ -0,0 +1,11 @@ +Initial state. +isLocked() = true +isSuspended(target_thread) = false +Suspend and sleep. +isLocked() = true +isSuspended(target_thread) = true +Let other thread release the raw monitor. +isLocked() = false +isSuspended(target_thread) = true +other thread doesn't hold lock! +resumed test thread diff --git a/test/1942-suspend-raw-monitor-exit/info.txt b/test/1942-suspend-raw-monitor-exit/info.txt new file mode 100644 index 0000000000..f608e0685a --- /dev/null +++ b/test/1942-suspend-raw-monitor-exit/info.txt @@ -0,0 +1,3 @@ +Tests jvmti suspending of a thread that is interacting with a raw monitor. + +Makes sure that the RawMonitorExit function does not act as a suspend point. diff --git a/test/1942-suspend-raw-monitor-exit/native_suspend_monitor.cc b/test/1942-suspend-raw-monitor-exit/native_suspend_monitor.cc new file mode 100644 index 0000000000..b182ad0ecb --- /dev/null +++ b/test/1942-suspend-raw-monitor-exit/native_suspend_monitor.cc @@ -0,0 +1,80 @@ +/* + * 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. + */ + +#include <atomic> + +#include "android-base/logging.h" +#include "jni.h" +#include "scoped_local_ref.h" +#include "scoped_primitive_array.h" + +#include "jvmti.h" + +// Test infrastructure +#include "jvmti_helper.h" +#include "test_env.h" + +namespace art { +namespace Test1942SuspendRawMonitorExit { + +jrawMonitorID mon; +std::atomic<bool> should_pause(true); +std::atomic<bool> paused(false); +std::atomic<bool> done(false); +std::atomic<bool> locked(false); + +extern "C" JNIEXPORT void JNICALL Java_art_Test1942_nativeRun(JNIEnv* env, jclass) { + if (JvmtiErrorToException( + env, jvmti_env, jvmti_env->CreateRawMonitor("Test1942 monitor", &mon))) { + return; + } + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) { + return; + } + locked.store(true); + while (should_pause.load()) { + paused.store(true); + } + paused.store(false); + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) { + return; + } + locked.store(false); +} + +extern "C" JNIEXPORT jboolean JNICALL Java_art_Test1942_isLocked(JNIEnv*, jclass) { + return locked.load(); +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1942_waitForPause(JNIEnv*, jclass) { + while (!paused.load()) { } +} +extern "C" JNIEXPORT void JNICALL Java_art_Test1942_resume(JNIEnv*, jclass) { + should_pause.store(false); + while (paused.load()) { } +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1942_grabRawMonitor(JNIEnv* env, jclass) { + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) { + return; + } + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) { + return; + } +} + +} // namespace Test1942SuspendRawMonitorExit +} // namespace art diff --git a/test/1942-suspend-raw-monitor-exit/run b/test/1942-suspend-raw-monitor-exit/run new file mode 100755 index 0000000000..e92b873956 --- /dev/null +++ b/test/1942-suspend-raw-monitor-exit/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/1942-suspend-raw-monitor-exit/src/Main.java b/test/1942-suspend-raw-monitor-exit/src/Main.java new file mode 100644 index 0000000000..0f75bc62d4 --- /dev/null +++ b/test/1942-suspend-raw-monitor-exit/src/Main.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1942.run(); + } +} diff --git a/test/1942-suspend-raw-monitor-exit/src/art/Suspension.java b/test/1942-suspend-raw-monitor-exit/src/art/Suspension.java new file mode 100644 index 0000000000..16e62ccac9 --- /dev/null +++ b/test/1942-suspend-raw-monitor-exit/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/1942-suspend-raw-monitor-exit/src/art/Test1942.java b/test/1942-suspend-raw-monitor-exit/src/art/Test1942.java new file mode 100644 index 0000000000..eaf756067b --- /dev/null +++ b/test/1942-suspend-raw-monitor-exit/src/art/Test1942.java @@ -0,0 +1,73 @@ +/* + * 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 Test1942 { + public static void run() throws Exception { + final Thread target_thread = new Thread(() -> { + nativeRun(); + }, "target_thread"); + + target_thread.start(); + + // wait for the other thread to spin holding lock. + waitForPause(); + + System.out.println("Initial state."); + System.out.println("isLocked() = " + isLocked()); + System.out.println("isSuspended(target_thread) = " + Suspension.isSuspended(target_thread)); + + // Suspend it from java. + System.out.println("Suspend and sleep."); + Suspension.suspend(target_thread); + // Wait for the other thread to do something. + try { Thread.sleep(1000); } catch (Exception e) {} + + System.out.println("isLocked() = " + isLocked()); + System.out.println("isSuspended(target_thread) = " + Suspension.isSuspended(target_thread)); + + // Let it try to unlock the monitor. + System.out.println("Let other thread release the raw monitor."); + // Let the thread try to lock the monitor. + resume(); + + // Wait for the other thread to do something. It should exit by the time this is done if it + // has not hit a suspend point. + while (isLocked()) { + try { Thread.sleep(1000); } catch (Exception e) {} + } + + System.out.println("isLocked() = " + isLocked()); + System.out.println("isSuspended(target_thread) = " + Suspension.isSuspended(target_thread)); + + // Make sure the monitor is gone. + grabRawMonitor(); + System.out.println("other thread doesn't hold lock!"); + + // Resume it from java + System.out.println("resumed test thread"); + Suspension.resume(target_thread); + target_thread.join(); + } + + public static native void nativeRun(); + public static native void waitForPause(); + public static native void resume(); + public static native boolean isLocked(); + // Gets then releases raw monitor. + public static native void grabRawMonitor(); +} diff --git a/test/1943-suspend-raw-monitor-wait/expected.txt b/test/1943-suspend-raw-monitor-wait/expected.txt new file mode 100644 index 0000000000..9bb1ca37d0 --- /dev/null +++ b/test/1943-suspend-raw-monitor-wait/expected.txt @@ -0,0 +1,7 @@ +target_thread is sleeping in a wait. +Suspend target_thread. +Wake up the target_thread. +target_thread is sleeping in suspend without lock. +target_thread.isAlive() = true +resumed target_thread +target_thread doesn't hold lock! diff --git a/test/1943-suspend-raw-monitor-wait/info.txt b/test/1943-suspend-raw-monitor-wait/info.txt new file mode 100644 index 0000000000..1d716e11d1 --- /dev/null +++ b/test/1943-suspend-raw-monitor-wait/info.txt @@ -0,0 +1,4 @@ +Tests jvmti suspending of a thread that is interacting with a raw monitor. + +Makes sure that the RawMonitorWait function acts as a suspend point as the +thread leaves the function. diff --git a/test/1943-suspend-raw-monitor-wait/native_suspend_monitor.cc b/test/1943-suspend-raw-monitor-wait/native_suspend_monitor.cc new file mode 100644 index 0000000000..fdfc3c63fc --- /dev/null +++ b/test/1943-suspend-raw-monitor-wait/native_suspend_monitor.cc @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#include <atomic> + +#include "android-base/logging.h" +#include "jni.h" +#include "scoped_local_ref.h" +#include "scoped_primitive_array.h" + +#include "jvmti.h" + +// Test infrastructure +#include "jvmti_helper.h" +#include "test_env.h" + +namespace art { +namespace Test1943SuspendRawMonitorExit { + +jrawMonitorID mon; +std::atomic<bool> locked(false); + +extern "C" JNIEXPORT void JNICALL Java_art_Test1943_nativeRun(JNIEnv* env, jclass) { + if (JvmtiErrorToException( + env, jvmti_env, jvmti_env->CreateRawMonitor("Test1943 monitor", &mon))) { + return; + } + // Grab the monitor twice + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) { + return; + } + locked.store(true); + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorWait(mon, 0))) { + return; + } + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) { + return; + } + locked.store(false); +} + + +extern "C" JNIEXPORT void JNICALL Java_art_Test1943_waitForPause(JNIEnv*, jclass) { + while (!locked.load()) { } +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1943_nativeNotify(JNIEnv* env, jclass) { + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) { + return; + } + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorNotifyAll(mon))) { + return; + } + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) { + return; + } +} + +extern "C" JNIEXPORT void JNICALL Java_art_Test1943_grabRawMonitor(JNIEnv* env, jclass) { + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(mon))) { + return; + } + if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(mon))) { + return; + } +} + +} // namespace Test1943SuspendRawMonitorExit +} // namespace art diff --git a/test/1943-suspend-raw-monitor-wait/run b/test/1943-suspend-raw-monitor-wait/run new file mode 100755 index 0000000000..e92b873956 --- /dev/null +++ b/test/1943-suspend-raw-monitor-wait/run @@ -0,0 +1,17 @@ +#!/bin/bash +# +# Copyright 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. + +./default-run "$@" --jvmti diff --git a/test/1943-suspend-raw-monitor-wait/src/Main.java b/test/1943-suspend-raw-monitor-wait/src/Main.java new file mode 100644 index 0000000000..b95905339f --- /dev/null +++ b/test/1943-suspend-raw-monitor-wait/src/Main.java @@ -0,0 +1,21 @@ +/* + * 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. + */ + +public class Main { + public static void main(String[] args) throws Exception { + art.Test1943.run(); + } +} diff --git a/test/1943-suspend-raw-monitor-wait/src/art/Suspension.java b/test/1943-suspend-raw-monitor-wait/src/art/Suspension.java new file mode 100644 index 0000000000..16e62ccac9 --- /dev/null +++ b/test/1943-suspend-raw-monitor-wait/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/1943-suspend-raw-monitor-wait/src/art/Test1943.java b/test/1943-suspend-raw-monitor-wait/src/art/Test1943.java new file mode 100644 index 0000000000..4be68f3d71 --- /dev/null +++ b/test/1943-suspend-raw-monitor-wait/src/art/Test1943.java @@ -0,0 +1,66 @@ +/* + * 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 Test1943 { + public static void run() throws Exception { + final Thread target_thread = new Thread(() -> { + nativeRun(); + }, "target_thread"); + + target_thread.start(); + + // wait for the other thread to spin holding lock. + waitForPause(); + + // Ensure that the other thread is in a wait. + grabRawMonitor(); + System.out.println("target_thread is sleeping in a wait."); + + // Suspend it from java. + System.out.println("Suspend target_thread."); + Suspension.suspend(target_thread); + + // Let it try to unlock the monitor. + System.out.println("Wake up the target_thread."); + // Let the thread try to lock the monitor. + nativeNotify(); + + // Ensure that the other thread is suspended without the monitor. + grabRawMonitor(); + System.out.println("target_thread is sleeping in suspend without lock."); + + // Check other thread is still alive + System.out.println("target_thread.isAlive() = " + target_thread.isAlive()); + + // Resume it from java + System.out.println("resumed target_thread"); + Suspension.resume(target_thread); + + // Make sure the monitor is gone. + grabRawMonitor(); + System.out.println("target_thread doesn't hold lock!"); + + target_thread.join(); + } + + public static native void nativeRun(); + public static native void waitForPause(); + public static native void nativeNotify(); + // Gets then releases raw monitor. + public static native void grabRawMonitor(); +} diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc index 472f2b768e..43a1d8319f 100644 --- a/test/901-hello-ti-agent/basics.cc +++ b/test/901-hello-ti-agent/basics.cc @@ -56,9 +56,13 @@ static void JNICALL VMInitCallback(jvmtiEnv *jvmti_env, fsync(1); } -static void JNICALL VMDeatchCallback(jvmtiEnv *jenv, JNIEnv* jni_env ATTRIBUTE_UNUSED) { +static void JNICALL VMDeathCallback(jvmtiEnv *jenv, JNIEnv* jni_env) { printf("VMDeath (phase %d)\n", getPhase(jenv)); fsync(1); + jthread cur_thr; + CHECK_EQ(jenv->GetCurrentThread(&cur_thr), JVMTI_ERROR_NONE); + CHECK(cur_thr != nullptr); + jni_env->DeleteLocalRef(cur_thr); } @@ -67,7 +71,7 @@ static void InstallVMEvents(jvmtiEnv* env) { memset(&callbacks, 0, sizeof(jvmtiEventCallbacks)); callbacks.VMStart = VMStartCallback; callbacks.VMInit = VMInitCallback; - callbacks.VMDeath = VMDeatchCallback; + callbacks.VMDeath = VMDeathCallback; jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks)); if (ret != JVMTI_ERROR_NONE) { printf("Failed to install callbacks"); diff --git a/test/980-redefine-object/expected.txt b/test/980-redefine-object/expected.txt index 4c294bc870..0a80882de1 100644 --- a/test/980-redefine-object/expected.txt +++ b/test/980-redefine-object/expected.txt @@ -30,3 +30,7 @@ Object allocated of type 'java.util.LinkedList$Node' Object allocated of type 'java.lang.Exception' Exception caught. Finishing test! +Object allocated of type 'java.lang.Thread' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.lang.Object' +Object allocated of type 'java.security.AccessControlContext' diff --git a/test/Android.bp b/test/Android.bp index 01e424d5e3..f5ca2f0338 100644 --- a/test/Android.bp +++ b/test/Android.bp @@ -260,6 +260,8 @@ art_cc_defaults { "1934-jvmti-signal-thread/signal_threads.cc", "1939-proxy-frames/local_instance.cc", "1941-dispose-stress/dispose_stress.cc", + "1942-suspend-raw-monitor-exit/native_suspend_monitor.cc", + "1943-suspend-raw-monitor-wait/native_suspend_monitor.cc", ], shared_libs: [ "libbase", diff --git a/tools/external_oj_libjdwp_art_failures.txt b/tools/external_oj_libjdwp_art_failures.txt index ce1160eb50..c96830a592 100644 --- a/tools/external_oj_libjdwp_art_failures.txt +++ b/tools/external_oj_libjdwp_art_failures.txt @@ -24,12 +24,6 @@ bug: 66905894, name: "org.apache.harmony.jpda.tests.jdwp.ReferenceType.GetValues006Test#testGetValues006" }, -{ - description: "Test fails with Error VM_DEAD when trying to resume during VM_DEATH event", - result: EXEC_FAILED, - bug: 66904725, - name: "org.apache.harmony.jpda.tests.jdwp.Events.VMDeath002Test#testVMDeathRequest" -}, /* TODO Categorize these failures more. */ { description: "Tests that fail on both ART and RI. These tests are likely incorrect", |