--- a/src/hotspot/share/prims/jvmtiEnv.cpp Wed Nov 22 14:31:48 2017 -0500
+++ b/src/hotspot/share/prims/jvmtiEnv.cpp Wed Nov 22 17:54:50 2017 -0800
@@ -62,6 +62,7 @@
#include "runtime/reflectionUtils.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.inline.hpp"
+#include "runtime/threadSMR.hpp"
#include "runtime/timerTrace.hpp"
#include "runtime/vframe.hpp"
#include "runtime/vmThread.hpp"
@@ -162,7 +163,6 @@
*data_ptr = (state == NULL) ? NULL :
state->env_thread_state(this)->get_agent_thread_local_storage_data();
} else {
-
// jvmti_GetThreadLocalStorage is "in native" and doesn't transition
// the thread to _thread_in_vm. However, when the TLS for a thread
// other than the current thread is required we need to transition
@@ -172,17 +172,13 @@
VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread)
debug_only(VMNativeEntryWrapper __vew;)
- oop thread_oop = JNIHandles::resolve_external_guard(thread);
- if (thread_oop == NULL) {
- return JVMTI_ERROR_INVALID_THREAD;
+ JavaThread* java_thread = NULL;
+ ThreadsListHandle tlh(current_thread);
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
+ if (err != JVMTI_ERROR_NONE) {
+ return err;
}
- if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
- return JVMTI_ERROR_INVALID_THREAD;
- }
- JavaThread* java_thread = java_lang_Thread::thread(thread_oop);
- if (java_thread == NULL) {
- return JVMTI_ERROR_THREAD_NOT_ALIVE;
- }
+
JvmtiThreadState* state = java_thread->jvmti_thread_state();
*data_ptr = (state == NULL) ? NULL :
state->env_thread_state(this)->get_agent_thread_local_storage_data();
@@ -518,43 +514,61 @@
// event_thread - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, jthread event_thread, ...) {
- JavaThread* java_thread = NULL;
- if (event_thread != NULL) {
- oop thread_oop = JNIHandles::resolve_external_guard(event_thread);
- if (thread_oop == NULL) {
- return JVMTI_ERROR_INVALID_THREAD;
+ if (event_thread == NULL) {
+ // Can be called at Agent_OnLoad() time with event_thread == NULL
+ // when Thread::current() does not work yet so we cannot create a
+ // ThreadsListHandle that is common to both thread-specific and
+ // global code paths.
+
+ // event_type must be valid
+ if (!JvmtiEventController::is_valid_event_type(event_type)) {
+ return JVMTI_ERROR_INVALID_EVENT_TYPE;
+ }
+
+ bool enabled = (mode == JVMTI_ENABLE);
+
+ // assure that needed capabilities are present
+ if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
+ return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+ }
+
+ if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
+ record_class_file_load_hook_enabled();
}
- if (!thread_oop->is_a(SystemDictionary::Thread_klass())) {
- return JVMTI_ERROR_INVALID_THREAD;
+ JvmtiEventController::set_user_enabled(this, (JavaThread*) NULL, event_type, enabled);
+ } else {
+ // We have a specified event_thread.
+
+ JavaThread* java_thread = NULL;
+ ThreadsListHandle tlh;
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), event_thread, &java_thread, NULL);
+ if (err != JVMTI_ERROR_NONE) {
+ return err;
+ }
+
+ // event_type must be valid
+ if (!JvmtiEventController::is_valid_event_type(event_type)) {
+ return JVMTI_ERROR_INVALID_EVENT_TYPE;
}
- java_thread = java_lang_Thread::thread(thread_oop);
- if (java_thread == NULL) {
- return JVMTI_ERROR_THREAD_NOT_ALIVE;
+
+ // global events cannot be controlled at thread level.
+ if (JvmtiEventController::is_global_event(event_type)) {
+ return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}
+
+ bool enabled = (mode == JVMTI_ENABLE);
+
+ // assure that needed capabilities are present
+ if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
+ return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
+ }
+
+ if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
+ record_class_file_load_hook_enabled();
+ }
+ JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
}
- // event_type must be valid
- if (!JvmtiEventController::is_valid_event_type(event_type)) {
- return JVMTI_ERROR_INVALID_EVENT_TYPE;
- }
-
- // global events cannot be controlled at thread level.
- if (java_thread != NULL && JvmtiEventController::is_global_event(event_type)) {
- return JVMTI_ERROR_ILLEGAL_ARGUMENT;
- }
-
- bool enabled = (mode == JVMTI_ENABLE);
-
- // assure that needed capabilities are present
- if (enabled && !JvmtiUtil::has_event_capability(event_type, get_capabilities())) {
- return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
- }
-
- if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) {
- record_class_file_load_hook_enabled();
- }
- JvmtiEventController::set_user_enabled(this, java_thread, event_type, enabled);
-
return JVMTI_ERROR_NONE;
} /* end SetEventNotificationMode */
@@ -817,35 +831,45 @@
// thread_state_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) {
- jint state;
- oop thread_oop;
- JavaThread* thr;
+ JavaThread* current_thread = JavaThread::current();
+ JavaThread* java_thread = NULL;
+ oop thread_oop = NULL;
+ ThreadsListHandle tlh(current_thread);
if (thread == NULL) {
- thread_oop = JavaThread::current()->threadObj();
+ java_thread = current_thread;
+ thread_oop = java_thread->threadObj();
+
+ if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
+ return JVMTI_ERROR_INVALID_THREAD;
+ }
} else {
- thread_oop = JNIHandles::resolve_external_guard(thread);
- }
-
- if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
- return JVMTI_ERROR_INVALID_THREAD;
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+ if (err != JVMTI_ERROR_NONE) {
+ // We got an error code so we don't have a JavaThread *, but
+ // only return an error from here if we didn't get a valid
+ // thread_oop.
+ if (thread_oop == NULL) {
+ return err;
+ }
+ // We have a valid thread_oop so we can return some thread state.
+ }
}
// get most state bits
- state = (jint)java_lang_Thread::get_thread_status(thread_oop);
-
- // add more state bits
- thr = java_lang_Thread::thread(thread_oop);
- if (thr != NULL) {
- JavaThreadState jts = thr->thread_state();
-
- if (thr->is_being_ext_suspended()) {
+ jint state = (jint)java_lang_Thread::get_thread_status(thread_oop);
+
+ if (java_thread != NULL) {
+ // We have a JavaThread* so add more state bits.
+ JavaThreadState jts = java_thread->thread_state();
+
+ if (java_thread->is_being_ext_suspended()) {
state |= JVMTI_THREAD_STATE_SUSPENDED;
}
if (jts == _thread_in_native) {
state |= JVMTI_THREAD_STATE_IN_NATIVE;
}
- OSThread* osThread = thr->osthread();
+ OSThread* osThread = java_thread->osthread();
if (osThread != NULL && osThread->interrupted()) {
state |= JVMTI_THREAD_STATE_INTERRUPTED;
}
@@ -891,7 +915,6 @@
thread_objs[i] = Handle(tle.get_threadObj(i));
}
- // have to make global handles outside of Threads_lock
jthread *jthreads = new_jthreadArray(nthreads, thread_objs);
NULL_CHECK(jthreads, JVMTI_ERROR_OUT_OF_MEMORY);
@@ -935,19 +958,12 @@
jvmtiError
JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
int needSafepoint = 0; // > 0 if we need a safepoint
+ ThreadsListHandle tlh;
for (int i = 0; i < request_count; i++) {
- JavaThread *java_thread = get_JavaThread(request_list[i]);
- if (java_thread == NULL) {
- results[i] = JVMTI_ERROR_INVALID_THREAD;
- continue;
- }
- // the thread has not yet run or has exited (not on threads list)
- if (java_thread->threadObj() == NULL) {
- results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
- continue;
- }
- if (java_lang_Thread::thread(java_thread->threadObj()) == NULL) {
- results[i] = JVMTI_ERROR_THREAD_NOT_ALIVE;
+ JavaThread *java_thread = NULL;
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
+ if (err != JVMTI_ERROR_NONE) {
+ results[i] = err;
continue;
}
// don't allow hidden thread suspend request.
@@ -1018,10 +1034,12 @@
// results - pre-checked for NULL
jvmtiError
JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmtiError* results) {
+ ThreadsListHandle tlh;
for (int i = 0; i < request_count; i++) {
- JavaThread *java_thread = get_JavaThread(request_list[i]);
- if (java_thread == NULL) {
- results[i] = JVMTI_ERROR_INVALID_THREAD;
+ JavaThread* java_thread = NULL;
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), request_list[i], &java_thread, NULL);
+ if (err != JVMTI_ERROR_NONE) {
+ results[i] = err;
continue;
}
// don't allow hidden thread resume request.
@@ -1039,7 +1057,7 @@
continue;
}
- results[i] = JVMTI_ERROR_NONE; // indicate successful suspend
+ results[i] = JVMTI_ERROR_NONE; // indicate successful resume
}
// per-thread resume results returned via results parameter
return JVMTI_ERROR_NONE;
@@ -1064,20 +1082,14 @@
// thread - NOT pre-checked
jvmtiError
JvmtiEnv::InterruptThread(jthread thread) {
- oop thread_oop = JNIHandles::resolve_external_guard(thread);
- if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
- return JVMTI_ERROR_INVALID_THREAD;
-
+ // TODO: this is very similar to JVM_Interrupt(); share code in future
JavaThread* current_thread = JavaThread::current();
-
- // Todo: this is a duplicate of JVM_Interrupt; share code in future
- // Ensure that the C++ Thread and OSThread structures aren't freed before we operate
- MutexLockerEx ml(current_thread->threadObj() == thread_oop ? NULL : Threads_lock);
- // We need to re-resolve the java_thread, since a GC might have happened during the
- // acquire of the lock
-
- JavaThread* java_thread = java_lang_Thread::thread(JNIHandles::resolve_external_guard(thread));
- NULL_CHECK(java_thread, JVMTI_ERROR_THREAD_NOT_ALIVE);
+ JavaThread* java_thread = NULL;
+ ThreadsListHandle tlh(current_thread);
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, NULL);
+ if (err != JVMTI_ERROR_NONE) {
+ return err;
+ }
Thread::interrupt(java_thread);
@@ -1094,16 +1106,28 @@
HandleMark hm;
JavaThread* current_thread = JavaThread::current();
+ ThreadsListHandle tlh(current_thread);
// if thread is NULL the current thread is used
- oop thread_oop;
+ oop thread_oop = NULL;
if (thread == NULL) {
thread_oop = current_thread->threadObj();
+ if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
+ return JVMTI_ERROR_INVALID_THREAD;
+ }
} else {
- thread_oop = JNIHandles::resolve_external_guard(thread);
+ JavaThread* java_thread = NULL;
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+ if (err != JVMTI_ERROR_NONE) {
+ // We got an error code so we don't have a JavaThread *, but
+ // only return an error from here if we didn't get a valid
+ // thread_oop.
+ if (thread_oop == NULL) {
+ return err;
+ }
+ // We have a valid thread_oop so we can return some thread info.
+ }
}
- if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass()))
- return JVMTI_ERROR_INVALID_THREAD;
Handle thread_obj(current_thread, thread_oop);
Handle name;
@@ -1272,17 +1296,31 @@
// arg - NULL is a valid value, must be checked
jvmtiError
JvmtiEnv::RunAgentThread(jthread thread, jvmtiStartFunction proc, const void* arg, jint priority) {
- oop thread_oop = JNIHandles::resolve_external_guard(thread);
- if (thread_oop == NULL || !thread_oop->is_a(SystemDictionary::Thread_klass())) {
+ JavaThread* current_thread = JavaThread::current();
+
+ JavaThread* java_thread = NULL;
+ oop thread_oop = NULL;
+ ThreadsListHandle tlh(current_thread);
+ jvmtiError err = JvmtiExport::cv_external_thread_to_JavaThread(tlh.list(), thread, &java_thread, &thread_oop);
+ if (err != JVMTI_ERROR_NONE) {
+ // We got an error code so we don't have a JavaThread *, but
+ // only return an error from here if we didn't get a valid
+ // thread_oop.
+ if (thread_oop == NULL) {
+ return err;
+ }
+ // We have a valid thread_oop.
+ }
+
+ if (java_thread != NULL) {
+ // 'thread' refers to an existing JavaThread.
return JVMTI_ERROR_INVALID_THREAD;
}
+
if (priority < JVMTI_THREAD_MIN_PRIORITY || priority > JVMTI_THREAD_MAX_PRIORITY) {
return JVMTI_ERROR_INVALID_PRIORITY;
}
- //Thread-self
- JavaThread* current_thread = JavaThread::current();
-
Handle thread_hndl(current_thread, thread_oop);
{
MutexLocker mu(Threads_lock); // grab Threads_lock
@@ -1292,7 +1330,9 @@
// At this point it may be possible that no osthread was created for the
// JavaThread due to lack of memory.
if (new_thread == NULL || new_thread->osthread() == NULL) {
- if (new_thread) delete new_thread;
+ if (new_thread != NULL) {
+ new_thread->smr_delete();
+ }
return JVMTI_ERROR_OUT_OF_MEMORY;
}
@@ -1394,36 +1434,53 @@
int ngroups = 0;
int hidden_threads = 0;
- ResourceMark rm;
- HandleMark hm;
+ ResourceMark rm(current_thread);
+ HandleMark hm(current_thread);
Handle group_hdl(current_thread, group_obj);
- { MutexLocker mu(Threads_lock);
+ { // Cannot allow thread or group counts to change.
+ MutexLocker mu(Threads_lock);
nthreads = java_lang_ThreadGroup::nthreads(group_hdl());
ngroups = java_lang_ThreadGroup::ngroups(group_hdl());
if (nthreads > 0) {
+ ThreadsListHandle tlh(current_thread);
objArrayOop threads = java_lang_ThreadGroup::threads(group_hdl());
assert(nthreads <= threads->length(), "too many threads");
thread_objs = NEW_RESOURCE_ARRAY(Handle,nthreads);
for (int i=0, j=0; i<nthreads; i++) {
oop thread_obj = threads->obj_at(i);
assert(thread_obj != NULL, "thread_obj is NULL");
- JavaThread *javathread = java_lang_Thread::thread(thread_obj);
- // Filter out hidden java threads.
- if (javathread != NULL && javathread->is_hidden_from_external_view()) {
- hidden_threads++;
- continue;
+ JavaThread *java_thread = NULL;
+ jvmtiError err = JvmtiExport::cv_oop_to_JavaThread(tlh.list(), thread_obj, &java_thread);
+ if (err == JVMTI_ERROR_NONE) {
+ // Have a valid JavaThread*.
+ if (java_thread->is_hidden_from_external_view()) {
+ // Filter out hidden java threads.
+ hidden_threads++;
+ continue;
+ }
+ } else {
+ // We couldn't convert thread_obj into a JavaThread*.
+ if (err == JVMTI_ERROR_INVALID_THREAD) {
+ // The thread_obj does not refer to a java.lang.Thread object
+ // so skip it.
+ hidden_threads++;
+ continue;
+ }
+ // We have a valid thread_obj, but no JavaThread*; the caller
+ // can still have limited use for the thread_obj.
}
thread_objs[j++] = Handle(current_thread, thread_obj);
}
nthreads -= hidden_threads;
- }
+ } // ThreadsListHandle is destroyed here.
+
if (ngroups > 0) {
objArrayOop groups = java_lang_ThreadGroup::groups(group_hdl());
- assert(ngroups <= groups->length(), "too many threads");
+ assert(ngroups <= groups->length(), "too many groups");
group_objs = NEW_RESOURCE_ARRAY(Handle,ngroups);
for (int i=0; i<ngroups; i++) {
oop group_obj = groups->obj_at(i);
@@ -1556,7 +1613,7 @@
}
// Check if java_thread is fully suspended
- if (!is_thread_fully_suspended(java_thread, true /* wait for suspend completion */, &debug_bits)) {
+ if (!java_thread->is_thread_fully_suspended(true /* wait for suspend completion */, &debug_bits)) {
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}
// Check to see if a PopFrame was already in progress
@@ -1686,8 +1743,8 @@
return JVMTI_ERROR_THREAD_NOT_ALIVE;
}
- if (!JvmtiEnv::is_thread_fully_suspended(java_thread, true, &debug_bits)) {
- return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
+ if (!java_thread->is_thread_fully_suspended(true, &debug_bits)) {
+ return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
}
if (TraceJVMTICalls) {