Skip to content
Permalink
Browse files
add except_list argument to Suspend/ResumeAllVirtualThreads
  • Loading branch information
sspitsyn committed Mar 5, 2021
1 parent efdb7d0 commit 1457d6d285ad96687c3bc100be3665c80c65f7a7
@@ -2316,8 +2316,30 @@ jvmtiEnv *jvmti;
<required id="can_support_virtual_threads"></required>
</capabilities>
<parameters>
<param id="except_count">
<jint min="0"/>
<description>
The number of threads in the list of threads not to be suspended.
</description>
</param>
<param id="except_list">
<inbuf incount="except_count">
<jthread/>
<nullok>not an error if <code>except_count == 0</code></nullok>
</inbuf>
<description>
The list of threads not to be suspended.
</description>
</param>
</parameters>
<errors>
<error id="JVMTI_ERROR_INVALID_THREAD">
A thread in <paramlink id="except_list"></paramlink> was invalid.
</error>
<error id="JVMTI_ERROR_NULL_POINTER">
Both <paramlink id="except_list"></paramlink> was <code>NULL</code>
and <paramlink id="except_count"></paramlink> was non-zero.
</error>
</errors>
</function>

@@ -2326,7 +2348,7 @@ jvmtiEnv *jvmti;
<description>
Resume all virtual threads except those already resumed.
Virtual threads may be suspended with
<functionlink id="RsuspendAllVirtualThreads"></functionlink> or
<functionlink id="SuspendAllVirtualThreads"></functionlink> or
<functionlink id="SuspendThreadList"></functionlink> or
<functionlink id="SuspendThread"></functionlink>.
Virtual threads that are currently resumed do not change state.
@@ -2337,8 +2359,30 @@ jvmtiEnv *jvmti;
<required id="can_support_virtual_threads"></required>
</capabilities>
<parameters>
<param id="except_count">
<jint min="0"/>
<description>
The number of threads in the list of threads not to be resumed.
</description>
</param>
<param id="except_list">
<inbuf incount="except_count">
<jthread/>
<nullok>not an error if <code>except_count == 0</code></nullok>
</inbuf>
<description>
The list of threads not to be resumed.
</description>
</param>
</parameters>
<errors>
<error id="JVMTI_ERROR_INVALID_THREAD">
A thread in <paramlink id="except_list"></paramlink> was invalid.
</error>
<error id="JVMTI_ERROR_NULL_POINTER">
Both <paramlink id="except_list"></paramlink> was <code>NULL</code>
and <paramlink id="except_count"></paramlink> was non-zero.
</error>
</errors>
</function>

@@ -1064,21 +1064,37 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm


jvmtiError
JvmtiEnv::SuspendAllVirtualThreads() {
JvmtiEnv::SuspendAllVirtualThreads(jint except_count, const jthread* except_list) {
int needSafepoint = 0; // > 0 if a safepoint is needed
jvmtiError err = JvmtiEnvBase::check_thread_list(except_count, except_list);
if (err != JVMTI_ERROR_NONE) {
return err;
}
if (!JvmtiExport::can_support_virtual_threads()) {
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
}
{
ResourceMark rm;
JvmtiVTMTDisabler vtmt_disabler;
GrowableArray<jthread>* elist = new GrowableArray<jthread>(except_count);

// Collect threads from except_list which resumed status must be restored.
for (int idx = 0; idx < except_count; idx++) {
jthread thread = except_list[idx];
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (!JvmtiVTSuspender::vthread_is_ext_suspended(thread_oop)) {
// is resumed, so its resumed status must be restored
elist->append(except_list[idx]);
}
}

for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) {
oop jt_oop = java_thread->threadObj();
if (jt_oop == NULL || java_thread->is_exiting() ||
!java_lang_Thread::is_alive(jt_oop) ||
java_thread->is_jvmti_agent_thread() ||
java_thread->is_hidden_from_external_view()) {
java_thread->is_hidden_from_external_view() ||
is_in_thread_list(except_count, except_list, jt_oop)) {
continue;
}
oop thread_oop = java_thread->mounted_vthread();
@@ -1092,6 +1108,15 @@ JvmtiEnv::SuspendAllVirtualThreads() {
}
}
JvmtiVTSuspender::register_all_vthreads_suspend();

// Resume threads from except list that were resumed before.
for (int idx = 0; idx < elist->length(); idx++) {
jthread thread = elist->at(idx);
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (JvmtiVTSuspender::vthread_is_ext_suspended(thread_oop)) {
JvmtiVTSuspender::register_vthread_resume(thread_oop);
}
}
}
if (needSafepoint > 0) {
VM_ThreadsSuspendJVMTI tsj;
@@ -1144,19 +1169,35 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt


jvmtiError
JvmtiEnv::ResumeAllVirtualThreads() {
JvmtiEnv::ResumeAllVirtualThreads(jint except_count, const jthread* except_list) {
jvmtiError err = JvmtiEnvBase::check_thread_list(except_count, except_list);
if (err != JVMTI_ERROR_NONE) {
return err;
}
if (!JvmtiExport::can_support_virtual_threads()) {
return JVMTI_ERROR_MUST_POSSESS_CAPABILITY;
}
JvmtiVTMTDisabler vtmt_disabler;
ResourceMark rm;
JvmtiVTMTDisabler vtmt_disabler;
GrowableArray<jthread>* elist = new GrowableArray<jthread>(except_count);

// Collect threads from except_list which suspended status must be restored.
for (int idx = 0; idx < except_count; idx++) {
jthread thread = except_list[idx];
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (JvmtiVTSuspender::vthread_is_ext_suspended(thread_oop)) {
// is suspended, so its suspended status must be restored
elist->append(except_list[idx]);
}
}

for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) {
oop jt_oop = java_thread->threadObj();
if (jt_oop == NULL || java_thread->is_exiting() ||
!java_lang_Thread::is_alive(jt_oop) ||
java_thread->is_jvmti_agent_thread() ||
java_thread->is_hidden_from_external_view()) {
java_thread->is_hidden_from_external_view() ||
is_in_thread_list(except_count, except_list, jt_oop)) {
continue;
}
oop thread_oop = java_thread->mounted_vthread();
@@ -1167,6 +1208,15 @@ JvmtiEnv::ResumeAllVirtualThreads() {
}
}
JvmtiVTSuspender::register_all_vthreads_resume();

// Suspend threads from except list that were suspended before.
for (int idx = 0; idx < elist->length(); idx++) {
jthread thread = elist->at(idx);
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (!JvmtiVTSuspender::vthread_is_ext_suspended(thread_oop)) {
JvmtiVTSuspender::register_vthread_suspend(thread_oop);
}
}
return JVMTI_ERROR_NONE;
}

@@ -1442,6 +1442,33 @@ JvmtiEnvBase::get_object_monitor_usage(JavaThread* calling_thread, jobject objec
return JVMTI_ERROR_NONE;
}

jvmtiError
JvmtiEnvBase::check_thread_list(jint count, const jthread* list) {
if (list == NULL && count != 0) {
return JVMTI_ERROR_NULL_POINTER;
}
for (int i = 0; i < count; i++) {
jthread thread = list[i];
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (thread_oop == NULL || !thread_oop->is_a(vmClasses::VirtualThread_klass())) {
return JVMTI_ERROR_INVALID_THREAD;
}
}
return JVMTI_ERROR_NONE;
}

bool
JvmtiEnvBase::is_in_thread_list(jint count, const jthread* list, oop jt_oop) {
for (int idx = 0; idx < count; idx++) {
jthread thread = list[idx];
oop thread_oop = JNIHandles::resolve_external_guard(thread);
if (thread_oop == jt_oop) {
return true;
}
}
return false;
}

jvmtiError
JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool single_suspend,
int* need_safepoint_p) {
@@ -85,6 +85,8 @@ class JvmtiEnvBase : public CHeapObj<mtInternal> {
static jvmtiError suspend_thread(oop thread_oop, JavaThread* java_thread, bool single_suspend,
int* need_safepoint_p);
static jvmtiError resume_thread(oop thread_oop, JavaThread* java_thread, bool single_suspend);
static jvmtiError check_thread_list(jint count, const jthread* list);
static bool is_in_thread_list(jint count, const jthread* list, oop jt_oop);
private:

enum {
@@ -358,13 +358,15 @@ JvmtiVTSuspender::register_all_vthreads_suspend() {

_vthread_suspend_mode = vthread_suspend_all;
_vthread_suspend_list->invalidate();
_vthread_resume_list->invalidate();
}

void
JvmtiVTSuspender::register_all_vthreads_resume() {
MonitorLocker ml(JvmtiVTMT_lock, Mutex::_no_safepoint_check_flag);

_vthread_suspend_mode = vthread_suspend_none;
_vthread_suspend_list->invalidate();
_vthread_resume_list->invalidate();
}

@@ -1617,7 +1617,7 @@ threadControl_suspendAll(void)
/* Tell JVMTI to suspend all virtual threads. */
if (suspendAllCount == 0) {
error = JVMTI_FUNC_PTR(gdata->jvmti, SuspendAllVirtualThreads)
(gdata->jvmti);
(gdata->jvmti, 0, NULL);
if (error != JVMTI_ERROR_NONE) {
EXIT_ERROR(error, "cannot suspend all virtual threads");
}
@@ -1722,7 +1722,7 @@ threadControl_resumeAll(void)
if (suspendAllCount == 1) {
/* Tell JVMTI to resume all virtual threads. */
error = JVMTI_FUNC_PTR(gdata->jvmti,ResumeAllVirtualThreads)
(gdata->jvmti);
(gdata->jvmti, 0, NULL);
if (error != JVMTI_ERROR_NONE) {
EXIT_ERROR(error, "cannot resume all virtual threads");
}

0 comments on commit 1457d6d

Please sign in to comment.