Skip to content

Commit 46ae7df

Browse files
Merge branch 'master' into JDK-8333664
2 parents 9876945 + cbbab07 commit 46ae7df

File tree

18 files changed

+208
-149
lines changed

18 files changed

+208
-149
lines changed

make/RunTests.gmk

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,12 +1343,14 @@ TARGETS += run-all-tests pre-run-test post-run-test run-test-report run-test
13431343

13441344
ifeq ($(TEST_OPTS_JCOV), true)
13451345

1346+
JCOV_VM_OPTS := -Xmx4g -Djdk.xml.totalEntitySizeLimit=0 -Djdk.xml.maxGeneralEntitySizeLimit=0
1347+
13461348
jcov-do-start-grabber:
13471349
$(call MakeDir, $(JCOV_OUTPUT_DIR))
13481350
if $(JAVA) -jar $(JCOV_HOME)/lib/jcov.jar GrabberManager -status 1>/dev/null 2>&1 ; then \
13491351
$(JAVA) -jar $(JCOV_HOME)/lib/jcov.jar GrabberManager -stop -stoptimeout 3600 ; \
13501352
fi
1351-
$(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar Grabber -v -t \
1353+
$(JAVA) $(JCOV_VM_OPTS) -jar $(JCOV_HOME)/lib/jcov.jar Grabber -v -t \
13521354
$(JCOV_IMAGE_DIR)/template.xml -o $(JCOV_RESULT_FILE) \
13531355
1>$(JCOV_GRABBER_LOG) 2>&1 &
13541356

@@ -1368,7 +1370,7 @@ ifeq ($(TEST_OPTS_JCOV), true)
13681370

13691371
jcov-gen-report: jcov-stop-grabber
13701372
$(call LogWarn, Generating JCov report ...)
1371-
$(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar RepGen -sourcepath \
1373+
$(JAVA) $(JCOV_VM_OPTS) -jar $(JCOV_HOME)/lib/jcov.jar RepGen -sourcepath \
13721374
`$(ECHO) $(TOPDIR)/src/*/share/classes/ | $(TR) ' ' ':'` -fmt html \
13731375
$(JCOV_FILTERS) \
13741376
-mainReportTitle "$(JCOV_REPORT_TITLE)" \
@@ -1392,7 +1394,7 @@ ifeq ($(TEST_OPTS_JCOV), true)
13921394
jcov-gen-diffcoverage: jcov-stop-grabber
13931395
$(call LogWarn, Generating diff coverage with changeset $(TEST_OPTS_JCOV_DIFF_CHANGESET) ... )
13941396
$(DIFF_COMMAND)
1395-
$(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar \
1397+
$(JAVA) $(JCOV_VM_OPTS) -jar $(JCOV_HOME)/lib/jcov.jar \
13961398
DiffCoverage -replaceDiff "src/.*/classes/:" -all \
13971399
$(JCOV_RESULT_FILE) $(JCOV_SOURCE_DIFF) > \
13981400
$(JCOV_DIFF_COVERAGE_REPORT)

src/hotspot/share/prims/jvmtiEnv.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,10 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm
988988
self_tobj = Handle(current, thread_oop);
989989
continue; // self suspend after all other suspends
990990
}
991+
if (java_lang_VirtualThread::is_instance(thread_oop)) {
992+
oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_oop);
993+
java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread);
994+
}
991995
results[i] = suspend_thread(thread_oop, java_thread, /* single_suspend */ true);
992996
}
993997
}
@@ -1114,6 +1118,10 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt
11141118
continue;
11151119
}
11161120
}
1121+
if (java_lang_VirtualThread::is_instance(thread_oop)) {
1122+
oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_oop);
1123+
java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread);
1124+
}
11171125
results[i] = resume_thread(thread_oop, java_thread, /* single_resume */ true);
11181126
}
11191127
// per-thread resume results returned via results parameter

src/hotspot/share/prims/jvmtiEnvBase.cpp

Lines changed: 61 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,8 +1398,7 @@ JvmtiEnvBase::is_vthread_suspended(oop vt_oop, JavaThread* jt) {
13981398
bool suspended = false;
13991399
if (java_lang_VirtualThread::is_instance(vt_oop)) {
14001400
suspended = JvmtiVTSuspender::is_vthread_suspended(vt_oop);
1401-
}
1402-
if (vt_oop->is_a(vmClasses::BoundVirtualThread_klass())) {
1401+
} else if (vt_oop->is_a(vmClasses::BoundVirtualThread_klass())) {
14031402
suspended = jt->is_suspended();
14041403
}
14051404
return suspended;
@@ -1757,66 +1756,55 @@ JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool singl
17571756
Handle thread_h(current, thread_oop);
17581757
bool is_virtual = java_lang_VirtualThread::is_instance(thread_h());
17591758

1760-
if (is_virtual) {
1761-
if (single_suspend) {
1762-
if (JvmtiVTSuspender::is_vthread_suspended(thread_h())) {
1763-
return JVMTI_ERROR_THREAD_SUSPENDED;
1764-
}
1765-
JvmtiVTSuspender::register_vthread_suspend(thread_h());
1766-
// Check if virtual thread is mounted and there is a java_thread.
1767-
// A non-null java_thread is always passed in the !single_suspend case.
1768-
oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_h());
1769-
java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread);
1770-
}
1771-
// The java_thread can be still blocked in VTMS transition after a previous JVMTI resume call.
1772-
// There is no need to suspend the java_thread in this case. After vthread unblocking,
1773-
// it will check for ext_suspend request and suspend itself if necessary.
1774-
if (java_thread == nullptr || java_thread->is_suspended()) {
1775-
// We are done if the virtual thread is unmounted or
1776-
// the java_thread is externally suspended.
1777-
return JVMTI_ERROR_NONE;
1778-
}
1779-
// The virtual thread is mounted: suspend the java_thread.
1780-
}
1781-
// Don't allow hidden thread suspend request.
1782-
if (java_thread->is_hidden_from_external_view()) {
1783-
return JVMTI_ERROR_NONE;
1784-
}
1785-
bool is_thread_carrying = is_thread_carrying_vthread(java_thread, thread_h());
1759+
// Unmounted vthread case.
17861760

1787-
// A case of non-virtual thread.
1788-
if (!is_virtual) {
1789-
// Thread.suspend() is used in some tests. It sets jt->is_suspended() only.
1790-
if (java_thread->is_carrier_thread_suspended() ||
1791-
(!is_thread_carrying && java_thread->is_suspended())) {
1761+
if (is_virtual && java_thread == nullptr) {
1762+
assert(single_suspend, "sanity check");
1763+
if (JvmtiVTSuspender::is_vthread_suspended(thread_h())) {
17921764
return JVMTI_ERROR_THREAD_SUSPENDED;
17931765
}
1794-
java_thread->set_carrier_thread_suspended();
1766+
JvmtiVTSuspender::register_vthread_suspend(thread_h());
1767+
return JVMTI_ERROR_NONE;
17951768
}
1769+
1770+
// Platform thread or mounted vthread cases.
1771+
1772+
assert(java_thread != nullptr, "sanity check");
17961773
assert(!java_thread->is_in_VTMS_transition(), "sanity check");
17971774

1798-
assert(!single_suspend || (!is_virtual && java_thread->is_carrier_thread_suspended()) ||
1799-
(is_virtual && JvmtiVTSuspender::is_vthread_suspended(thread_h())),
1800-
"sanity check");
1775+
// Don't allow hidden thread suspend request.
1776+
if (java_thread->is_hidden_from_external_view()) {
1777+
return JVMTI_ERROR_NONE;
1778+
}
18011779

18021780
// An attempt to handshake-suspend a thread carrying a virtual thread will result in
18031781
// suspension of mounted virtual thread. So, we just mark it as suspended
18041782
// and it will be actually suspended at virtual thread unmount transition.
1805-
if (!is_thread_carrying) {
1783+
bool is_thread_carrying = is_thread_carrying_vthread(java_thread, thread_h());
1784+
if (is_thread_carrying) {
1785+
return java_thread->set_carrier_thread_suspended() ? JVMTI_ERROR_NONE : JVMTI_ERROR_THREAD_SUSPENDED;
1786+
} else {
1787+
// Platform thread (not carrying vthread) or mounted vthread cases.
18061788
assert(thread_h() != nullptr, "sanity check");
18071789
assert(single_suspend || thread_h()->is_a(vmClasses::BaseVirtualThread_klass()),
18081790
"SuspendAllVirtualThreads should never suspend non-virtual threads");
1809-
// Case of mounted virtual or attached carrier thread.
1810-
if (!java_thread->java_suspend()) {
1791+
1792+
// Ideally we would just need to check java_thread->is_suspended(), but we have to
1793+
// consider the case of trying to suspend a thread that was previously suspended while
1794+
// carrying a vthread but has already unmounted it.
1795+
if (java_thread->is_suspended() || (!is_virtual && java_thread->is_carrier_thread_suspended())) {
1796+
return JVMTI_ERROR_THREAD_SUSPENDED;
1797+
}
1798+
if (!java_thread->java_suspend(is_virtual && single_suspend)) {
18111799
// Thread is already suspended or in process of exiting.
18121800
if (java_thread->is_exiting()) {
18131801
// The thread was in the process of exiting.
18141802
return JVMTI_ERROR_THREAD_NOT_ALIVE;
18151803
}
18161804
return JVMTI_ERROR_THREAD_SUSPENDED;
18171805
}
1806+
return JVMTI_ERROR_NONE;
18181807
}
1819-
return JVMTI_ERROR_NONE;
18201808
}
18211809

18221810
// java_thread - protected by ThreadsListHandle
@@ -1827,54 +1815,51 @@ JvmtiEnvBase::resume_thread(oop thread_oop, JavaThread* java_thread, bool single
18271815
Handle thread_h(current, thread_oop);
18281816
bool is_virtual = java_lang_VirtualThread::is_instance(thread_h());
18291817

1830-
if (is_virtual) {
1831-
if (single_resume) {
1832-
if (!JvmtiVTSuspender::is_vthread_suspended(thread_h())) {
1833-
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
1834-
}
1835-
JvmtiVTSuspender::register_vthread_resume(thread_h());
1836-
// Check if virtual thread is mounted and there is a java_thread.
1837-
// A non-null java_thread is always passed in the !single_resume case.
1838-
oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_h());
1839-
java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread);
1840-
}
1841-
// The java_thread can be still blocked in VTMS transition after a previous JVMTI suspend call.
1842-
// There is no need to resume the java_thread in this case. After vthread unblocking,
1843-
// it will check for is_vthread_suspended request and remain resumed if necessary.
1844-
if (java_thread == nullptr || !java_thread->is_suspended()) {
1845-
// We are done if the virtual thread is unmounted or
1846-
// the java_thread is not externally suspended.
1847-
return JVMTI_ERROR_NONE;
1818+
// Unmounted vthread case.
1819+
1820+
if (is_virtual && java_thread == nullptr) {
1821+
assert(single_resume, "sanity check");
1822+
if (!JvmtiVTSuspender::is_vthread_suspended(thread_h())) {
1823+
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
18481824
}
1849-
// The virtual thread is mounted and java_thread is supended: resume the java_thread.
1825+
JvmtiVTSuspender::register_vthread_resume(thread_h());
1826+
return JVMTI_ERROR_NONE;
18501827
}
1828+
1829+
// Platform thread or mounted vthread cases.
1830+
1831+
assert(java_thread != nullptr, "sanity check");
1832+
assert(!java_thread->is_in_VTMS_transition(), "sanity check");
1833+
18511834
// Don't allow hidden thread resume request.
18521835
if (java_thread->is_hidden_from_external_view()) {
18531836
return JVMTI_ERROR_NONE;
18541837
}
1855-
bool is_thread_carrying = is_thread_carrying_vthread(java_thread, thread_h());
18561838

1857-
// A case of a non-virtual thread.
1858-
if (!is_virtual) {
1859-
if (!java_thread->is_carrier_thread_suspended() &&
1860-
(is_thread_carrying || !java_thread->is_suspended())) {
1861-
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
1862-
}
1863-
java_thread->clear_carrier_thread_suspended();
1864-
}
1865-
assert(!java_thread->is_in_VTMS_transition(), "sanity check");
1839+
bool is_thread_carrying = is_thread_carrying_vthread(java_thread, thread_h());
1840+
if (is_thread_carrying) {
1841+
return java_thread->clear_carrier_thread_suspended() ? JVMTI_ERROR_NONE : JVMTI_ERROR_THREAD_NOT_SUSPENDED;
1842+
} else {
1843+
// Platform thread (not carrying vthread) or mounted vthread cases.
18661844

1867-
if (!is_thread_carrying) {
18681845
assert(thread_h() != nullptr, "sanity check");
18691846
assert(single_resume || thread_h()->is_a(vmClasses::BaseVirtualThread_klass()),
18701847
"ResumeAllVirtualThreads should never resume non-virtual threads");
1871-
if (java_thread->is_suspended()) {
1872-
if (!java_thread->java_resume()) {
1873-
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
1874-
}
1848+
1849+
// Ideally we would not have to check this but we have to consider the case
1850+
// of trying to resume a thread that was previously suspended while carrying
1851+
// a vthread but has already unmounted it.
1852+
if (!is_virtual && java_thread->is_carrier_thread_suspended()) {
1853+
bool res = java_thread->clear_carrier_thread_suspended();
1854+
assert(res, "resume operations running concurrently?");
1855+
return JVMTI_ERROR_NONE;
1856+
}
1857+
1858+
if (!java_thread->java_resume(is_virtual && single_resume)) {
1859+
return JVMTI_ERROR_THREAD_NOT_SUSPENDED;
18751860
}
1861+
return JVMTI_ERROR_NONE;
18761862
}
1877-
return JVMTI_ERROR_NONE;
18781863
}
18791864

18801865
ResourceTracker::ResourceTracker(JvmtiEnv* env) {

src/hotspot/share/prims/jvmtiImpl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ vframe *VM_GetOrSetLocal::get_vframe() {
658658

659659
javaVFrame *VM_GetOrSetLocal::get_java_vframe() {
660660
vframe* vf = get_vframe();
661-
if (!(_self || _thread->is_carrier_thread_suspended())) {
661+
if (!_self && !_thread->is_suspended() && !_thread->is_carrier_thread_suspended()) {
662662
_result = JVMTI_ERROR_THREAD_NOT_SUSPENDED;
663663
return nullptr;
664664
}

src/hotspot/share/prims/jvmtiThreadState.cpp

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -254,29 +254,37 @@ JvmtiVTMSTransitionDisabler::print_info() {
254254
// disable VTMS transitions for one virtual thread
255255
// disable VTMS transitions for all threads if thread is nullptr or a platform thread
256256
JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread)
257-
: _is_SR(false), _thread(thread)
257+
: _is_SR(false),
258+
_is_virtual(false),
259+
_is_self(false),
260+
_thread(thread)
258261
{
259262
if (!Continuations::enabled()) {
260263
return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads
261264
}
262265
if (Thread::current_or_null() == nullptr) {
263266
return; // Detached thread, can be a call from Agent_OnLoad.
264267
}
268+
JavaThread* current = JavaThread::current();
269+
oop thread_oop = JNIHandles::resolve_external_guard(thread);
270+
_is_virtual = java_lang_VirtualThread::is_instance(thread_oop);
271+
272+
if (thread == nullptr ||
273+
(!_is_virtual && thread_oop == current->threadObj()) ||
274+
(_is_virtual && thread_oop == current->vthread())) {
275+
_is_self = true;
276+
return; // no need for current thread to disable and enable transitions for itself
277+
}
265278
if (!sync_protocol_enabled_permanently()) {
266279
JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count();
267280
}
268-
oop thread_oop = JNIHandles::resolve_external_guard(thread);
269281

270282
// Target can be virtual or platform thread.
271283
// If target is a platform thread then we have to disable VTMS transitions for all threads.
272284
// It is by several reasons:
273285
// - carrier threads can mount virtual threads which may cause incorrect behavior
274286
// - there is no mechanism to disable transitions for a specific carrier thread yet
275-
if (!java_lang_VirtualThread::is_instance(thread_oop)) {
276-
_thread = nullptr; // target is a platform thread, switch to disabling VTMS transitions for all threads
277-
}
278-
279-
if (_thread != nullptr) {
287+
if (_is_virtual) {
280288
VTMS_transition_disable_for_one(); // disable VTMS transitions for one virtual thread
281289
} else {
282290
VTMS_transition_disable_for_all(); // disable VTMS transitions for all virtual threads
@@ -285,7 +293,10 @@ JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread)
285293

286294
// disable VTMS transitions for all virtual threads
287295
JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR)
288-
: _is_SR(is_SR), _thread(nullptr)
296+
: _is_SR(is_SR),
297+
_is_virtual(false),
298+
_is_self(false),
299+
_thread(nullptr)
289300
{
290301
if (!Continuations::enabled()) {
291302
return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads
@@ -309,7 +320,10 @@ JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() {
309320
if (Thread::current_or_null() == nullptr) {
310321
return; // Detached thread, can be a call from Agent_OnLoad.
311322
}
312-
if (_thread != nullptr) {
323+
if (_is_self) {
324+
return; // no need for current thread to disable and enable transitions for itself
325+
}
326+
if (_is_virtual) {
313327
VTMS_transition_enable_for_one(); // enable VTMS transitions for one virtual thread
314328
} else {
315329
VTMS_transition_enable_for_all(); // enable VTMS transitions for all virtual threads
@@ -684,7 +698,7 @@ JvmtiVTSuspender::_not_suspended_list = new VirtualThreadList();
684698

685699
void
686700
JvmtiVTSuspender::register_all_vthreads_suspend() {
687-
MonitorLocker ml(JvmtiVTMSTransition_lock);
701+
MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag);
688702

689703
_SR_mode = SR_all;
690704
_suspended_list->invalidate();
@@ -693,7 +707,7 @@ JvmtiVTSuspender::register_all_vthreads_suspend() {
693707

694708
void
695709
JvmtiVTSuspender::register_all_vthreads_resume() {
696-
MonitorLocker ml(JvmtiVTMSTransition_lock);
710+
MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag);
697711

698712
_SR_mode = SR_none;
699713
_suspended_list->invalidate();
@@ -703,7 +717,7 @@ JvmtiVTSuspender::register_all_vthreads_resume() {
703717
void
704718
JvmtiVTSuspender::register_vthread_suspend(oop vt) {
705719
int64_t id = java_lang_Thread::thread_id(vt);
706-
MonitorLocker ml(JvmtiVTMSTransition_lock);
720+
MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag);
707721

708722
if (_SR_mode == SR_all) {
709723
assert(_not_suspended_list->contains(id),
@@ -720,7 +734,7 @@ JvmtiVTSuspender::register_vthread_suspend(oop vt) {
720734
void
721735
JvmtiVTSuspender::register_vthread_resume(oop vt) {
722736
int64_t id = java_lang_Thread::thread_id(vt);
723-
MonitorLocker ml(JvmtiVTMSTransition_lock);
737+
MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag);
724738

725739
if (_SR_mode == SR_all) {
726740
assert(!_not_suspended_list->contains(id),

src/hotspot/share/prims/jvmtiThreadState.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -86,6 +86,8 @@ class JvmtiVTMSTransitionDisabler {
8686
static volatile bool _sync_protocol_enabled_permanently; // seen a suspender: JvmtiVTMSTransitionDisabler protocol is enabled permanently
8787

8888
bool _is_SR; // is suspender or resumer
89+
bool _is_virtual; // target thread is virtual
90+
bool _is_self; // JvmtiVTMSTransitionDisabler is a no-op for current platform, carrier or virtual thread
8991
jthread _thread; // virtual thread to disable transitions for, no-op if it is a platform thread
9092

9193
DEBUG_ONLY(static void print_info();)

0 commit comments

Comments
 (0)