Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/criusupport/criusupport.cpp
5985 views
1
/*******************************************************************************
2
* Copyright (c) 2021, 2022 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
#if defined(LINUX)
23
#include <criu/criu.h>
24
#include <fcntl.h>
25
#include <errno.h>
26
#endif /* defined(LINUX) */
27
28
#include "criusupport.hpp"
29
30
#include "jni.h"
31
#include "j9.h"
32
#include "j9jclnls.h"
33
#include "ut_j9criu.h"
34
#include "omrlinkedlist.h"
35
#include "omrthread.h"
36
37
extern "C" {
38
39
#define STRING_BUFFER_SIZE 256
40
41
static void
42
setupJNIFieldIDs(JNIEnv *env)
43
{
44
J9VMThread *currentThread = (J9VMThread*)env;
45
J9JavaVM *vm = currentThread->javaVM;
46
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
47
jclass criuJVMCheckpointExceptionClass = NULL;
48
jclass criuSystemCheckpointExceptionClass = NULL;
49
jclass criuRestoreExceptionClass = NULL;
50
51
criuJVMCheckpointExceptionClass = env->FindClass("org/eclipse/openj9/criu/JVMCheckpointException");
52
Assert_CRIU_notNull(criuJVMCheckpointExceptionClass);
53
vm->criuJVMCheckpointExceptionClass = (jclass) env->NewGlobalRef(criuJVMCheckpointExceptionClass);
54
55
vm->criuJVMCheckpointExceptionInit = env->GetMethodID(criuJVMCheckpointExceptionClass, "<init>", "(Ljava/lang/String;I)V");
56
Assert_CRIU_notNull(vm->criuJVMCheckpointExceptionInit);
57
58
criuSystemCheckpointExceptionClass = env->FindClass("org/eclipse/openj9/criu/SystemCheckpointException");
59
Assert_CRIU_notNull(criuSystemCheckpointExceptionClass);
60
vm->criuSystemCheckpointExceptionClass = (jclass) env->NewGlobalRef(criuSystemCheckpointExceptionClass);
61
62
vm->criuSystemCheckpointExceptionInit = env->GetMethodID(criuSystemCheckpointExceptionClass, "<init>", "(Ljava/lang/String;I)V");
63
Assert_CRIU_notNull(vm->criuSystemCheckpointExceptionInit);
64
65
criuRestoreExceptionClass = env->FindClass("org/eclipse/openj9/criu/RestoreException");
66
Assert_CRIU_notNull(criuRestoreExceptionClass);
67
vm->criuRestoreExceptionClass = (jclass) env->NewGlobalRef(criuRestoreExceptionClass);
68
69
vm->criuRestoreExceptionInit = env->GetMethodID(criuRestoreExceptionClass, "<init>", "(Ljava/lang/String;I)V");
70
Assert_CRIU_notNull(vm->criuRestoreExceptionInit);
71
72
if (NULL == vm->criuJVMCheckpointExceptionClass
73
|| NULL == vm->criuSystemCheckpointExceptionClass
74
|| NULL == vm->criuRestoreExceptionClass
75
) {
76
vmFuncs->internalEnterVMFromJNI(currentThread);
77
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
78
vmFuncs->internalExitVMToJNI(currentThread);
79
}
80
}
81
82
jboolean JNICALL
83
Java_org_eclipse_openj9_criu_CRIUSupport_isCRIUSupportEnabledImpl(JNIEnv *env, jclass unused)
84
{
85
J9VMThread *currentThread = (J9VMThread *) env;
86
J9JavaVM *vm = currentThread->javaVM;
87
jboolean res = JNI_FALSE;
88
89
UT_MODULE_LOADED(J9_UTINTERFACE_FROM_VM(vm));
90
if (vm->internalVMFunctions->isCRIUSupportEnabled(currentThread)) {
91
#if defined(LINUX)
92
if (0 == criu_init_opts()) {
93
res = JNI_TRUE;
94
}
95
#endif /* defined(LINUX) */
96
}
97
setupJNIFieldIDs(env);
98
99
return res;
100
}
101
102
jboolean JNICALL
103
Java_org_eclipse_openj9_criu_CRIUSupport_isCheckpointAllowed(JNIEnv *env, jclass unused)
104
{
105
J9VMThread *currentThread = (J9VMThread *) env;
106
jboolean res = JNI_FALSE;
107
108
if (currentThread->javaVM->internalVMFunctions->isCheckpointAllowed(currentThread)) {
109
res = JNI_TRUE;
110
}
111
112
return res;
113
}
114
115
#define J9_NATIVE_STRING_NO_ERROR 0
116
#define J9_NATIVE_STRING_OUT_OF_MEMORY (-1)
117
#define J9_NATIVE_STRING_FAIL_TO_CONVERT (-2)
118
119
/**
120
* Converts the given java string to native representation. The nativeString parameter should point
121
* to a buffer with its size specified by nativeStringBufSize. If the java string length exceeds the buffer
122
* size, nativeString will be set to allocated memory.
123
*
124
* @note If successful, the caller is responsible for freeing any memory allocated and stored in nativeString.
125
*
126
* @param[in] currentThread current thread
127
* @param[in] javaString java string object
128
* @param[out] nativeString the native representation of the java string
129
* @param[in] nativeStringBufSize size of the nativeString buffer
130
*
131
* @return return code indicating success, allocation failure, or string conversion failure
132
*/
133
static IDATA
134
getNativeString(J9VMThread *currentThread, j9object_t javaString, char **nativeString, IDATA nativeStringBufSize)
135
{
136
J9JavaVM *vm = currentThread->javaVM;
137
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
138
char mutf8StringBuf[STRING_BUFFER_SIZE];
139
char *mutf8String = NULL;
140
UDATA mutf8StringSize = 0;
141
IDATA requiredConvertedStringSize = 0;
142
char *localNativeString = *nativeString;
143
IDATA res = J9_NATIVE_STRING_NO_ERROR;
144
PORT_ACCESS_FROM_VMC(currentThread);
145
OMRPORT_ACCESS_FROM_J9PORT(PORTLIB);
146
147
mutf8String = vmFuncs->copyStringToUTF8WithMemAlloc(currentThread, javaString, J9_STR_NULL_TERMINATE_RESULT, "", 0, mutf8StringBuf, STRING_BUFFER_SIZE, &mutf8StringSize);
148
if (NULL == mutf8String) {
149
res = J9_NATIVE_STRING_OUT_OF_MEMORY;
150
goto free;
151
}
152
153
/* get the required size */
154
requiredConvertedStringSize = omrstr_convert(J9STR_CODE_MUTF8, J9STR_CODE_PLATFORM_RAW,
155
mutf8String,
156
mutf8StringSize,
157
localNativeString,
158
0);
159
160
if (requiredConvertedStringSize < 0) {
161
Trc_CRIU_getNativeString_getStringSizeFail(currentThread, mutf8String, mutf8StringSize);
162
res = J9_NATIVE_STRING_FAIL_TO_CONVERT;
163
goto free;
164
}
165
166
/* Add 1 for NUL terminator */
167
requiredConvertedStringSize += 1;
168
169
if (requiredConvertedStringSize > nativeStringBufSize) {
170
localNativeString = (char*) j9mem_allocate_memory(requiredConvertedStringSize, OMRMEM_CATEGORY_VM);
171
if (NULL == localNativeString) {
172
res = J9_NATIVE_STRING_OUT_OF_MEMORY;
173
goto free;
174
}
175
}
176
177
localNativeString[requiredConvertedStringSize - 1] = '\0';
178
179
/* convert the string */
180
requiredConvertedStringSize = omrstr_convert(J9STR_CODE_MUTF8, J9STR_CODE_PLATFORM_RAW,
181
mutf8String,
182
mutf8StringSize,
183
localNativeString,
184
requiredConvertedStringSize);
185
186
if (requiredConvertedStringSize < 0) {
187
Trc_CRIU_getNativeString_convertFail(currentThread, mutf8String, mutf8StringSize, requiredConvertedStringSize);
188
res = J9_NATIVE_STRING_FAIL_TO_CONVERT;
189
goto free;
190
}
191
192
free:
193
if (mutf8String != mutf8StringBuf) {
194
j9mem_free_memory(mutf8String);
195
}
196
if (localNativeString != *nativeString) {
197
if (J9_NATIVE_STRING_NO_ERROR == res) {
198
*nativeString = localNativeString;
199
} else {
200
j9mem_free_memory(localNativeString);
201
localNativeString = NULL;
202
}
203
}
204
205
return res;
206
}
207
208
/**
209
* Caller must first acquire exclusive VMAccess
210
*/
211
static void
212
toggleSuspendOnJavaThreads(J9VMThread *currentThread, BOOLEAN suspend)
213
{
214
J9JavaVM *vm = currentThread->javaVM;
215
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
216
UDATA javaThreads = J9THREAD_CATEGORY_RESOURCE_MONITOR_THREAD | J9THREAD_CATEGORY_APPLICATION_THREAD;
217
J9VMThread *walkThread = J9_LINKED_LIST_START_DO(vm->mainThread);
218
219
Assert_CRIU_true(J9_XACCESS_EXCLUSIVE == vm->exclusiveAccessState);
220
221
while (NULL != walkThread) {
222
if (J9_ARE_ANY_BITS_SET(javaThreads, omrthread_get_category(walkThread->osThread))
223
&& (currentThread != walkThread)
224
) {
225
if (suspend) {
226
vmFuncs->setHaltFlag(walkThread, J9_PUBLIC_FLAGS_HALT_THREAD_FOR_CHECKPOINT);
227
} else {
228
vmFuncs->clearHaltFlag(walkThread, J9_PUBLIC_FLAGS_HALT_THREAD_FOR_CHECKPOINT);
229
}
230
}
231
walkThread = J9_LINKED_LIST_NEXT_DO(vm->mainThread, walkThread);
232
}
233
}
234
235
void JNICALL
236
Java_org_eclipse_openj9_criu_CRIUSupport_checkpointJVMImpl(JNIEnv *env,
237
jclass unused,
238
jstring imagesDir,
239
jboolean leaveRunning,
240
jboolean shellJob,
241
jboolean extUnixSupport,
242
jint logLevel,
243
jstring logFile,
244
jboolean fileLocks,
245
jstring workDir,
246
jboolean tcpEstablished,
247
jboolean autoDedup,
248
jboolean trackMemory)
249
{
250
J9VMThread *currentThread = (J9VMThread*)env;
251
J9JavaVM *vm = currentThread->javaVM;
252
J9InternalVMFunctions *vmFuncs = vm->internalVMFunctions;
253
254
jclass currentExceptionClass = NULL;
255
char *exceptionMsg = NULL;
256
const char *nlsMsgFormat = NULL;
257
UDATA msgCharLength = 0;
258
IDATA systemReturnCode = 0;
259
PORT_ACCESS_FROM_VMC(currentThread);
260
261
Trc_CRIU_checkpointJVMImpl_Entry(currentThread);
262
if (vmFuncs->isCheckpointAllowed(currentThread)) {
263
#if defined(LINUX)
264
j9object_t cpDir = NULL;
265
j9object_t log = NULL;
266
j9object_t wrkDir = NULL;
267
IDATA dirFD = 0;
268
IDATA workDirFD = 0;
269
char directoryBuf[STRING_BUFFER_SIZE];
270
char *directoryChars = directoryBuf;
271
char logFileBuf[STRING_BUFFER_SIZE];
272
char *logFileChars = logFileBuf;
273
char workDirBuf[STRING_BUFFER_SIZE];
274
char *workDirChars = workDirBuf;
275
BOOLEAN isAfterCheckpoint = FALSE;
276
277
vmFuncs->internalEnterVMFromJNI(currentThread);
278
279
Assert_CRIU_notNull(imagesDir);
280
cpDir = J9_JNI_UNWRAP_REFERENCE(imagesDir);
281
systemReturnCode = getNativeString(currentThread, cpDir, &directoryChars, STRING_BUFFER_SIZE);
282
switch (systemReturnCode) {
283
case J9_NATIVE_STRING_NO_ERROR:
284
break;
285
case J9_NATIVE_STRING_OUT_OF_MEMORY:
286
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
287
goto freeDir;
288
case J9_NATIVE_STRING_FAIL_TO_CONVERT:
289
currentExceptionClass = vm->criuJVMCheckpointExceptionClass;
290
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_FAILED_TO_CONVERT_JAVA_STRING, NULL);
291
goto freeDir;
292
}
293
294
if (NULL != logFile) {
295
log = J9_JNI_UNWRAP_REFERENCE(logFile);
296
systemReturnCode = getNativeString(currentThread, log, &logFileChars, STRING_BUFFER_SIZE);
297
switch (systemReturnCode) {
298
case J9_NATIVE_STRING_NO_ERROR:
299
break;
300
case J9_NATIVE_STRING_OUT_OF_MEMORY:
301
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
302
goto freeLog;
303
case J9_NATIVE_STRING_FAIL_TO_CONVERT:
304
currentExceptionClass = vm->criuJVMCheckpointExceptionClass;
305
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_FAILED_TO_CONVERT_JAVA_STRING, NULL);
306
goto freeLog;
307
}
308
}
309
310
if (NULL != workDir) {
311
wrkDir = J9_JNI_UNWRAP_REFERENCE(workDir);
312
systemReturnCode = getNativeString(currentThread, wrkDir, &workDirChars, STRING_BUFFER_SIZE);
313
switch (systemReturnCode) {
314
case J9_NATIVE_STRING_NO_ERROR:
315
break;
316
case J9_NATIVE_STRING_OUT_OF_MEMORY:
317
vmFuncs->setNativeOutOfMemoryError(currentThread, 0, 0);
318
goto freeWorkDir;
319
case J9_NATIVE_STRING_FAIL_TO_CONVERT:
320
currentExceptionClass = vm->criuJVMCheckpointExceptionClass;
321
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_FAILED_TO_CONVERT_JAVA_STRING, NULL);
322
goto freeWorkDir;
323
}
324
}
325
326
dirFD = open(directoryChars, O_DIRECTORY);
327
if (dirFD < 0) {
328
systemReturnCode = errno;
329
currentExceptionClass = vm->criuJVMCheckpointExceptionClass;
330
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_FAILED_TO_OPEN_DIR, NULL);
331
goto freeWorkDir;
332
}
333
334
if (NULL != workDir) {
335
workDirFD = open(workDirChars, O_DIRECTORY);
336
if (workDirFD < 0) {
337
systemReturnCode = errno;
338
currentExceptionClass = vm->criuJVMCheckpointExceptionClass;
339
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_FAILED_TO_OPEN_WORK_DIR, NULL);
340
goto closeDirFD;
341
}
342
}
343
344
systemReturnCode = criu_init_opts();
345
if (0 != systemReturnCode) {
346
currentExceptionClass = vm->criuSystemCheckpointExceptionClass;
347
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_INIT_FAILED, NULL);
348
goto closeWorkDirFD;
349
}
350
351
criu_set_images_dir_fd(dirFD);
352
criu_set_shell_job(JNI_FALSE != shellJob);
353
if (logLevel > 0) {
354
criu_set_log_level((int)logLevel);
355
}
356
if (NULL != logFile) {
357
criu_set_log_file(logFileChars);
358
}
359
criu_set_leave_running(JNI_FALSE != leaveRunning);
360
criu_set_ext_unix_sk(JNI_FALSE != extUnixSupport);
361
criu_set_file_locks(JNI_FALSE != fileLocks);
362
criu_set_tcp_established(JNI_FALSE != tcpEstablished);
363
criu_set_auto_dedup(JNI_FALSE != autoDedup);
364
criu_set_track_mem(JNI_FALSE != trackMemory);
365
366
if (NULL != workDir) {
367
criu_set_work_dir_fd(workDirFD);
368
}
369
370
vmFuncs->acquireExclusiveVMAccess(currentThread);
371
372
toggleSuspendOnJavaThreads(currentThread, TRUE);
373
374
vmFuncs->releaseExclusiveVMAccess(currentThread);
375
376
if (FALSE == vmFuncs->jvmCheckpointHooks(currentThread)) {
377
/* throw the pending exception */
378
goto wakeJavaThreads;
379
}
380
381
vmFuncs->acquireExclusiveVMAccess(currentThread);
382
383
/* Run internal checkpoint hooks, after iterating heap objects */
384
if (FALSE == vmFuncs->runInternalJVMCheckpointHooks(currentThread)) {
385
currentExceptionClass = vm->criuSystemCheckpointExceptionClass;
386
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE,
387
J9NLS_JCL_CRIU_FAILED_TO_RUN_INTERNAL_CHECKPOINT_HOOKS, NULL);
388
goto wakeJavaThreadsWithExclusiveVMAccess;
389
}
390
391
Trc_CRIU_before_checkpoint(currentThread);
392
systemReturnCode = criu_dump();
393
Trc_CRIU_after_checkpoint(currentThread);
394
if (systemReturnCode < 0) {
395
currentExceptionClass = vm->criuSystemCheckpointExceptionClass;
396
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_DUMP_FAILED, NULL);
397
goto wakeJavaThreadsWithExclusiveVMAccess;
398
}
399
400
/* We can only end up here if the CRIU restore was successful */
401
isAfterCheckpoint = TRUE;
402
403
/* Run internal restore hooks, and cleanup */
404
if (FALSE == vmFuncs->runInternalJVMRestoreHooks(currentThread)) {
405
currentExceptionClass = vm->criuRestoreExceptionClass;
406
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE,
407
J9NLS_JCL_CRIU_FAILED_TO_RUN_INTERNAL_RESTORE_HOOKS, NULL);
408
goto wakeJavaThreadsWithExclusiveVMAccess;
409
}
410
411
vmFuncs->releaseExclusiveVMAccess(currentThread);
412
413
if (FALSE == vmFuncs->jvmRestoreHooks(currentThread)) {
414
/* throw the pending exception */
415
goto wakeJavaThreads;
416
}
417
418
wakeJavaThreads:
419
vmFuncs->acquireExclusiveVMAccess(currentThread);
420
421
wakeJavaThreadsWithExclusiveVMAccess:
422
toggleSuspendOnJavaThreads(currentThread, FALSE);
423
424
vmFuncs->releaseExclusiveVMAccess(currentThread);
425
closeWorkDirFD:
426
if ((0 != close(workDirFD)) && (NULL == currentExceptionClass)) {
427
systemReturnCode = errno;
428
if (isAfterCheckpoint) {
429
currentExceptionClass = vm->criuRestoreExceptionClass;
430
} else {
431
currentExceptionClass = vm->criuSystemCheckpointExceptionClass;
432
}
433
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_FAILED_TO_CLOSE_WORK_DIR, NULL);
434
}
435
closeDirFD:
436
if ((0 != close(dirFD)) && (NULL == currentExceptionClass)) {
437
systemReturnCode = errno;
438
if (isAfterCheckpoint) {
439
currentExceptionClass = vm->criuRestoreExceptionClass;
440
} else {
441
currentExceptionClass = vm->criuSystemCheckpointExceptionClass;
442
}
443
nlsMsgFormat = j9nls_lookup_message(J9NLS_DO_NOT_PRINT_MESSAGE_TAG | J9NLS_DO_NOT_APPEND_NEWLINE, J9NLS_JCL_CRIU_FAILED_TO_CLOSE_DIR, NULL);
444
}
445
freeWorkDir:
446
if (workDirBuf != workDirChars) {
447
j9mem_free_memory(workDirChars);
448
}
449
freeLog:
450
if (logFileBuf != logFileChars) {
451
j9mem_free_memory(logFileChars);
452
}
453
freeDir:
454
if (directoryBuf != directoryChars) {
455
j9mem_free_memory(directoryChars);
456
}
457
458
vmFuncs->internalExitVMToJNI(currentThread);
459
#endif /* defined(LINUX) */
460
}
461
462
/*
463
* Pending exceptions will be set by the JVM hooks, these exception will take precedence.
464
*/
465
if ((NULL != currentExceptionClass) && (NULL == currentThread->currentException)) {
466
msgCharLength = j9str_printf(PORTLIB, NULL, 0, nlsMsgFormat, systemReturnCode);
467
exceptionMsg = (char*) j9mem_allocate_memory(msgCharLength, J9MEM_CATEGORY_VM);
468
469
j9str_printf(PORTLIB, exceptionMsg, msgCharLength, nlsMsgFormat, systemReturnCode);
470
471
jmethodID init = NULL;
472
if (vm->criuJVMCheckpointExceptionClass == currentExceptionClass) {
473
init = vm->criuJVMCheckpointExceptionInit;
474
} else if (vm->criuSystemCheckpointExceptionClass == currentExceptionClass) {
475
init = vm->criuSystemCheckpointExceptionInit;
476
} else {
477
init = vm->criuRestoreExceptionInit;
478
}
479
jstring jExceptionMsg = env->NewStringUTF(exceptionMsg);
480
481
if (JNI_FALSE == env->ExceptionCheck()) {
482
jobject exception = env->NewObject(currentExceptionClass, init, jExceptionMsg, (jint)systemReturnCode);
483
if (NULL != exception) {
484
env->Throw((jthrowable)exception);
485
}
486
}
487
488
if (NULL != exceptionMsg) {
489
j9mem_free_memory(exceptionMsg);
490
}
491
}
492
493
Trc_CRIU_checkpointJVMImpl_Exit(currentThread);
494
}
495
496
} /* extern "C" */
497
498