Skip to content

Commit eae55d4

Browse files
committed
Support restore with -XX:CRaCRestoreFrom=PATH
Support restore with -XX:CRaCRestoreFrom=PATH that specifies the path to the checkpoint image. Issue: eclipse-openj9/openj9#19261 Signed-off-by: Amarpreet Singh <[email protected]>
1 parent 35724ad commit eae55d4

File tree

1 file changed

+201
-1
lines changed
  • src/java.base/share/native/libjli

1 file changed

+201
-1
lines changed

src/java.base/share/native/libjli/java.c

Lines changed: 201 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
/*
2727
* ===========================================================================
28-
* (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved
28+
* (c) Copyright IBM Corp. 2022, 2024 All Rights Reserved
2929
* ===========================================================================
3030
*/
3131

@@ -58,9 +58,16 @@
5858

5959

6060
#include <assert.h>
61+
#if defined(J9VM_OPT_CRAC_SUPPORT)
62+
#include <ctype.h>
63+
#include <sys/wait.h>
64+
#endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
6165

6266
#include "java.h"
6367
#include "jni.h"
68+
#if defined(J9VM_OPT_CRAC_SUPPORT)
69+
#include "j9cfg.h"
70+
#endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
6471

6572
/*
6673
* A NOTE TO DEVELOPERS: For performance reasons it is important that
@@ -534,6 +541,195 @@ invokeInstanceMainWithoutArgs(JNIEnv *env, jclass mainClass) {
534541
return 1;
535542
}
536543

544+
#if defined(J9VM_OPT_CRAC_SUPPORT)
545+
static jboolean getCommandLineOptionValue(const char *optionName, int argc, char **argv, char **value) {
546+
*value = NULL;
547+
for (int i = 0; i < argc; i++) {
548+
char *arg = argv[i];
549+
if (0 == strncmp(arg, optionName, strlen(optionName))) {
550+
char *equals = strchr(arg, '=');
551+
if (NULL != equals) {
552+
int length = strlen(equals + 1);
553+
*value = (char *)JLI_MemAlloc(length + 1);
554+
if (NULL == value) {
555+
JLI_ReportErrorMessage(
556+
"Failed to allocate memory for the value of the command line option %s.",
557+
optionName);
558+
exit(EXIT_FAILURE);
559+
}
560+
snprintf(*value, length + 1, "%s", equals + 1);
561+
(*value)[length] = '\0';
562+
}
563+
return JNI_TRUE;
564+
}
565+
}
566+
return JNI_FALSE;
567+
}
568+
569+
static char *getCheckpointDir(int argc, char **argv) {
570+
char *checkpointDir = NULL;
571+
getCommandLineOptionValue("-XX:CRaCRestoreFrom", argc, argv, &checkpointDir);
572+
return checkpointDir;
573+
}
574+
575+
static char *getLogLevel(int argc, char **argv) {
576+
char *defaultLogLevel = strdup("-v2");
577+
const char *logLevelPropertyName = "-Dopenj9.internal.criu.logLevel";
578+
char *logLevelPropertyValue = NULL;
579+
if (NULL == defaultLogLevel) {
580+
JLI_ReportErrorMessage("Failed to allocate memory for the CRIU default log level.");
581+
exit(EXIT_FAILURE);
582+
}
583+
if (getCommandLineOptionValue(logLevelPropertyName, argc, argv, &logLevelPropertyValue)
584+
&& logLevelPropertyValue
585+
) {
586+
for (const char *c = logLevelPropertyValue; *c; c++) {
587+
if (!isdigit(*c)) {
588+
JLI_ReportErrorMessage(
589+
"The value %s of the command line option %s is not valid.",
590+
logLevelPropertyValue,
591+
logLevelPropertyName);
592+
JLI_MemFree(logLevelPropertyValue);
593+
logLevelPropertyValue = NULL;
594+
exit(EXIT_FAILURE);
595+
}
596+
}
597+
int logLevelValue = atoi(logLevelPropertyValue);
598+
if (logLevelValue >= 0 && logLevelValue <= 4) {
599+
/* The format of the logLevel string is "-vX". */
600+
char *logLevel = (char *)JLI_MemAlloc(4);
601+
if (NULL == logLevel) {
602+
JLI_MemFree(defaultLogLevel);
603+
defaultLogLevel = NULL;
604+
JLI_MemFree(logLevelPropertyValue);
605+
logLevelPropertyValue = NULL;
606+
exit(EXIT_FAILURE);
607+
}
608+
snprintf(logLevel, 4, "-v%d", logLevelValue);
609+
JLI_MemFree(logLevelPropertyValue);
610+
logLevelPropertyValue = NULL;
611+
return logLevel;
612+
}
613+
}
614+
if (logLevelPropertyValue) {
615+
JLI_MemFree(logLevelPropertyValue);
616+
logLevelPropertyValue = NULL;
617+
}
618+
return defaultLogLevel;
619+
}
620+
621+
static char *getUnprivilegedMode(int argc, char **argv) {
622+
const char *unprivilegedModePropertyName = "-Dopenj9.internal.criu.unprivilegedMode";
623+
char *unprivilegedModePropertyValue = NULL;
624+
if (getCommandLineOptionValue(unprivilegedModePropertyName, argc, argv, &unprivilegedModePropertyValue)) {
625+
if (unprivilegedModePropertyValue) {
626+
JLI_ReportErrorMessage(
627+
"The value %s of the command line option %s is not expected.",
628+
unprivilegedModePropertyValue,
629+
unprivilegedModePropertyName);
630+
JLI_MemFree(unprivilegedModePropertyValue);
631+
unprivilegedModePropertyValue = NULL;
632+
exit(EXIT_FAILURE);
633+
}
634+
return strdup("--unprivileged");
635+
}
636+
return NULL;
637+
}
638+
639+
static char *getLogFile(int argc, char **argv) {
640+
char *logFilePropertyValue = NULL;
641+
if (getCommandLineOptionValue("-Dopenj9.internal.criu.logFile", argc, argv, &logFilePropertyValue)
642+
&& logFilePropertyValue
643+
) {
644+
int bufferSize = snprintf(NULL, 0, "--log-file=%s", logFilePropertyValue) + 1;
645+
char *logFileOption = (char *)JLI_MemAlloc(bufferSize);
646+
if (logFileOption == NULL) {
647+
JLI_ReportErrorMessage("Failed to allocate memory for the CRIU log file option.");
648+
exit(EXIT_FAILURE);
649+
}
650+
snprintf(logFileOption, bufferSize, "--log-file=%s", logFilePropertyValue);
651+
JLI_MemFree(logFilePropertyValue);
652+
logFilePropertyValue = NULL;
653+
return logFileOption;
654+
}
655+
if (logFilePropertyValue) {
656+
JLI_MemFree(logFilePropertyValue);
657+
logFilePropertyValue = NULL;
658+
}
659+
return NULL;
660+
}
661+
662+
static int restoreFromCheckpoint(char *checkpointDir, char *logLevel, char *unprivilegedMode, char *logFile) {
663+
int argc = 6;
664+
char *argv[9] = { NULL };
665+
argv[0] = "criu";
666+
argv[1] = "restore";
667+
argv[2] = "-D";
668+
argv[3] = checkpointDir;
669+
argv[4] = logLevel;
670+
argv[5] = "--shell-job";
671+
if (unprivilegedMode) {
672+
argv[argc++] = unprivilegedMode;
673+
}
674+
if (logFile) {
675+
argv[argc++] = logFile;
676+
}
677+
argv[argc] = NULL;
678+
if (-1 == execvp(argv[0], argv)) {
679+
return -1;
680+
}
681+
return 0;
682+
}
683+
684+
static void handleCRaCRestore(int argc, char **argv) {
685+
char *checkpointDir = getCheckpointDir(argc, argv);
686+
if (checkpointDir) {
687+
/*
688+
* The if block will be invoked by the child process,
689+
* and the else block will be invoked by the parent process.
690+
*/
691+
pid_t criuRestorePid = fork();
692+
if (0 == criuRestorePid) {
693+
char *logLevel = getLogLevel(argc, argv);
694+
char *unprivilegedMode = getUnprivilegedMode(argc, argv);
695+
char *logFile = getLogFile(argc, argv);
696+
int restoreResult = restoreFromCheckpoint(checkpointDir, logLevel, unprivilegedMode, logFile);
697+
if (NULL != logLevel) {
698+
JLI_MemFree(logLevel);
699+
logLevel = NULL;
700+
}
701+
if (NULL != unprivilegedMode) {
702+
JLI_MemFree(unprivilegedMode);
703+
unprivilegedMode = NULL;
704+
}
705+
if (NULL != logFile) {
706+
JLI_MemFree(logFile);
707+
logFile = NULL;
708+
}
709+
exit(restoreResult);
710+
} else {
711+
int exitStatus = EXIT_SUCCESS;
712+
int criuRestorePidStatus = 0;
713+
waitpid(criuRestorePid, &criuRestorePidStatus, 0);
714+
if (WIFEXITED(criuRestorePidStatus)) {
715+
if (0 != WEXITSTATUS(criuRestorePidStatus)) {
716+
JLI_ReportErrorMessage("Failed to restore from checkpoint.");
717+
exitStatus = EXIT_FAILURE;
718+
}
719+
} else {
720+
JLI_ReportErrorMessage("The CRIU restore child process failed.");
721+
exitStatus = EXIT_FAILURE;
722+
}
723+
if (NULL != checkpointDir) {
724+
JLI_MemFree(checkpointDir);
725+
checkpointDir = NULL;
726+
}
727+
exit(exitStatus);
728+
}
729+
}
730+
}
731+
#endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
732+
537733
int
538734
JavaMain(void* _args)
539735
{
@@ -554,6 +750,10 @@ JavaMain(void* _args)
554750

555751
RegisterThread();
556752

753+
#if defined(J9VM_OPT_CRAC_SUPPORT)
754+
handleCRaCRestore(argc, argv);
755+
#endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
756+
557757
/* Initialize the virtual machine */
558758
start = CurrentTimeMicros();
559759
if (!InitializeJVM(&vm, &env, &ifn)) {

0 commit comments

Comments
 (0)