25
25
26
26
/*
27
27
* ===========================================================================
28
- * (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved
28
+ * (c) Copyright IBM Corp. 2022, 2024 All Rights Reserved
29
29
* ===========================================================================
30
30
*/
31
31
58
58
59
59
60
60
#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) */
61
65
62
66
#include "java.h"
63
67
#include "jni.h"
68
+ #if defined(J9VM_OPT_CRAC_SUPPORT )
69
+ #include "j9cfg.h"
70
+ #endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
64
71
65
72
/*
66
73
* A NOTE TO DEVELOPERS: For performance reasons it is important that
@@ -534,6 +541,195 @@ invokeInstanceMainWithoutArgs(JNIEnv *env, jclass mainClass) {
534
541
return 1 ;
535
542
}
536
543
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
+
537
733
int
538
734
JavaMain (void * _args )
539
735
{
@@ -554,6 +750,10 @@ JavaMain(void* _args)
554
750
555
751
RegisterThread ();
556
752
753
+ #if defined(J9VM_OPT_CRAC_SUPPORT )
754
+ handleCRaCRestore (argc , argv );
755
+ #endif /* defined(J9VM_OPT_CRAC_SUPPORT) */
756
+
557
757
/* Initialize the virtual machine */
558
758
start = CurrentTimeMicros ();
559
759
if (!InitializeJVM (& vm , & env , & ifn )) {
0 commit comments