On Thu, 17 Feb 2022 05:57:24 GMT, Chris Plummer <cjplum...@openjdk.org> wrote:

> processUnloads is continuously called on every event. It's purpose is to 
> process pending CLASS_UNLOAD events that have accumulated since the last 
> JVMTI event. This is a rather hacky solution. JVMTI does not actually send a 
> CLASS_UNLOAD event. It doesn't support them. What it does support is 
> OBJECT_FREE events. So when the debugger has enabled CLASS_UNLOAD events, the 
> debug agent enables OBJECT_FEE events. It tags each j.l.Class instance so it 
> will get the OBJECT_FREE event for them, and when the event comes in, the 
> Class gets added to deletedSignatures so the agent can later notify the 
> debugger about it.
> 
> As a side note, this OBJECT_FREE solution is somewhat new. The old solution 
> was to always do an "allClasses" during initialization, and then diff that 
> with "allClasses" every time there was a full GC to see which classes 
> unloaded. I wonder now if there isn't a reason we just don't send the 
> CLASS_UNLOAD when the OBJECT_FREE is received. It would probably greatly 
> simplify classTrack.c, and will fix an outstanding bug we have where 
> sometimes there is a lengthy delay before CLASS_UNLOAD events are sent. This 
> is because once there is a GC, they events are not sent until the next JVMTI 
> event. It's actually possible there would never be one if the only thing the 
> debugger is requesting is CLASS_UNLOAD events.
> 
> Anyway, back to processUnloads synchronization. The reason for 
> synchronization between processUnload and activate is because one thread 
> could be handling some random JVMTI event (maybe a breakpoint) and is calling 
> processUnloads, and at the same time another thread is handling a 
> CLASS_UNLOAD event request from the debugger, and calling activate. But now 
> that I think of it, this should be harmless even without synchronization. The 
> processUnloads thread will see the allocated deletedSignatures if activate 
> has gotten that far, otherwise it won't. It should behave correctly in either 
> case. I'm not convince that activate even needs synchronization. The purpose 
> of the classTrack synchronization is to prevent one thread in processUnloads 
> from grabbing and using deletedSignatures, only to have another thread in 
> processUnloads do the same, and delete deletedSignatures in the process, 
> leaving the 1st thread holding onto a deallocated pointer. However, even this 
> should not be possible because
  all callers to processUnloads have already grabbed the handlerLock.
> 
> What I'm tempted to say here is just have this PR keep all the 
> synchronization and I'll file a CR to possibly do a lot of cleanup here. 
> Either remove (maybe all of) the synchronization, or maybe even implement 
> sending the CLASS_UNLOAD when the OBJECT_FREE comes in, which will make the 
> synchronization question moot, and also fix that other bug I mentioned.
> 
> BTW, one other bit of nonsense. classTrack_activate() does:
> 
> ```
> deletedSignatures = bagCreateBag(sizeof(char*), 1000);
> ```
> 
> This will be deleted the very first time an event comes in, even if no 
> classes were unloaded, and processUnloads replaces it with:
> 
> ```
> deletedSignatures = bagCreateBag(sizeof(char*), 10);
> ```

I believe checking `bagSize() == 0` is an optimization. I think just taking 
`handlerLock` lock before calling `classTrack_reset()` ensures no race can 
happen and seems harmless.

-------------

PR: https://git.openjdk.java.net/jdk/pull/7461

Reply via email to