Skip to content

Commit 966a42f

Browse files
committed
8324868: debug agent does not properly handle interrupts of a virtual thread
Reviewed-by: sspitsyn, amenkov
1 parent 22f10e0 commit 966a42f

File tree

3 files changed

+241
-126
lines changed

3 files changed

+241
-126
lines changed

src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c

Lines changed: 51 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ threadControl_resumeAll(void)
15491549
* resume any vthread with a suspendCount == 1, and we want to ignore
15501550
* vthreads with a suspendCount > 0. Therefore we don't want
15511551
* ResumeAllVirtualThreads resuming these vthreads. We must first
1552-
* build a list of them to pass to as the exclude list.
1552+
* build a list of them to pass as the exclude list.
15531553
*/
15541554
enumerateOverThreadList(env, &runningVThreads, excludeCountHelper,
15551555
&excludeCnt);
@@ -2117,28 +2117,25 @@ threadControl_onEventHandlerEntry(jbyte sessionID, EventInfo *evinfo, jobject cu
21172117
}
21182118

21192119
static void
2120-
doPendingTasks(JNIEnv *env, ThreadNode *node)
2120+
doPendingTasks(JNIEnv *env, jthread thread, int pendingInterrupt, jobject pendingStop)
21212121
{
21222122
/*
2123-
* Take care of any pending interrupts/stops, and clear out
2124-
* info on pending interrupts/stops.
2123+
* Take care of any pending interrupts/stops.
21252124
*/
2126-
if (node->pendingInterrupt) {
2125+
if (pendingInterrupt) {
21272126
JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2128-
(gdata->jvmti, node->thread);
2127+
(gdata->jvmti, thread);
21292128
/*
21302129
* TO DO: Log error
21312130
*/
2132-
node->pendingInterrupt = JNI_FALSE;
21332131
}
21342132

2135-
if (node->pendingStop != NULL) {
2133+
if (pendingStop != NULL) {
21362134
JVMTI_FUNC_PTR(gdata->jvmti,StopThread)
2137-
(gdata->jvmti, node->thread, node->pendingStop);
2135+
(gdata->jvmti, thread, pendingStop);
21382136
/*
21392137
* TO DO: Log error
21402138
*/
2141-
tossGlobalRef(env, &(node->pendingStop));
21422139
}
21432140
}
21442141

@@ -2147,35 +2144,44 @@ threadControl_onEventHandlerExit(EventIndex ei, jthread thread,
21472144
struct bag *eventBag)
21482145
{
21492146
ThreadNode *node;
2147+
JNIEnv *env = getEnv();
21502148

21512149
log_debugee_location("threadControl_onEventHandlerExit()", thread, NULL, 0);
21522150

21532151
if (ei == EI_THREAD_END) {
2154-
eventHandler_lock(); /* for proper lock order */
2155-
}
2156-
debugMonitorEnter(threadLock);
2157-
2158-
node = findRunningThread(thread);
2159-
if (node == NULL) {
2160-
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2161-
} else {
2162-
JNIEnv *env;
2163-
2164-
env = getEnv();
2165-
if (ei == EI_THREAD_END) {
2166-
removeThread(env, node);
2167-
node = NULL; /* has been freed */
2168-
} else {
2169-
/* No point in doing this if the thread is about to die.*/
2170-
doPendingTasks(env, node);
2171-
node->eventBag = eventBag;
2172-
node->current_ei = 0;
2152+
eventHandler_lock(); /* for proper lock order - see removeThread() call below */
2153+
debugMonitorEnter(threadLock);
2154+
node = findRunningThread(thread);
2155+
if (node == NULL) {
2156+
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
21732157
}
2174-
}
2175-
2176-
debugMonitorExit(threadLock);
2177-
if (ei == EI_THREAD_END) {
2158+
removeThread(env, node); // Grabs handlerLock, thus the reason for first grabbing it above.
2159+
node = NULL; // We exiting the threadLock. No longer safe to access.
2160+
debugMonitorExit(threadLock);
21782161
eventHandler_unlock();
2162+
} else {
2163+
debugMonitorEnter(threadLock);
2164+
node = findRunningThread(thread);
2165+
if (node == NULL) {
2166+
EXIT_ERROR(AGENT_ERROR_NULL_POINTER,"thread list corrupted");
2167+
}
2168+
/* No need to do the following if the thread is about to die.*/
2169+
int pendingInterrupt = node->pendingInterrupt;
2170+
jobject pendingStop = node->pendingStop;
2171+
jthread thread = node->thread;
2172+
node->pendingInterrupt = JNI_FALSE;
2173+
node->pendingStop = NULL;
2174+
node->eventBag = eventBag;
2175+
node->current_ei = 0;
2176+
node = NULL; // We exiting the threadLock. No longer safe to access.
2177+
// doPendingTasks() may do an upcall to java, and we don't want to hold any
2178+
// locks when doing that. Thus we got all our node updates done first
2179+
// and can now exit the threadLock.
2180+
debugMonitorExit(threadLock);
2181+
doPendingTasks(env, thread, pendingInterrupt, pendingStop);
2182+
if (pendingStop != NULL) {
2183+
tossGlobalRef(env, &pendingStop);
2184+
}
21792185
}
21802186
}
21812187

@@ -2219,29 +2225,9 @@ threadControl_applicationThreadStatus(jthread thread,
22192225
jvmtiError
22202226
threadControl_interrupt(jthread thread)
22212227
{
2222-
ThreadNode *node;
2223-
jvmtiError error;
2224-
2225-
error = JVMTI_ERROR_NONE;
2226-
22272228
log_debugee_location("threadControl_interrupt()", thread, NULL, 0);
22282229

2229-
debugMonitorEnter(threadLock);
2230-
2231-
node = findThread(&runningThreads, thread);
2232-
if ((node == NULL) || !HANDLING_EVENT(node)) {
2233-
error = JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)
2234-
(gdata->jvmti, thread);
2235-
} else {
2236-
/*
2237-
* Hold any interrupts until after the event is processed.
2238-
*/
2239-
node->pendingInterrupt = JNI_TRUE;
2240-
}
2241-
2242-
debugMonitorExit(threadLock);
2243-
2244-
return error;
2230+
return JVMTI_FUNC_PTR(gdata->jvmti,InterruptThread)(gdata->jvmti, thread);
22452231
}
22462232

22472233
void
@@ -2308,26 +2294,20 @@ threadControl_saveCLEInfo(JNIEnv *env, jthread thread, EventIndex ei,
23082294
debugMonitorExit(threadLock);
23092295
}
23102296

2297+
/*
2298+
* Support for getting an interrupt in an application thread while doing
2299+
* a debugMonitorWait().
2300+
*/
23112301
void
23122302
threadControl_setPendingInterrupt(jthread thread)
23132303
{
23142304
ThreadNode *node;
23152305

2316-
/*
2317-
* vmTestbase/nsk/jdb/kill/kill001/kill001.java seems to be the only code
2318-
* that triggers this function. Is uses ThreadReference.Stop.
2319-
*
2320-
* Since ThreadReference.Stop is not supported for vthreads, we should never
2321-
* get here with a vthread.
2322-
*/
2323-
JDI_ASSERT(!isVThread(thread));
2324-
23252306
debugMonitorEnter(threadLock);
23262307

2327-
node = findThread(&runningThreads, thread);
2328-
if (node != NULL) {
2329-
node->pendingInterrupt = JNI_TRUE;
2330-
}
2308+
node = findRunningThread(thread);
2309+
JDI_ASSERT(node != NULL);
2310+
node->pendingInterrupt = JNI_TRUE;
23312311

23322312
debugMonitorExit(threadLock);
23332313
}
@@ -2512,23 +2492,13 @@ threadControl_setEventMode(jvmtiEventMode mode, EventIndex ei, jthread thread)
25122492
}
25132493

25142494
/*
2515-
* Returns the current thread, if the thread has generated at least
2516-
* one event, and has not generated a thread end event.
2495+
* Returns the current thread.
25172496
*/
25182497
jthread
25192498
threadControl_currentThread(void)
25202499
{
2521-
jthread thread;
2522-
2523-
debugMonitorEnter(threadLock);
2524-
{
2525-
ThreadNode *node;
2526-
2527-
node = findThread(&runningThreads, NULL);
2528-
thread = (node == NULL) ? NULL : node->thread;
2529-
}
2530-
debugMonitorExit(threadLock);
2531-
2500+
jthread thread = NULL;
2501+
jvmtiError error = JVMTI_FUNC_PTR(gdata->jvmti,GetCurrentThread)(gdata->jvmti, &thread);
25322502
return thread;
25332503
}
25342504

@@ -2670,6 +2640,7 @@ dumpThread(ThreadNode *node) {
26702640
tty_message("\tthreadState: 0x%x", getThreadState(node));
26712641
tty_message("\ttoBeResumed: %d", node->toBeResumed);
26722642
tty_message("\tis_vthread: %d", node->is_vthread);
2643+
tty_message("\tpendingInterrupt: %d", node->pendingInterrupt);
26732644
tty_message("\tcurrentInvoke.pending: %d", node->currentInvoke.pending);
26742645
tty_message("\tcurrentInvoke.started: %d", node->currentInvoke.started);
26752646
tty_message("\tcurrentInvoke.available: %d", node->currentInvoke.available);

test/jdk/ProblemList-Xcomp.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@
2727
#
2828
#############################################################################
2929

30-
java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all
30+
java/lang/invoke/MethodHandles/CatchExceptionTest.java 8146623 generic-all
3131
java/lang/management/MemoryMXBean/CollectionUsageThreshold.java 8318668 generic-all
32+
com/sun/jdi/InterruptHangTest.java 8306679,8043571 generic-all

0 commit comments

Comments
 (0)