@@ -147,7 +147,7 @@ class CracRestoreParameters : public CHeapObj<mtInternal> {
147147
148148 struct header {
149149 jlong _restore_time;
150- jlong _restore_counter ;
150+ jlong _restore_nanos ;
151151 int _nflags;
152152 int _nprops;
153153 int _env_memory_size;
@@ -205,10 +205,10 @@ class CracRestoreParameters : public CHeapObj<mtInternal> {
205205 const SystemProperty* props,
206206 const char *args,
207207 jlong restore_time,
208- jlong restore_counter ) {
208+ jlong restore_nanos ) {
209209 header hdr = {
210210 restore_time,
211- restore_counter ,
211+ restore_nanos ,
212212 num_flags,
213213 system_props_length (props),
214214 env_vars_size (environ)
@@ -295,9 +295,17 @@ static char* _crengine_arg_str = NULL;
295295static unsigned int _crengine_argc = 0 ;
296296static const char * _crengine_args[32 ];
297297static jlong _restore_start_time;
298- static jlong _restore_start_counter ;
298+ static jlong _restore_start_nanos ;
299299static FdsInfo _vm_inited_fds (false );
300300
301+ // Timestamps recorded before checkpoint
302+ jlong crac::checkpoint_millis;
303+ jlong crac::checkpoint_nanos;
304+ char crac::checkpoint_bootid[UUID_LENGTH];
305+ // Value based on wall clock time difference that will guarantee monotonic
306+ // System.nanoTime() close to actual wall-clock time difference.
307+ jlong crac::javaTimeNanos_offset = 0 ;
308+
301309jlong crac::restore_start_time () {
302310 if (!_restore_start_time) {
303311 return -1 ;
@@ -306,10 +314,10 @@ jlong crac::restore_start_time() {
306314}
307315
308316jlong crac::uptime_since_restore () {
309- if (!_restore_start_counter ) {
317+ if (!_restore_start_nanos ) {
310318 return -1 ;
311319 }
312- return os::javaTimeNanos () - _restore_start_counter ;
320+ return os::javaTimeNanos () - _restore_start_nanos ;
313321}
314322
315323void VM_Crac::trace_cr (const char * msg, ...) {
@@ -600,6 +608,7 @@ class CracSHM {
600608};
601609
602610static int checkpoint_restore (int *shmid) {
611+ crac::record_time_before_checkpoint ();
603612
604613 int cres = call_crengine ();
605614 if (cres < 0 ) {
@@ -617,6 +626,8 @@ static int checkpoint_restore(int *shmid) {
617626 } while (sig == -1 && errno == EINTR);
618627 assert (sig == RESTORE_SIGNAL, " got what requested" );
619628
629+ crac::update_javaTimeNanos_offset ();
630+
620631 if (CRTraceStartupTime) {
621632 tty->print_cr (" STARTUPTIME " JLONG_FORMAT " restore-native" , os::javaTimeNanos ());
622633 }
@@ -788,7 +799,9 @@ void VM_Crac::doit() {
788799
789800 if (shmid <= 0 || !VM_Crac::read_shm (shmid)) {
790801 _restore_start_time = os::javaTimeMillis ();
791- _restore_start_counter = os::javaTimeNanos ();
802+ _restore_start_nanos = os::javaTimeNanos ();
803+ } else {
804+ _restore_start_nanos += crac::monotonic_time_offset ();
792805 }
793806 PerfMemoryLinux::restore ();
794807
@@ -892,7 +905,7 @@ void crac::restore() {
892905 struct stat st;
893906
894907 jlong restore_time = os::javaTimeMillis ();
895- jlong restore_counter = os::javaTimeNanos ();
908+ jlong restore_nanos = os::javaTimeNanos ();
896909
897910 compute_crengine ();
898911
@@ -906,7 +919,7 @@ void crac::restore() {
906919 Arguments::system_properties (),
907920 Arguments::java_command () ? Arguments::java_command () : " " ,
908921 restore_time,
909- restore_counter )) {
922+ restore_nanos )) {
910923 char strid[32 ];
911924 snprintf (strid, sizeof (strid), " %d" , id);
912925 setenv (" CRAC_NEW_ARGS_ID" , strid, true );
@@ -1008,7 +1021,7 @@ bool CracRestoreParameters::read_from(int fd) {
10081021 char * cursor = _raw_content + sizeof (header);
10091022
10101023 ::_restore_start_time = hdr->_restore_time ;
1011- ::_restore_start_counter = hdr->_restore_counter ;
1024+ ::_restore_start_nanos = hdr->_restore_nanos ;
10121025
10131026 for (int i = 0 ; i < hdr->_nflags ; i++) {
10141027 FormatBuffer<80 > err_msg (" %s" , " " );
@@ -1057,3 +1070,77 @@ bool CracRestoreParameters::read_from(int fd) {
10571070 _args = cursor;
10581071 return true ;
10591072}
1073+
1074+ void crac::record_time_before_checkpoint () {
1075+ checkpoint_millis = os::javaTimeMillis ();
1076+ checkpoint_nanos = os::javaTimeNanos ();
1077+ memset (checkpoint_bootid, 0 , UUID_LENGTH);
1078+ read_bootid (checkpoint_bootid);
1079+ }
1080+
1081+ void crac::update_javaTimeNanos_offset () {
1082+ char buf[UUID_LENGTH];
1083+ // We will change the nanotime offset only if this is not the same boot
1084+ // to prevent reducing the accuracy of System.nanoTime() unnecessarily.
1085+ // It is possible that in a real-world case the boot_id does not change
1086+ // (containers keep the boot_id) - but the monotonic time changes. We will
1087+ // only guarantee that the nanotime does not go backwards in that case but
1088+ // won't offset the time based on wall-clock time as this change in monotonic
1089+ // time is likely intentional.
1090+ if (!read_bootid (buf) || memcmp (buf, checkpoint_bootid, UUID_LENGTH) != 0 ) {
1091+ assert (checkpoint_millis >= 0 , " Restore without a checkpoint?" );
1092+ long diff_millis = os::javaTimeMillis () - checkpoint_millis;
1093+ // If the wall clock has gone backwards we won't add it to the offset
1094+ if (diff_millis < 0 ) {
1095+ diff_millis = 0 ;
1096+ }
1097+ // javaTimeNanos() call on the second line below uses the *_offset, so we will zero
1098+ // it to make the call return true monotonic time rather than the adjusted value.
1099+ javaTimeNanos_offset = 0 ;
1100+ javaTimeNanos_offset = checkpoint_nanos - os::javaTimeNanos () + diff_millis * 1000000L ;
1101+ } else {
1102+ // ensure monotonicity even if this looks like the same boot
1103+ jlong diff = os::javaTimeNanos () - checkpoint_nanos;
1104+ if (diff < 0 ) {
1105+ javaTimeNanos_offset -= diff;
1106+ }
1107+ }
1108+ }
1109+
1110+ static bool read_all (int fd, char *dest, size_t n) {
1111+ size_t rd = 0 ;
1112+ do {
1113+ ssize_t r = ::read (fd, dest + rd, n - rd);
1114+ if (r == 0 ) {
1115+ return false ;
1116+ } else if (r < 0 ) {
1117+ if (errno == EINTR) {
1118+ continue ;
1119+ }
1120+ return false ;
1121+ }
1122+ rd += r;
1123+ } while (rd < n);
1124+ return true ;
1125+ }
1126+
1127+ bool crac::read_bootid (char *dest) {
1128+ int fd = ::open (" /proc/sys/kernel/random/boot_id" , O_RDONLY);
1129+ if (fd < 0 || !read_all (fd, dest, UUID_LENGTH)) {
1130+ perror (" CRaC: Cannot read system boot ID" );
1131+ return false ;
1132+ }
1133+ char c;
1134+ if (!read_all (fd, &c, 1 ) || c != ' \n ' ) {
1135+ perror (" CRaC: system boot ID does not end with newline" );
1136+ return false ;
1137+ }
1138+ if (::read (fd, &c, 1 ) != 0 ) {
1139+ perror (" CRaC: Unexpected data/error reading system boot ID" );
1140+ return false ;
1141+ }
1142+ if (::close (fd) != 0 ) {
1143+ perror (" CRaC: Cannot close system boot ID file" );
1144+ }
1145+ return true ;
1146+ }
0 commit comments