Is there any difference in using SuspendThread from a JVMTI agent and using the plain Java thread.suspend()?
In HotSpot JVM both APIs have the same effect.
I've added the links to the relevant parts of OpenJDK source code. Both functions are almost copy-paste of each other, both of them end up calling the same low-level routine JavaThread::java_suspend()
.
The native code for java.lang.Thread.suspend0()
:
JVM_ENTRY(void, JVM_SuspendThread(JNIEnv* env, jobject jthread))
JVMWrapper("JVM_SuspendThread");
ThreadsListHandle tlh(thread);
JavaThread* receiver = NULL;
bool is_alive = tlh.cv_internal_thread_to_JavaThread(jthread, &receiver, NULL);
if (is_alive) {
// jthread refers to a live JavaThread.
{
MutexLockerEx ml(receiver->SR_lock(), Mutex::_no_safepoint_check_flag);
if (receiver->is_external_suspend()) {
// Don't allow nested external suspend requests. We can't return
// an error from this interface so just ignore the problem.
return;
}
if (receiver->is_exiting()) { // thread is in the process of exiting
return;
}
receiver->set_external_suspend();
}
// java_suspend() will catch threads in the process of exiting
// and will ignore them.
receiver->java_suspend();
// It would be nice to have the following assertion in all the
// time, but it is possible for a racing resume request to have
// resumed this thread right after we suspended it. Temporarily
// enable this assertion if you are chasing a different kind of
// bug.
//
// assert(java_lang_Thread::thread(receiver->threadObj()) == NULL ||
// receiver->is_being_ext_suspended(), "thread is not suspended");
}
JVM_END
The implementation of JVM TI SuspendThread:
jvmtiError
JvmtiEnv::SuspendThread(JavaThread* java_thread) {
// don't allow hidden thread suspend request.
if (java_thread->is_hidden_from_external_view()) {
return (JVMTI_ERROR_NONE);
}
{
MutexLockerEx ml(java_thread->SR_lock(), Mutex::_no_safepoint_check_flag);
if (java_thread->is_external_suspend()) {
// don't allow nested external suspend requests.
return (JVMTI_ERROR_THREAD_SUSPENDED);
}
if (java_thread->is_exiting()) { // thread is in the process of exiting
return (JVMTI_ERROR_THREAD_NOT_ALIVE);
}
java_thread->set_external_suspend();
}
if (!JvmtiSuspendControl::suspend(java_thread)) {
// the thread was in the process of exiting
return (JVMTI_ERROR_THREAD_NOT_ALIVE);
}
return JVMTI_ERROR_NONE;
} /* end SuspendThread */
bool JvmtiSuspendControl::suspend(JavaThread *java_thread) {
// external suspend should have caught suspending a thread twice
// Immediate suspension required for JPDA back-end so JVMTI agent threads do
// not deadlock due to later suspension on transitions while holding
// raw monitors. Passing true causes the immediate suspension.
// java_suspend() will catch threads in the process of exiting
// and will ignore them.
java_thread->java_suspend();
// It would be nice to have the following assertion in all the time,
// but it is possible for a racing resume request to have resumed
// this thread right after we suspended it. Temporarily enable this
// assertion if you are chasing a different kind of bug.
//
// assert(java_lang_Thread::thread(java_thread->threadObj()) == NULL ||
// java_thread->is_being_ext_suspended(), "thread is not suspended");
...