Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/gc_base/FinalizerSupport.cpp
5986 views
1
/*******************************************************************************
2
* Copyright (c) 1991, 2020 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception
21
*******************************************************************************/
22
23
#include "j9.h"
24
#include "j9accessbarrier.h"
25
#include "j9cfg.h"
26
#include "j9protos.h"
27
#include "j9user.h"
28
#include "j9consts.h"
29
#include "omrthread.h"
30
#include "jni.h"
31
#include "ModronAssertions.h"
32
33
#include "FinalizerSupport.hpp"
34
35
#include "AtomicOperations.hpp"
36
#include "ClassLoaderIterator.hpp"
37
#include "EnvironmentBase.hpp"
38
#include "FinalizeListManager.hpp"
39
#include "FinalizableObjectBuffer.hpp"
40
#include "GCExtensions.hpp"
41
#include "Heap.hpp"
42
#include "ModronTypes.hpp"
43
#include "ObjectAccessBarrier.hpp"
44
#include "OMRVMInterface.hpp"
45
#include "SublistFragment.hpp"
46
#include "SublistIterator.hpp"
47
#include "SublistSlotIterator.hpp"
48
#include "SublistPuddle.hpp"
49
#include "UnfinalizedObjectBuffer.hpp"
50
#include "UnfinalizedObjectList.hpp"
51
52
extern "C" {
53
54
#if defined(J9VM_GC_FINALIZATION)
55
56
/**
57
* finds and removes a class loader with thread notification from finalize list
58
*/
59
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
60
void *
61
finalizeForcedClassLoaderUnload(J9VMThread *vmThread)
62
{
63
void *returnValue = NULL;
64
J9ClassLoader *classLoader = NULL;
65
J9JavaVM *javaVM = vmThread->javaVM;
66
GC_FinalizeListManager *finalizeListManager = MM_GCExtensions::getExtensions(javaVM)->finalizeListManager;
67
68
#if defined(J9VM_THR_PREEMPTIVE)
69
finalizeListManager->lock();
70
omrthread_monitor_enter(javaVM->classLoaderBlocksMutex);
71
#endif /* J9VM_THR_PREEMPTIVE */
72
73
returnValue = (void *)finalizeListManager->popRequiredClassLoaderForForcedClassLoaderUnload();
74
75
if (NULL == returnValue) {
76
/* we did not find anything on the finalizeList now try the regular classloader list */
77
GC_ClassLoaderIterator classLoaderIterator(javaVM->classLoaderBlocks);
78
79
while (NULL != (classLoader = classLoaderIterator.nextSlot())) {
80
if (!(classLoader->gcFlags & J9_GC_CLASS_LOADER_UNLOADING)) {
81
if (classLoader->gcFlags & J9_GC_CLASS_LOADER_DEAD) {
82
if (NULL != classLoader->gcThreadNotification) {
83
// Class loader with pending threads found - process this class loader
84
returnValue = classLoader;
85
break;
86
}
87
}
88
}
89
} /* classLoaderIterator */
90
}
91
92
#if defined(J9VM_THR_PREEMPTIVE)
93
omrthread_monitor_exit(javaVM->classLoaderBlocksMutex);
94
finalizeListManager->unlock();
95
#endif /* J9VM_THR_PREEMPTIVE */
96
97
return returnValue;
98
}
99
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
100
101
102
/**
103
* Force objects from the unfinalized list to the finalizable lists.
104
*
105
* @note System class loader types are skipped until all other types of objects are processed (jck issue).
106
* @note Assumes the calling thread has VM access.
107
* @note This routine is a temporary hack while the finalizer is rewritten.
108
*/
109
void
110
finalizeForcedUnfinalizedToFinalizable(J9VMThread *vmThread)
111
{
112
#if defined(J9VM_GC_FINALIZATION)
113
MM_EnvironmentBase *env = MM_EnvironmentBase::getEnvironment(vmThread->omrVMThread);
114
MM_GCExtensions* extensions = MM_GCExtensions::getExtensions(env);
115
GC_FinalizeListManager *finalizeListManager = extensions->finalizeListManager;
116
117
/* Drop the lock and go for exclusive */
118
finalizeListManager->unlock();
119
env->acquireExclusiveVMAccess();
120
finalizeListManager->lock();
121
122
/* ensure that all thread-local buffers of unfinalized objects are flushed */
123
GC_OMRVMInterface::flushNonAllocationCaches(env);
124
125
GC_FinalizableObjectBuffer buffer(extensions);
126
/* process the lists */
127
MM_UnfinalizedObjectList *unfinalizedObjectList = extensions->unfinalizedObjectLists;
128
while(NULL != unfinalizedObjectList) {
129
/* Iterate directly the current list. Not calling startUnfinalizedProcessing() to create and iterate priorList.
130
* If forced finalize occurs in a middle of a CS cycle, startUnfinalizedProcessing have been already done.
131
* Doing it again would overwrite existing prior list, plus all of objects would then be processed
132
* at the end of CS as being in unfinalized list, while ther are actually in finalizable list.
133
*/
134
J9Object *objectPtr = unfinalizedObjectList->getHeadOfList();
135
while (NULL != objectPtr) {
136
J9Object* next = extensions->accessBarrier->getFinalizeLink(objectPtr);
137
/* CMVC 181817: need to remember all objects forced onto the finalizable list */
138
extensions->accessBarrier->forcedToFinalizableObject(vmThread, objectPtr);
139
buffer.add(env, objectPtr);
140
objectPtr = next;
141
}
142
/* Now that we moved out the content, make the list look empty (what typically startUnfinalizedProcessing does).
143
*/
144
unfinalizedObjectList->resetHeadOfList();
145
146
/* Flush the local buffer of finalizable objects to the global list.
147
* This needs to be done once per unfinalized list to ensure that all
148
* the objects contained in the buffer are always from the same tenant
149
* in multi-tenant mode
150
*/
151
buffer.flush(env);
152
153
unfinalizedObjectList = unfinalizedObjectList->getNextList();
154
}
155
156
env->releaseExclusiveVMAccess();
157
#endif /* J9VM_GC_FINALIZATION */
158
}
159
160
#define FINALIZE_WORKER_STAY_ALIVE 0
161
#define FINALIZE_WORKER_SHOULD_DIE 1
162
#define FINALIZE_WORKER_ABANDONED 2
163
#define FINALIZE_WORKER_SHOULD_ABANDON 3
164
165
#define FINALIZE_WORKER_MODE_NORMAL 0
166
#define FINALIZE_WORKER_MODE_FORCED 1
167
#define FINALIZE_WORKER_MODE_CL_UNLOAD 2
168
169
struct finalizeWorkerData {
170
omrthread_monitor_t monitor;
171
J9JavaVM *vm;
172
J9VMThread *vmThread;
173
IDATA finished;
174
IDATA die;
175
IDATA noWorkDone;
176
IDATA mode;
177
IDATA wakeUp;
178
};
179
180
static int J9THREAD_PROC FinalizeWorkerThread(void *arg);
181
IDATA FinalizeMainRunFinalization(J9JavaVM * vm, omrthread_t * indirectWorkerThreadHandle, struct finalizeWorkerData **indirectWorkerData, IDATA finalizeCycleLimit, IDATA mode);
182
static int J9THREAD_PROC FinalizeMainThread(void *javaVM);
183
static int J9THREAD_PROC gpProtectedFinalizeWorkerThread(void *entryArg);
184
185
static int J9THREAD_PROC FinalizeMainThread(void *javaVM)
186
{
187
J9JavaVM *vm = (J9JavaVM *)javaVM;
188
omrthread_t workerThreadHandle;
189
int doneRunFinalizersOnExit, noCycleWait;
190
struct finalizeWorkerData *workerData = NULL;
191
IDATA finalizeCycleInterval, finalizeCycleLimit, currentWaitTime, finalizableListUsed;
192
IDATA cycleIntervalWaitResult;
193
UDATA workerMode, savedFinalizeMainFlags;
194
GC_FinalizeListManager *finalizeListManager;
195
MM_GCExtensions* extensions = MM_GCExtensions::getExtensions(vm->omrVM);
196
MM_Forge *forge = extensions->getForge();
197
198
/* explicitly set the name for main finalizer thread as it is not attached to VM */
199
omrthread_set_name(omrthread_self(), "Finalizer main");
200
201
vm->finalizeMainThread = omrthread_self();
202
workerThreadHandle = NULL;
203
noCycleWait = 0;
204
205
finalizeListManager = extensions->finalizeListManager;
206
207
/* Initialize the defaults */
208
finalizeCycleInterval = extensions->finalizeCycleInterval;
209
finalizeCycleLimit = extensions->finalizeCycleLimit;
210
211
#if defined(J9VM_OPT_JAVA_OFFLOAD_SUPPORT)
212
if(NULL != vm->javaOffloadSwitchOnNoEnvWithReasonFunc) {
213
(*vm->javaOffloadSwitchOnNoEnvWithReasonFunc)(vm, vm->finalizeMainThread, J9_JNI_OFFLOAD_SWITCH_GC_FINALIZE_MAIN_THREAD);
214
}
215
#endif
216
217
currentWaitTime = 0;
218
omrthread_monitor_enter(vm->finalizeMainMonitor);
219
vm->finalizeMainFlags |= J9_FINALIZE_FLAGS_ACTIVE;
220
omrthread_monitor_notify_all(vm->finalizeMainMonitor);
221
222
do {
223
if(currentWaitTime != -1 && !noCycleWait) {
224
if(!(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_MAIN_WORK_REQUEST)) {
225
if(currentWaitTime == -2) {
226
omrthread_yield();
227
} else {
228
do {
229
cycleIntervalWaitResult = omrthread_monitor_wait_timed(vm->finalizeMainMonitor, currentWaitTime, 0);
230
} while(!(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_MAIN_WORK_REQUEST) && cycleIntervalWaitResult != J9THREAD_TIMED_OUT);
231
}
232
}
233
}
234
235
/* Check for a shutdown request, which overrides all other requests */
236
if(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_SHUTDOWN)
237
break;
238
239
/* Check for a wake up request, which means the garbage collector has placed objects on the finalizable queue for processing */
240
if(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_MAIN_WAKE_UP) {
241
vm->finalizeMainFlags &= ~J9_FINALIZE_FLAGS_MAIN_WAKE_UP;
242
currentWaitTime = finalizeCycleInterval;
243
}
244
245
/* Adjust the wait time based on how full the finalizable queue is (magic for now) */
246
finalizableListUsed = finalizeListManager->getJobCount();
247
if(0 != finalizableListUsed) {
248
noCycleWait = 1;
249
} else {
250
noCycleWait = 0;
251
}
252
253
/* If RUN_FINALIZATION is set, make the interval time is set to -1 -> This will override any "wake up" request made by the garbage collector */
254
if(vm->finalizeMainFlags & (J9_FINALIZE_FLAGS_RUN_FINALIZATION
255
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
256
| J9_FINALIZE_FLAGS_FORCE_CLASS_LOADER_UNLOAD
257
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
258
))
259
currentWaitTime = -1;
260
261
/* There is work to be done - run one finalization cycle */
262
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
263
if(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_FORCE_CLASS_LOADER_UNLOAD) {
264
workerMode = FINALIZE_WORKER_MODE_CL_UNLOAD;
265
} else {
266
workerMode = FINALIZE_WORKER_MODE_NORMAL;
267
}
268
#else /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
269
workerMode = FINALIZE_WORKER_MODE_NORMAL;
270
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
271
272
savedFinalizeMainFlags = vm->finalizeMainFlags;
273
274
IDATA result = FinalizeMainRunFinalization(vm, &workerThreadHandle, &workerData, finalizeCycleLimit, workerMode);
275
if(result < 0) {
276
/* give up this run and hope next time will be better */
277
currentWaitTime = 0;
278
noCycleWait = 0;
279
continue;
280
}
281
282
/* Determine whether the worker actually did finish it's work */
283
omrthread_monitor_enter(workerData->monitor);
284
if(workerData->finished) {
285
if(workerData->noWorkDone) {
286
workerData->noWorkDone = 0;
287
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
288
if(!(savedFinalizeMainFlags & J9_FINALIZE_FLAGS_FORCE_CLASS_LOADER_UNLOAD)) {
289
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
290
currentWaitTime = 0;
291
if(savedFinalizeMainFlags & J9_FINALIZE_FLAGS_RUN_FINALIZATION) {
292
vm->finalizeMainFlags &= ~J9_FINALIZE_FLAGS_RUN_FINALIZATION;
293
omrthread_monitor_enter(vm->finalizeRunFinalizationMutex);
294
omrthread_monitor_notify_all(vm->finalizeRunFinalizationMutex);
295
omrthread_monitor_exit(vm->finalizeRunFinalizationMutex);
296
}
297
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
298
}
299
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
300
}
301
} else {
302
/* The worker never finished during the allocated time - abandon it */
303
workerData->die = FINALIZE_WORKER_ABANDONED;
304
workerThreadHandle = NULL;
305
}
306
omrthread_monitor_exit(workerData->monitor);
307
} while(!(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_SHUTDOWN));
308
309
/* Check if finalizers should be run on exit */
310
if(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_RUN_FINALIZERS_ON_EXIT) {
311
doneRunFinalizersOnExit = 0;
312
while(!doneRunFinalizersOnExit) {
313
IDATA result = 0;
314
do {
315
/* Keep trying, even if a worker requests that it be abandoned */
316
result = FinalizeMainRunFinalization(vm, &workerThreadHandle, &workerData, finalizeCycleLimit, FINALIZE_WORKER_MODE_FORCED);
317
} while(result == -2);
318
319
if(result == -1) {
320
/* There was a bad error - just move to the actual quit phase */
321
break;
322
}
323
324
omrthread_monitor_enter(workerData->monitor);
325
if(workerData->finished && workerData->noWorkDone) {
326
/* No more work to be done */
327
doneRunFinalizersOnExit = 1;
328
}
329
if(!workerData->finished) {
330
/* The worker seems to be hung - just quit */
331
doneRunFinalizersOnExit = 1;
332
workerData->die = FINALIZE_WORKER_ABANDONED;
333
workerThreadHandle = NULL;
334
}
335
omrthread_monitor_exit(workerData->monitor);
336
}
337
}
338
339
/* We've been told to die */
340
if(NULL != workerThreadHandle) {
341
omrthread_monitor_exit((omrthread_monitor_t)vm->finalizeMainMonitor);
342
omrthread_monitor_enter(workerData->monitor);
343
workerData->die = FINALIZE_WORKER_SHOULD_DIE;
344
omrthread_monitor_notify_all(workerData->monitor);
345
omrthread_monitor_wait(workerData->monitor);
346
omrthread_monitor_exit(workerData->monitor);
347
omrthread_monitor_destroy(workerData->monitor);
348
forge->free(workerData);
349
omrthread_monitor_enter((omrthread_monitor_t)vm->finalizeMainMonitor);
350
}
351
352
#if defined(J9VM_OPT_JAVA_OFFLOAD_SUPPORT)
353
if(NULL != vm->javaOffloadSwitchOffNoEnvWithReasonFunc) {
354
(*vm->javaOffloadSwitchOffNoEnvWithReasonFunc)(vm, vm->finalizeMainThread, J9_JNI_OFFLOAD_SWITCH_GC_FINALIZE_MAIN_THREAD);
355
}
356
#endif
357
358
/* Notify the main thread that we have shut down */
359
vm->finalizeMainFlags |= J9_FINALIZE_FLAGS_SHUTDOWN_COMPLETE;
360
vm->finalizeMainFlags &= ~J9_FINALIZE_FLAGS_ACTIVE;
361
omrthread_monitor_notify_all((omrthread_monitor_t)vm->finalizeMainMonitor);
362
363
/* If anyone is left waiting for forced finalization to complete, wake them up */
364
if(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_RUN_FINALIZATION) {
365
vm->finalizeMainFlags &= ~J9_FINALIZE_FLAGS_RUN_FINALIZATION;
366
omrthread_monitor_enter(vm->finalizeRunFinalizationMutex);
367
omrthread_monitor_notify_all(vm->finalizeRunFinalizationMutex);
368
omrthread_monitor_exit(vm->finalizeRunFinalizationMutex);
369
}
370
371
omrthread_exit((omrthread_monitor_t)vm->finalizeMainMonitor); /* exit the monitor and terminate the thread */
372
373
/* NO GUARANTEED EXECUTION BEYOND THIS POINT */
374
375
return 0;
376
}
377
378
static void
379
process_finalizable(J9VMThread *vmThread, j9object_t object, jclass j9VMInternalsClass, jmethodID runFinalizeMID)
380
{
381
J9InternalVMFunctions* fns;
382
J9JavaVM *vm;
383
384
vm = vmThread->javaVM;
385
fns = vm->internalVMFunctions;
386
387
jobject localRef = fns->j9jni_createLocalRef((JNIEnv *)vmThread, object);
388
389
fns->internalReleaseVMAccess(vmThread);
390
391
if((NULL != j9VMInternalsClass) && (NULL != runFinalizeMID)) {
392
#if defined(J9VM_PORT_ZOS_CEEHDLRSUPPORT)
393
/* Tell the interpreter to not register a user condition handler for this callin.
394
* Note: the interpreter clears J9_PRIVATE_FLAGS_SKIP_THREAD_SIGNAL_PROTECTION after reading it,
395
* so subsequent callins are not affected */
396
vmThread->privateFlags |= J9_PRIVATE_FLAGS_SKIP_THREAD_SIGNAL_PROTECTION;
397
#endif
398
((JNIEnv *)vmThread)->CallStaticVoidMethod(j9VMInternalsClass, runFinalizeMID, localRef);
399
((JNIEnv *)vmThread)->ExceptionClear();
400
}
401
402
((JNIEnv *)vmThread)->DeleteLocalRef(localRef);
403
404
fns->internalEnterVMFromJNI(vmThread);
405
}
406
407
static void
408
process_reference(J9VMThread *vmThread, j9object_t reference, jmethodID refMID)
409
{
410
J9InternalVMFunctions* fns;
411
J9JavaVM *vm;
412
413
vm = vmThread->javaVM;
414
fns = vm->internalVMFunctions;
415
416
jobject localRef = fns->j9jni_createLocalRef((JNIEnv *)vmThread, reference);
417
418
fns->internalReleaseVMAccess(vmThread);
419
420
if (refMID) {
421
#if defined(J9VM_PORT_ZOS_CEEHDLRSUPPORT)
422
/* Tell the interpreter to not register a user condition handler for this callin.
423
* Note: the interpreter clears J9_PRIVATE_FLAGS_SKIP_THREAD_SIGNAL_PROTECTION after reading it,
424
* so subsequent callins are not affected */
425
vmThread->privateFlags |= J9_PRIVATE_FLAGS_SKIP_THREAD_SIGNAL_PROTECTION;
426
#endif
427
((JNIEnv *)vmThread)->CallBooleanMethod(localRef, refMID);
428
((JNIEnv *)vmThread)->ExceptionClear();
429
}
430
431
((JNIEnv *)vmThread)->DeleteLocalRef(localRef);
432
433
fns->internalEnterVMFromJNI(vmThread);
434
}
435
436
static void
437
process_classloader(J9VMThread *vmThread, J9ClassLoader *classLoader)
438
{
439
J9InternalVMFunctions* fns;
440
J9JavaVM *vm;
441
442
vm = vmThread->javaVM;
443
fns = vm->internalVMFunctions;
444
445
fns->internalReleaseVMAccess(vmThread);
446
447
fns->internalEnterVMFromJNI(vmThread);
448
Assert_MM_true(NULL == classLoader->classSegments);
449
fns->freeClassLoader(classLoader, vm, vmThread, JNI_FALSE);
450
fns->internalReleaseVMAccess(vmThread);
451
452
fns->internalEnterVMFromJNI(vmThread);
453
}
454
455
static void
456
process(J9VMThread *vmThread, const GC_FinalizeJob *finalizeJob, jclass j9VMInternalsClass, jmethodID runFinalizeMID, jmethodID referenceEnqueueImplMID)
457
{
458
if (FINALIZE_JOB_TYPE_OBJECT == (finalizeJob->type & FINALIZE_JOB_TYPE_OBJECT)) {
459
process_finalizable(vmThread, finalizeJob->object, j9VMInternalsClass, runFinalizeMID);
460
} else if (FINALIZE_JOB_TYPE_REFERENCE == (finalizeJob->type & FINALIZE_JOB_TYPE_REFERENCE)) {
461
process_reference(vmThread, finalizeJob->reference, referenceEnqueueImplMID);
462
} else if (FINALIZE_JOB_TYPE_CLASSLOADER == (finalizeJob->type & FINALIZE_JOB_TYPE_CLASSLOADER)) {
463
process_classloader(vmThread, finalizeJob->classLoader);
464
} else {
465
Assert_MM_unreachable();
466
}
467
}
468
469
/**
470
* Worker thread consumes jobs from Finalize List Manager and process them
471
*/
472
static int J9THREAD_PROC FinalizeWorkerThread(void *arg)
473
{
474
struct finalizeWorkerData *workerData = (struct finalizeWorkerData *)arg;
475
J9VMThread *env;
476
const GC_FinalizeJob *finalizeJob;
477
GC_FinalizeJob localJob;
478
jclass referenceClazz, j9VMInternalsClass = NULL;
479
jmethodID referenceEnqueueImplMID = NULL, runFinalizeMID = NULL;
480
J9InternalVMFunctions* fns;
481
omrthread_monitor_t monitor;
482
GC_FinalizeListManager *finalizeListManager;
483
J9JavaVM *vm = (J9JavaVM *)(workerData->vm);
484
MM_GCExtensions *extensions = MM_GCExtensions::getExtensions(vm);
485
MM_Forge *forge = extensions->getForge();
486
487
fns = vm->internalVMFunctions;
488
monitor = workerData->monitor;
489
490
finalizeListManager = extensions->finalizeListManager;
491
492
if (JNI_OK != vm->internalVMFunctions->attachSystemDaemonThread(vm, &env, "Finalizer thread")) {
493
/* Failed to attach the thread - very bad, most likely out of memory */
494
workerData->vmThread = (J9VMThread *)NULL;
495
omrthread_monitor_enter(monitor);
496
omrthread_monitor_notify_all(monitor);
497
omrthread_monitor_exit(monitor);
498
return 0;
499
}
500
501
#if defined(J9VM_OPT_JAVA_OFFLOAD_SUPPORT)
502
if( vm->javaOffloadSwitchOnWithReasonFunc != NULL ) {
503
(*vm->javaOffloadSwitchOnWithReasonFunc)((J9VMThread *)env, J9_JNI_OFFLOAD_SWITCH_FINALIZE_WORKER_THREAD);
504
((J9VMThread *)env)->javaOffloadState = 1;
505
}
506
#endif
507
508
fns->internalEnterVMFromJNI(env);
509
env->privateFlags |= (J9_PRIVATE_FLAGS_FINALIZE_WORKER | J9_PRIVATE_FLAGS_USE_BOOTSTRAP_LOADER);
510
fns->internalReleaseVMAccess(env);
511
512
/* Remember that the thread was gpProtected -- important for the JIT */
513
env->gpProtected = 1;
514
515
if(vm->jclFlags & J9_JCL_FLAG_FINALIZATION) {
516
/* Only look up finalization methods if the class library supports them */
517
j9VMInternalsClass = ((JNIEnv *)env)->FindClass("java/lang/J9VMInternals");
518
if (j9VMInternalsClass) {
519
j9VMInternalsClass = (jclass)((JNIEnv *)env)->NewGlobalRef(j9VMInternalsClass);
520
if (j9VMInternalsClass) {
521
runFinalizeMID = ((JNIEnv *)env)->GetStaticMethodID(j9VMInternalsClass, "runFinalize", "(Ljava/lang/Object;)V");
522
}
523
}
524
if (!runFinalizeMID) {
525
((JNIEnv *)env)->ExceptionClear();
526
}
527
528
referenceClazz = ((JNIEnv *)env)->FindClass("java/lang/ref/Reference");
529
if (referenceClazz) {
530
referenceEnqueueImplMID = ((JNIEnv *)env)->GetMethodID(referenceClazz, "enqueueImpl", "()Z");
531
}
532
if (!referenceEnqueueImplMID) {
533
((JNIEnv *)env)->ExceptionClear();
534
}
535
}
536
workerData->vmThread = env;
537
538
/* Notify that the worker has come on line (We should check the result from above) */
539
omrthread_monitor_enter(monitor);
540
omrthread_monitor_notify_all(monitor);
541
542
do {
543
if(!workerData->wakeUp) {
544
omrthread_monitor_wait(monitor);
545
}
546
workerData->wakeUp = 0;
547
548
if(workerData->die != FINALIZE_WORKER_STAY_ALIVE) {
549
continue;
550
}
551
552
omrthread_monitor_exit(monitor);
553
554
fns->internalEnterVMFromJNI(env);
555
556
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
557
if(workerData->mode != FINALIZE_WORKER_MODE_CL_UNLOAD)
558
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
559
{
560
if ((NULL != vm->processReferenceMonitor) && (0 != finalizeListManager->getReferenceCount())) {
561
omrthread_monitor_enter(vm->processReferenceMonitor);
562
vm->processReferenceActive = 1;
563
omrthread_monitor_exit(vm->processReferenceMonitor);
564
}
565
}
566
567
do {
568
569
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
570
if(workerData->mode == FINALIZE_WORKER_MODE_CL_UNLOAD) {
571
572
if (NULL == (localJob.classLoader = (J9ClassLoader *)finalizeForcedClassLoaderUnload((J9VMThread *)env))) {
573
break;
574
} else {
575
localJob.type = FINALIZE_JOB_TYPE_CLASSLOADER;
576
finalizeJob = &localJob;
577
}
578
579
} else {
580
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
581
582
583
finalizeListManager->lock();
584
585
finalizeJob = finalizeListManager->consumeJob(env, &localJob);
586
if(finalizeJob == NULL) {
587
if(workerData->mode == FINALIZE_WORKER_MODE_FORCED) {
588
finalizeForcedUnfinalizedToFinalizable(env);
589
finalizeJob = finalizeListManager->consumeJob(env, &localJob);
590
}
591
}
592
593
finalizeListManager->unlock();
594
595
if(NULL != finalizeJob) {
596
workerData->noWorkDone = 0;
597
} else {
598
workerData->noWorkDone = 1;
599
break;
600
}
601
602
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
603
}
604
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
605
606
/* processing will release/acquire VM access */
607
process(env, finalizeJob, j9VMInternalsClass, runFinalizeMID, referenceEnqueueImplMID);
608
609
if ((NULL != vm->processReferenceMonitor) && (0 != vm->processReferenceActive)) {
610
omrthread_monitor_enter(vm->processReferenceMonitor);
611
if (0 == finalizeListManager->getReferenceCount()) {
612
/* There is no more pending reference. */
613
vm->processReferenceActive = 0;
614
}
615
/*
616
* Notify any waiters that progress has been made.
617
* This improves latency for Reference.waitForReferenceProcessing() and try to
618
* avoid the performance issue if there are many of pending references in the queue.
619
*/
620
omrthread_monitor_notify_all(vm->processReferenceMonitor);
621
omrthread_monitor_exit(vm->processReferenceMonitor);
622
}
623
624
fns->jniResetStackReferences((JNIEnv *)env);
625
626
if(FINALIZE_WORKER_SHOULD_ABANDON == workerData->die) {
627
/* We've been abandoned, finish up */
628
break;
629
}
630
} while (true);
631
632
fns->internalReleaseVMAccess(env);
633
634
workerData->finished = 1;
635
636
/* Notify the main that the work is complete */
637
omrthread_monitor_enter(monitor);
638
omrthread_monitor_notify_all(monitor);
639
} while(workerData->die == FINALIZE_WORKER_STAY_ALIVE);
640
641
if (j9VMInternalsClass) {
642
((JNIEnv *)env)->DeleteGlobalRef(j9VMInternalsClass);
643
}
644
645
((JavaVM *)vm)->DetachCurrentThread();
646
647
#if defined(J9VM_OPT_JAVA_OFFLOAD_SUPPORT)
648
if( vm->javaOffloadSwitchOffNoEnvWithReasonFunc != NULL ) {
649
(*vm->javaOffloadSwitchOffNoEnvWithReasonFunc)(vm, omrthread_self(), J9_JNI_OFFLOAD_SWITCH_FINALIZE_WORKER_THREAD);
650
}
651
#endif
652
653
switch(workerData->die) {
654
case FINALIZE_WORKER_SHOULD_ABANDON:
655
/* Poke the main in case it missed the notify */
656
omrthread_monitor_notify_all(workerData->monitor);
657
658
/* Now wait for the main to give us the OK to die */
659
while(FINALIZE_WORKER_SHOULD_ABANDON == workerData->die) {
660
omrthread_monitor_wait(workerData->monitor);
661
}
662
Assert_MM_true(FINALIZE_WORKER_ABANDONED == workerData->die);
663
/* Fallthrough to the abandoned case */
664
665
case FINALIZE_WORKER_ABANDONED:
666
/* Clean up communication data structures data structures */
667
omrthread_monitor_exit(workerData->monitor);
668
omrthread_monitor_destroy(workerData->monitor);
669
forge->free(workerData);
670
break;
671
case FINALIZE_WORKER_SHOULD_DIE:
672
omrthread_monitor_notify_all(workerData->monitor);
673
omrthread_exit(workerData->monitor); /* exit the monitor, and terminate the thread */
674
/* NO EXECUTION GUARANTEE BEYOND THIS POINT */
675
}
676
677
/* NO EXECUTION GUARANTEE BEYOND THIS POINT */
678
679
return 0;
680
}
681
682
/*
683
* Preconditions:
684
* holds finalizeMainMonitor
685
* does not hold workerData->monitor
686
* Postconditions:
687
* holds finalizeMainMonitor
688
* does not hold workerData->monitor
689
*/
690
IDATA FinalizeMainRunFinalization(J9JavaVM * vm, omrthread_t * indirectWorkerThreadHandle,
691
struct finalizeWorkerData **indirectWorkerData, IDATA finalizeCycleLimit,
692
IDATA mode)
693
{
694
omrthread_t workerThreadHandle;
695
struct finalizeWorkerData *workerData;
696
IDATA workerWaitResult;
697
UDATA publicFlags;
698
MM_Forge *forge = MM_GCExtensionsBase::getExtensions(vm->omrVM)->getForge();
699
700
workerThreadHandle = *indirectWorkerThreadHandle;
701
workerData = *indirectWorkerData;
702
703
/* There is work to be done - if no worker thread exists, create one */
704
if (NULL == workerThreadHandle) {
705
/* Initialize a workerData structure */
706
workerData = (struct finalizeWorkerData *) forge->allocate(sizeof(struct finalizeWorkerData), MM_AllocationCategory::FINALIZE, J9_GET_CALLSITE());
707
if (NULL == workerData) {
708
/* What should be done here! */
709
return -1;
710
}
711
workerData->vm = vm;
712
workerData->die = FINALIZE_WORKER_STAY_ALIVE;
713
workerData->noWorkDone = 0;
714
workerData->mode = FINALIZE_WORKER_MODE_NORMAL;
715
workerData->wakeUp = 0;
716
717
if (0 != omrthread_monitor_init(&(workerData->monitor), 0)) {
718
forge->free(workerData);
719
720
/* What should be done here! */
721
return -1;
722
}
723
omrthread_monitor_exit(vm->finalizeMainMonitor);
724
omrthread_monitor_enter(workerData->monitor);
725
726
/* Fork the worker thread */
727
IDATA result = vm->internalVMFunctions->createThreadWithCategory(
728
&workerThreadHandle,
729
vm->defaultOSStackSize,
730
MM_GCExtensions::getExtensions(vm)->finalizeWorkerPriority,
731
0,
732
&gpProtectedFinalizeWorkerThread,
733
workerData,
734
J9THREAD_CATEGORY_APPLICATION_THREAD);
735
736
if (result != 0) {
737
omrthread_monitor_exit(workerData->monitor);
738
omrthread_monitor_destroy(workerData->monitor);
739
forge->free(workerData);
740
omrthread_monitor_enter(vm->finalizeMainMonitor);
741
return -1;
742
}
743
omrthread_monitor_wait(workerData->monitor);
744
if (!workerData->vmThread) {
745
/* The worker thread failed to initialize/attach - this is really bad */
746
omrthread_monitor_exit(workerData->monitor);
747
omrthread_monitor_destroy(workerData->monitor);
748
forge->free(workerData);
749
omrthread_monitor_enter(vm->finalizeMainMonitor);
750
return -1;
751
}
752
omrthread_monitor_exit(workerData->monitor);
753
omrthread_monitor_enter(vm->finalizeMainMonitor);
754
755
*indirectWorkerData = workerData;
756
*indirectWorkerThreadHandle = workerThreadHandle;
757
758
/* Connect the worker */
759
vm->finalizeWorkerData = workerData;
760
}
761
762
/* A worker exists - set it to work */
763
omrthread_monitor_exit(vm->finalizeMainMonitor);
764
765
omrthread_monitor_enter(workerData->monitor);
766
workerData->wakeUp = 1;
767
workerData->mode = mode;
768
workerData->finished = 0;
769
omrthread_monitor_notify_all(workerData->monitor); /* Wake worker up */
770
do {
771
workerWaitResult = omrthread_monitor_wait_timed(workerData->monitor, finalizeCycleLimit, 0);
772
773
omrthread_monitor_enter(workerData->vmThread->publicFlagsMutex);
774
publicFlags = workerData->vmThread->publicFlags;
775
omrthread_monitor_exit(workerData->vmThread->publicFlagsMutex);
776
}
777
while (
778
(workerWaitResult == J9THREAD_TIMED_OUT && publicFlags & J9_PUBLIC_FLAGS_HALT_VM_DUTIES &&
779
!workerData->finished) || (workerWaitResult != J9THREAD_TIMED_OUT && !workerData->finished));
780
omrthread_monitor_exit(workerData->monitor);
781
782
omrthread_monitor_enter(vm->finalizeMainMonitor);
783
784
if(FINALIZE_WORKER_SHOULD_ABANDON == workerData->die) {
785
/* The worker thread has requested that we abandon it */
786
787
/* Disconnect the worker */
788
vm->finalizeWorkerData = NULL;
789
*indirectWorkerThreadHandle = NULL;
790
*indirectWorkerData = NULL;
791
792
/* Let the abandoned worker know that it can clean up */
793
omrthread_monitor_enter(workerData->monitor);
794
workerData->die = FINALIZE_WORKER_ABANDONED;
795
omrthread_monitor_notify_all(workerData->monitor);
796
omrthread_monitor_exit(workerData->monitor);
797
798
return -2;
799
}
800
801
return workerWaitResult;
802
}
803
804
static UDATA
805
FinalizeWorkerThreadGlue(J9PortLibrary* portLib, void* userData)
806
{
807
return FinalizeWorkerThread(userData);
808
}
809
810
static int J9THREAD_PROC
811
gpProtectedFinalizeWorkerThread(void *entryArg)
812
{
813
struct finalizeWorkerData *workerData = (struct finalizeWorkerData *) entryArg;
814
PORT_ACCESS_FROM_PORT(workerData->vm->portLibrary);
815
UDATA rc;
816
817
j9sig_protect(FinalizeWorkerThreadGlue, workerData,
818
workerData->vm->internalVMFunctions->structuredSignalHandlerVM, workerData->vm,
819
J9PORT_SIG_FLAG_SIGALLSYNC | J9PORT_SIG_FLAG_MAY_CONTINUE_EXECUTION,
820
&rc);
821
822
return 0;
823
}
824
825
void
826
j9gc_finalizer_completeFinalizersOnExit(J9VMThread* vmThread)
827
{
828
J9JavaVM* vm = vmThread->javaVM;
829
830
/* If finalization has already been shut down, do nothing */
831
if (!J9_ARE_ALL_BITS_SET(vm->finalizeMainFlags, J9_FINALIZE_FLAGS_ACTIVE)) {
832
return;
833
}
834
835
/* Set the run finalizers on exit flag and initiate finalizer shutdown. */
836
omrthread_monitor_enter(vm->finalizeMainMonitor);
837
vm->finalizeMainFlags |= J9_FINALIZE_FLAGS_RUN_FINALIZERS_ON_EXIT;
838
if (!J9_ARE_ALL_BITS_SET(vm->finalizeMainFlags, J9_FINALIZE_FLAGS_SHUTDOWN)) {
839
vm->finalizeMainFlags |= J9_FINALIZE_FLAGS_SHUTDOWN;
840
omrthread_monitor_notify_all(vm->finalizeMainMonitor);
841
}
842
/* Is there an active worker thread? */
843
if (NULL != vm->finalizeWorkerData) {
844
struct finalizeWorkerData *workerData = (struct finalizeWorkerData*)vm->finalizeWorkerData;
845
if ((NULL != workerData) && (0 == workerData->finished)) {
846
/* An active worker thread exists (possibly the current thread).
847
* Abandon it so that a new worker can be created.
848
*/
849
omrthread_monitor_enter(workerData->monitor);
850
if (0 == workerData->finished) {
851
workerData->finished = 1;
852
workerData->die = FINALIZE_WORKER_SHOULD_ABANDON;
853
omrthread_monitor_notify_all(workerData->monitor);
854
}
855
omrthread_monitor_exit(workerData->monitor);
856
}
857
}
858
859
/* Now block until finalizer shutdown is complete */
860
omrthread_monitor_notify_all(vm->finalizeMainMonitor);
861
while (!(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_SHUTDOWN_COMPLETE)) {
862
omrthread_monitor_wait(vm->finalizeMainMonitor);
863
}
864
omrthread_monitor_exit(vm->finalizeMainMonitor);
865
}
866
867
int j9gc_finalizer_startup(J9JavaVM * vm)
868
{
869
IDATA result;
870
871
omrthread_monitor_enter(vm->finalizeMainMonitor);
872
873
result = vm->internalVMFunctions->createThreadWithCategory(
874
NULL,
875
vm->defaultOSStackSize,
876
MM_GCExtensions::getExtensions(vm)->finalizeMainPriority,
877
0,
878
&FinalizeMainThread,
879
vm,
880
J9THREAD_CATEGORY_SYSTEM_GC_THREAD);
881
882
if (0 != result) {
883
omrthread_monitor_exit(vm->finalizeMainMonitor);
884
return -1;
885
}
886
887
while (!(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_ACTIVE)) {
888
omrthread_monitor_wait(vm->finalizeMainMonitor);
889
}
890
omrthread_monitor_exit(vm->finalizeMainMonitor);
891
892
return 0;
893
}
894
895
/**
896
* Check if processing reference is active
897
*
898
* @param vm Pointer to the Java VM
899
* @return 1 if processing reference is active, otherwise return 0.
900
*/
901
UDATA j9gc_wait_for_reference_processing(J9JavaVM *vm)
902
{
903
UDATA ret = 0;
904
if (NULL != vm->processReferenceMonitor) {
905
omrthread_monitor_enter(vm->processReferenceMonitor);
906
if (0 != vm->processReferenceActive) {
907
omrthread_monitor_wait(vm->processReferenceMonitor);
908
ret = 1;
909
}
910
omrthread_monitor_exit(vm->processReferenceMonitor);
911
}
912
return ret;
913
}
914
915
/**
916
* Precondition: JVMTI must be in JVMTI_PHASE_DEAD
917
*/
918
void j9gc_finalizer_shutdown(J9JavaVM * vm)
919
{
920
J9VMThread *vmThread = vm->internalVMFunctions->currentVMThread(vm);
921
922
omrthread_monitor_enter(vm->finalizeMainMonitor);
923
if(!(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_SHUTDOWN)) {
924
if ( (vm->finalizeMainFlags & J9_FINALIZE_FLAGS_ACTIVE)
925
&& ( (vmThread && !(vmThread->privateFlags & J9_PRIVATE_FLAGS_FINALIZE_WORKER)) || !vmThread) ) {
926
bool waitForFinalizer = true;
927
struct finalizeWorkerData *workerData = (struct finalizeWorkerData*)vm->finalizeWorkerData;
928
929
vm->finalizeMainFlags |= J9_FINALIZE_FLAGS_SHUTDOWN;
930
omrthread_monitor_notify_all(vm->finalizeMainMonitor);
931
if ((NULL != workerData) && (NULL != workerData->vmThread)
932
&& J9_ARE_ANY_BITS_SET(workerData->vmThread->publicFlags, J9_PUBLIC_FLAGS_HALT_THREAD_JAVA_SUSPEND)) {
933
/*
934
* PR 87639 - don't wait for the finalizer if it has been suspended.
935
* This will cause jniinv:terminateRemainingThreads() to fail.
936
*/
937
waitForFinalizer = false;
938
}
939
if (waitForFinalizer) {
940
while (!(vm->finalizeMainFlags & J9_FINALIZE_FLAGS_SHUTDOWN_COMPLETE)) {
941
omrthread_monitor_wait(vm->finalizeMainMonitor);
942
}
943
}
944
}
945
}
946
omrthread_monitor_exit(vm->finalizeMainMonitor);
947
}
948
949
/**
950
* Called whenever a finalizeable object is created. Places the object on the unfinalized List.
951
* @param vmThread
952
* @param object The object to be finalized.
953
* @returns 0 if the object was successfully placed on the unfinalized list, UDATA_MAX otherwise.
954
*/
955
UDATA
956
finalizeObjectCreated(J9VMThread *vmThread, j9object_t object)
957
{
958
Trc_FinalizeSupport_finalizeObjectCreated_Entry(vmThread, object);
959
960
MM_EnvironmentBase *env = MM_EnvironmentBase::getEnvironment(vmThread->omrVMThread);
961
env->getGCEnvironment()->_unfinalizedObjectBuffer->add(env, object);
962
963
Trc_FinalizeSupport_finalizeObjectCreated_Exit(vmThread, 0);
964
return 0;
965
}
966
967
/**
968
* Must not hold VM access when calling runFinalization.
969
*/
970
void
971
runFinalization(J9VMThread *vmThread)
972
{
973
Trc_FinalizeSupport_runFinalization_Entry(vmThread);
974
J9JavaVM *jvm = vmThread->javaVM;
975
976
Assert_MM_mustNotHaveVMAccess(vmThread);
977
978
/* Bump the run finalizers count and signal the main finalize thread if necessary */
979
omrthread_monitor_enter(jvm->finalizeMainMonitor);
980
if ( 0 == jvm->finalizeRunFinalizationCount ) {
981
omrthread_monitor_notify_all(jvm->finalizeMainMonitor);
982
}
983
jvm->finalizeMainFlags |= J9_FINALIZE_FLAGS_RUN_FINALIZATION;
984
jvm->finalizeRunFinalizationCount += 1;
985
omrthread_monitor_exit(jvm->finalizeMainMonitor);
986
987
/* The main flags are checked without mutex protection, but no writes, so it's safe */
988
omrthread_monitor_enter(jvm->finalizeRunFinalizationMutex);
989
if ( 0 != (jvm->finalizeMainFlags & J9_FINALIZE_FLAGS_RUN_FINALIZATION) ) {
990
/* TODO: The 1000ms wait time arbitrary. This number should probably come from somewhere else. */
991
omrthread_monitor_wait_timed(jvm->finalizeRunFinalizationMutex,1000,0);
992
}
993
omrthread_monitor_exit(jvm->finalizeRunFinalizationMutex);
994
995
/* stop the run finalizers request and signal the main monitor if necessary */
996
omrthread_monitor_enter(jvm->finalizeMainMonitor);
997
jvm->finalizeRunFinalizationCount -= 1;
998
if ( 0 == jvm->finalizeRunFinalizationCount ) {
999
jvm->finalizeMainFlags &= ~((UDATA)J9_FINALIZE_FLAGS_RUN_FINALIZATION);
1000
omrthread_monitor_notify_all(jvm->finalizeMainMonitor);
1001
}
1002
omrthread_monitor_exit(jvm->finalizeMainMonitor);
1003
1004
Trc_FinalizeSupport_runFinalization_Exit(vmThread);
1005
}
1006
1007
#if defined(J9VM_GC_DYNAMIC_CLASS_UNLOADING)
1008
/**
1009
* Forcibly unloads the given class loader provided its gcFlags has the J9_GC_CLASS_LOADER_DEAD
1010
* bit set. Otherwise, calls runFinalization() and invoke the GC twice.
1011
* Assumptions: The current thread has the classLoaderBlocksMutex. Must not hold VM Access.
1012
*
1013
* @param vmThread
1014
* @param classLoader the class loader to forcibly unload
1015
* @return 0 on success if the class loader is unloaded, 1 if a failure occurred.
1016
*/
1017
UDATA
1018
forceClassLoaderUnload(J9VMThread *vmThread, J9ClassLoader *classLoader)
1019
{
1020
Trc_FinalizeSupport_forceClassLoaderUnload_Entry(vmThread,classLoader);
1021
UDATA result = 0;
1022
bool setForceFlag = false;
1023
J9JavaVM *jvm = vmThread->javaVM;
1024
1025
Assert_MM_mustNotHaveVMAccess(vmThread);
1026
1027
if ( 0 != (classLoader->gcFlags & J9_GC_CLASS_LOADER_DEAD) ) {
1028
if ( 0 == (classLoader->gcFlags & J9_GC_CLASS_LOADER_UNLOADING) ) {
1029
/* Class loader is not being unloaded but is eligible. Post the request and wait. */
1030
Trc_FinalizeSupport_forceClassLoaderUnload_classLoaderNotBeingUnloaded(vmThread,classLoader);
1031
setForceFlag = true;
1032
}
1033
/* The class loader is in the process of being unloaded.
1034
* Enqueue the thread for a response and wait
1035
*/
1036
if ( NULL == vmThread->gcClassUnloadingMutex ) {
1037
/* There's no signaling mutex for this thread yet, so allocate one */
1038
if ( 0 != omrthread_monitor_init(&vmThread->gcClassUnloadingMutex,0) ) {
1039
/* Failed to initialize the gcClassUnloadingMutex */
1040
Trc_FinalizeSupport_forceClassLoaderUnload_failedToInitializeClassUnloadingMutex(vmThread);
1041
result = 1;
1042
}
1043
}
1044
1045
if ( NULL != vmThread->gcClassUnloadingMutex ) {
1046
/* Link the thread into the notification list of the class loader */
1047
J9VMThread *tempNextThread = classLoader->gcThreadNotification;
1048
classLoader->gcThreadNotification = vmThread;
1049
vmThread->gcClassUnloadingThreadNext = tempNextThread;
1050
if ( NULL != tempNextThread ) {
1051
tempNextThread->gcClassUnloadingThreadPrevious = vmThread;
1052
}
1053
1054
/* If we need to signal the finalzer to force unloading a class loader, do so */
1055
if ( setForceFlag ) {
1056
omrthread_monitor_enter(jvm->finalizeMainMonitor);
1057
jvm->finalizeMainFlags |= J9_FINALIZE_FLAGS_FORCE_CLASS_LOADER_UNLOAD;
1058
jvm->finalizeForceClassLoaderUnloadCount += 1;
1059
omrthread_monitor_notify_all(jvm->finalizeMainMonitor);
1060
omrthread_monitor_exit(jvm->finalizeMainMonitor);
1061
}
1062
1063
/* Wait for notification that the class loader has finished unloading */
1064
omrthread_monitor_exit(jvm->classLoaderBlocksMutex);
1065
omrthread_monitor_enter(vmThread->gcClassUnloadingMutex);
1066
1067
IDATA waitResult = omrthread_monitor_wait_timed(vmThread->gcClassUnloadingMutex,5000,0);
1068
omrthread_monitor_exit(vmThread->gcClassUnloadingMutex);
1069
omrthread_monitor_enter(jvm->classLoaderBlocksMutex);
1070
1071
/* If force finalize flag was set, remove 1 from the count and clear the flag if necessary */
1072
if ( setForceFlag ) {
1073
omrthread_monitor_enter(jvm->finalizeMainMonitor);
1074
jvm->finalizeForceClassLoaderUnloadCount -= 1;
1075
if ( 0 == jvm->finalizeForceClassLoaderUnloadCount ) {
1076
jvm->finalizeMainFlags |= J9_FINALIZE_FLAGS_FORCE_CLASS_LOADER_UNLOAD;
1077
}
1078
omrthread_monitor_notify_all(jvm->finalizeMainMonitor);
1079
omrthread_monitor_exit(jvm->finalizeMainMonitor);
1080
}
1081
1082
if ( J9THREAD_TIMED_OUT == waitResult ) {
1083
/* Lock down the signalling mechanism. If we appear to be still linked up, it is safe to unlink
1084
* (the class loader mutex is still in our possession)
1085
*/
1086
Trc_FinalizeSupport_forceClassLoaderUnload_timedOut(vmThread,classLoader);
1087
omrthread_monitor_enter(vmThread->gcClassUnloadingMutex);
1088
if ( (NULL != vmThread->gcClassUnloadingThreadPrevious) || (NULL != vmThread->gcClassUnloadingThreadNext) ) {
1089
if (NULL == vmThread->gcClassUnloadingThreadPrevious) {
1090
classLoader->gcThreadNotification = vmThread->gcClassUnloadingThreadNext;
1091
} else {
1092
vmThread->gcClassUnloadingThreadPrevious->gcClassUnloadingThreadNext = vmThread->gcClassUnloadingThreadNext;
1093
}
1094
if (NULL != vmThread->gcClassUnloadingThreadNext) {
1095
vmThread->gcClassUnloadingThreadNext->gcClassUnloadingThreadPrevious = vmThread->gcClassUnloadingThreadPrevious;
1096
}
1097
vmThread->gcClassUnloadingThreadNext = NULL;
1098
vmThread->gcClassUnloadingThreadPrevious = NULL;
1099
}
1100
omrthread_monitor_exit(vmThread->gcClassUnloadingMutex);
1101
result = 1;
1102
}
1103
}
1104
} else {
1105
/** If the classLoader is not dead, run the GC aggressively to see if that causes the classLoader
1106
* to be marked as dead.
1107
*/
1108
Trc_FinalizeSupport_forceClassLoaderUnload_classLoaderNotDead(vmThread,classLoader);
1109
omrthread_monitor_exit(jvm->classLoaderBlocksMutex);
1110
runFinalization(vmThread);
1111
jvm->internalVMFunctions->internalEnterVMFromJNI(vmThread);
1112
j9gc_modron_global_collect(vmThread);
1113
jvm->internalVMFunctions->internalReleaseVMAccess(vmThread);
1114
runFinalization(vmThread);
1115
jvm->internalVMFunctions->internalEnterVMFromJNI(vmThread);
1116
j9gc_modron_global_collect(vmThread);
1117
jvm->internalVMFunctions->internalReleaseVMAccess(vmThread);
1118
omrthread_monitor_enter(jvm->classLoaderBlocksMutex);
1119
}
1120
1121
Trc_FinalizeSupport_forceClassLoaderUnload_Exit(vmThread,result);
1122
return result;
1123
}
1124
#endif /* J9VM_GC_DYNAMIC_CLASS_UNLOADING */
1125
1126
/**
1127
* Set a global flag which determines if finalizers are run on exit.
1128
* This is used to implement java.lang.Runtime.runFinalizersOnExit().
1129
*
1130
* @param vmThread[in] the current thread
1131
* @param run TRUE if finalizers should be run, false otherwise
1132
*/
1133
void
1134
j9gc_runFinalizersOnExit(J9VMThread* vmThread, UDATA run)
1135
{
1136
J9JavaVM* jvm = vmThread->javaVM;
1137
1138
omrthread_monitor_enter(jvm->finalizeMainMonitor);
1139
if (FALSE == run) {
1140
jvm->finalizeMainFlags &= ~(UDATA)J9_FINALIZE_FLAGS_RUN_FINALIZERS_ON_EXIT;
1141
} else {
1142
jvm->finalizeMainFlags |= (UDATA)J9_FINALIZE_FLAGS_RUN_FINALIZERS_ON_EXIT;
1143
}
1144
omrthread_monitor_exit(jvm->finalizeMainMonitor);
1145
}
1146
1147
#endif /* J9VM_GC_FINALIZATION */
1148
1149
} /* extern "C" */
1150
1151
1152