Skip to content

Commit 5e39f0f

Browse files
committed
8256811: Delayed/missed jdwp class unloading events
Reviewed-by: andrew Backport-of: 54854d9300479c22c416fd9d2fdb5c29fc1884bc
1 parent cce918b commit 5e39f0f

File tree

6 files changed

+193
-141
lines changed

6 files changed

+193
-141
lines changed

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

Lines changed: 4 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "util.h"
3838
#include "bag.h"
3939
#include "classTrack.h"
40+
#include "eventHandler.h"
4041

4142
#define NOT_TAGGED 0
4243

@@ -46,64 +47,14 @@
4647
static jvmtiEnv* trackingEnv;
4748

4849
/*
49-
* A bag containing all the deleted classes' signatures. Must be accessed under
50-
* classTrackLock.
50+
* Invoke the callback when classes are freed.
5151
*/
52-
struct bag* deletedSignatures;
53-
54-
/*
55-
* Lock to keep integrity of deletedSignatures.
56-
*/
57-
static jrawMonitorID classTrackLock;
58-
59-
/*
60-
* Invoke the callback when classes are freed, find and record the signature
61-
* in deletedSignatures. Those are only used in addPreparedClass() by the
62-
* same thread.
63-
*/
64-
static void JNICALL
52+
void JNICALL
6553
cbTrackingObjectFree(jvmtiEnv* jvmti_env, jlong tag)
6654
{
67-
debugMonitorEnter(classTrackLock);
68-
if (deletedSignatures == NULL) {
69-
debugMonitorExit(classTrackLock);
70-
return;
71-
}
72-
*(char**)bagAdd(deletedSignatures) = (char*)jlong_to_ptr(tag);
73-
74-
debugMonitorExit(classTrackLock);
75-
}
76-
77-
/*
78-
* Called after class unloads have occurred.
79-
* The signatures of classes which were unloaded are returned.
80-
*/
81-
struct bag *
82-
classTrack_processUnloads(JNIEnv *env)
83-
{
84-
if (deletedSignatures == NULL) {
85-
return NULL;
86-
}
87-
88-
/* Allocate new bag outside classTrackLock lock to avoid deadlock.
89-
*
90-
* Note: jvmtiAllocate/jvmtiDeallocate() may be blocked by ongoing safepoints.
91-
* It is dangerous to call them (via bagCreateBag/bagDestroyBag()) while holding monitor(s),
92-
* because jvmti may post events, e.g. JVMTI_EVENT_OBJECT_FREE at safepoints and event processing
93-
* code may acquire the same monitor(s), e.g. classTrackLock in cbTrackingObjectFree(),
94-
* which can lead to deadlock.
95-
*/
96-
struct bag* new_bag = bagCreateBag(sizeof(char*), 10);
97-
debugMonitorEnter(classTrackLock);
98-
struct bag* deleted = deletedSignatures;
99-
deletedSignatures = new_bag;
100-
debugMonitorExit(classTrackLock);
101-
return deleted;
55+
eventHandler_synthesizeUnloadEvent((char*)jlong_to_ptr(tag), getEnv());
10256
}
10357

104-
/*
105-
* Add a class to the prepared class table.
106-
*/
10758
void
10859
classTrack_addPreparedClass(JNIEnv *env_unused, jclass klass)
10960
{
@@ -162,8 +113,6 @@ setupEvents()
162113
void
163114
classTrack_initialize(JNIEnv *env)
164115
{
165-
deletedSignatures = NULL;
166-
classTrackLock = debugMonitorCreate("Deleted class tag lock");
167116
trackingEnv = getSpecialJvmti();
168117
if (trackingEnv == NULL) {
169118
EXIT_ERROR(AGENT_ERROR_INTERNAL, "Failed to allocate tag-tracking jvmtiEnv");
@@ -195,44 +144,3 @@ classTrack_initialize(JNIEnv *env)
195144
EXIT_ERROR(error,"loaded classes array");
196145
}
197146
}
198-
199-
/*
200-
* Called to activate class-tracking when a listener registers for EI_GC_FINISH.
201-
*/
202-
void
203-
classTrack_activate(JNIEnv *env)
204-
{
205-
// Allocate bag outside classTrackLock lock to avoid deadlock.
206-
// See comments in classTrack_processUnloads() for details.
207-
struct bag* new_bag = bagCreateBag(sizeof(char*), 1000);
208-
debugMonitorEnter(classTrackLock);
209-
deletedSignatures = new_bag;
210-
debugMonitorExit(classTrackLock);
211-
}
212-
213-
static jboolean
214-
cleanDeleted(void *signatureVoid, void *arg)
215-
{
216-
char* sig = *(char**)signatureVoid;
217-
jvmtiDeallocate(sig);
218-
return JNI_TRUE;
219-
}
220-
221-
/*
222-
* Called when agent detaches.
223-
*/
224-
void
225-
classTrack_reset(void)
226-
{
227-
debugMonitorEnter(classTrackLock);
228-
struct bag* to_delete = deletedSignatures;
229-
deletedSignatures = NULL;
230-
debugMonitorExit(classTrackLock);
231-
232-
// Deallocate bag outside classTrackLock to avoid deadlock.
233-
// See comments in classTrack_processUnloads() for details.
234-
if (to_delete != NULL) {
235-
bagEnumerateOver(to_delete, cleanDeleted, NULL);
236-
bagDestroyBag(to_delete);
237-
}
238-
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,6 @@ debugInit_reset(JNIEnv *env)
792792
threadControl_reset();
793793
util_reset();
794794
commonRef_reset(env);
795-
classTrack_reset();
796795

797796
/*
798797
* If this is a server, we are now ready to accept another connection.

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

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -457,16 +457,10 @@ reportEvents(JNIEnv *env, jbyte sessionID, jthread thread, EventIndex ei,
457457
}
458458
}
459459

460-
/* A bagEnumerateFunction. Create a synthetic class unload event
461-
* for every class no longer present. Analogous to event_callback
462-
* combined with a handler in a unload specific (no event
463-
* structure) kind of way.
464-
*/
465-
static jboolean
466-
synthesizeUnloadEvent(void *signatureVoid, void *envVoid)
460+
/* Create a synthetic class unload event for the specified signature. */
461+
jboolean
462+
eventHandler_synthesizeUnloadEvent(char *signature, JNIEnv *env)
467463
{
468-
JNIEnv *env = (JNIEnv *)envVoid;
469-
char *signature = *(char **)signatureVoid;
470464
char *classname;
471465
HandlerNode *node;
472466
jbyte eventSessionID = currentSessionID;
@@ -560,39 +554,10 @@ event_callback(JNIEnv *env, EventInfo *evinfo)
560554
currentException = JNI_FUNC_PTR(env,ExceptionOccurred)(env);
561555
JNI_FUNC_PTR(env,ExceptionClear)(env);
562556

563-
/* See if a garbage collection finish event happened earlier.
564-
*
565-
* Note: The "if" is an optimization to avoid entering the lock on every
566-
* event; garbageCollected may be zapped before we enter
567-
* the lock but then this just becomes one big no-op.
568-
*/
569-
if ( garbageCollected > 0 ) {
570-
struct bag *unloadedSignatures = NULL;
571-
572-
/* We want to compact the hash table of all
573-
* objects sent to the front end by removing objects that have
574-
* been collected.
575-
*/
557+
/* See if a garbage collection finish event happened earlier. */
558+
if ( garbageCollected > 0) {
576559
commonRef_compact();
577-
578-
/* We also need to simulate the class unload events. */
579-
580-
debugMonitorEnter(handlerLock);
581-
582-
/* Clear garbage collection counter */
583560
garbageCollected = 0;
584-
585-
/* Analyze which class unloads occurred */
586-
unloadedSignatures = classTrack_processUnloads(env);
587-
588-
debugMonitorExit(handlerLock);
589-
590-
/* Generate the synthetic class unload events and/or just cleanup. */
591-
if ( unloadedSignatures != NULL ) {
592-
(void)bagEnumerateOver(unloadedSignatures, synthesizeUnloadEvent,
593-
(void *)env);
594-
bagDestroyBag(unloadedSignatures);
595-
}
596561
}
597562

598563
thread = evinfo->thread;
@@ -1627,9 +1592,6 @@ installHandler(HandlerNode *node,
16271592

16281593
node->handlerID = external? ++requestIdCounter : 0;
16291594
error = eventFilterRestricted_install(node);
1630-
if (node->ei == EI_GC_FINISH) {
1631-
classTrack_activate(getEnv());
1632-
}
16331595
if (error == JVMTI_ERROR_NONE) {
16341596
insert(getHandlerChain(node->ei), node);
16351597
}

src/jdk.jdwp.agent/share/native/libjdwp/eventHandler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ void eventHandler_reset(jbyte sessionID);
7676
void eventHandler_lock(void);
7777
void eventHandler_unlock(void);
7878

79+
jboolean eventHandler_synthesizeUnloadEvent(char *signature, JNIEnv *env);
7980

8081
jclass getMethodClass(jvmtiEnv *jvmti_env, jmethodID method);
8182

test/hotspot/jtreg/ProblemList.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2016, 2022, 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

0 commit comments

Comments
 (0)