@@ -5928,6 +5928,84 @@ class CompilationDensity
59285928 }
59295929 }; // class CompilationDensity
59305930
5931+ #if defined(J9VM_OPT_CRIU_SUPPORT)
5932+ static void suspendSamplerThreadForCheckpoint (J9VMThread *samplerThread, J9JITConfig *jitConfig, TR::CompilationInfo *compInfo)
5933+ {
5934+ compInfo->acquireCompMonitor (samplerThread);
5935+ if (compInfo->shouldSuspendThreadsForCheckpoint ())
5936+ {
5937+ PORT_ACCESS_FROM_JITCONFIG (jitConfig);
5938+
5939+ // Must acquire this with the comp monitor in hand to ensure
5940+ // consistency with the checkpointing thread.
5941+ j9thread_monitor_enter (jitConfig->samplerMonitor );
5942+
5943+ // Because this thread has the comp monitor in hand, and because
5944+ // shouldSuspendThreadsForCheckpoint() returned true, it is not possible
5945+ // for the Sampler Thread to have any other state other than SAMPLE_THR_INITIALIZED
5946+ TR_ASSERT_FATAL (compInfo->getSamplingThreadLifetimeState () == TR::CompilationInfo::SAMPLE_THR_INITIALIZED,
5947+ " Sampler Thread Lifetime State %d is not SAMPLE_THR_INITIALIZED!" , compInfo->getSamplingThreadLifetimeState ());
5948+
5949+ // Update the sampler thread state.
5950+ compInfo->setSamplingThreadLifetimeState (TR::CompilationInfo::SAMPLE_THR_SUSPENDED);
5951+
5952+ // Notify the checkpointing thread about the state change.
5953+ //
5954+ // Note, unlike the checkpointing thread, this thread does NOT
5955+ // release the sampler monitor before acquring the CR monitor.
5956+ // This ensures that the Sampling Thread Lifetime State does not
5957+ // change because of something like Shutdown. However, this
5958+ // can only cause a deadlock if the checkpointing thread
5959+ // decides to re-acquire the sampler monitor with the CR monitor
5960+ // in hand.
5961+ compInfo->acquireCRMonitor ();
5962+ compInfo->getCRMonitor ()->notifyAll ();
5963+ compInfo->releaseCRMonitor ();
5964+
5965+ if (TR::Options::isAnyVerboseOptionSet ())
5966+ TR_VerboseLog::writeLineLocked (TR_Vlog_CHECKPOINT_RESTORE, " Suspending Sampler Thread for Checkpoint" );
5967+
5968+ // Release the comp monitor before suspending.
5969+ compInfo->releaseCompMonitor (samplerThread);
5970+
5971+ // Wait until restore, at which point the lifetime state
5972+ // will be TR::CompilationInfo::SAMPLE_THR_RESUMING
5973+ while (compInfo->getSamplingThreadLifetimeState () == TR::CompilationInfo::SAMPLE_THR_SUSPENDED)
5974+ {
5975+ j9thread_monitor_wait (jitConfig->samplerMonitor );
5976+ }
5977+
5978+ if (TR::Options::isAnyVerboseOptionSet ())
5979+ TR_VerboseLog::writeLineLocked (TR_Vlog_CHECKPOINT_RESTORE, " Resuming Sampler Thread from Checkpoint" );
5980+
5981+ // Release the sampler monitor before reacquring both the
5982+ // comp monitor and sampler monitor. This is necessary to
5983+ // ensure consistency with the checkpointing thread.
5984+ j9thread_monitor_exit (jitConfig->samplerMonitor );
5985+ compInfo->acquireCompMonitor (samplerThread);
5986+ j9thread_monitor_enter (jitConfig->samplerMonitor );
5987+
5988+ // Ensure the sampler thread was resumed because of a restore
5989+ // rather than something else (such as shutdown)
5990+ if (compInfo->getSamplingThreadLifetimeState () == TR::CompilationInfo::SAMPLE_THR_RESUMING)
5991+ {
5992+ if (TR::Options::isAnyVerboseOptionSet ())
5993+ TR_VerboseLog::writeLineLocked (TR_Vlog_CHECKPOINT_RESTORE, " Resetting Sampling Thread Lifetime State" );
5994+ compInfo->setSamplingThreadLifetimeState (TR::CompilationInfo::SAMPLE_THR_INITIALIZED);
5995+ }
5996+ else
5997+ {
5998+ if (TR::Options::isAnyVerboseOptionSet ())
5999+ TR_VerboseLog::writeLineLocked (TR_Vlog_CHECKPOINT_RESTORE, " Sampling Thread Lifetime State is %p which is not %p!" , compInfo->getSamplingThreadLifetimeState (), TR::CompilationInfo::SAMPLE_THR_RESUMING);
6000+ }
6001+
6002+ // Release the reacquired sampler thread monitor.
6003+ j9thread_monitor_exit (jitConfig->samplerMonitor );
6004+ }
6005+ compInfo->releaseCompMonitor (samplerThread);
6006+ }
6007+ #endif
6008+
59316009static int32_t J9THREAD_PROC samplerThreadProc (void * entryarg)
59326010 {
59336011 J9JITConfig * jitConfig = (J9JITConfig *) entryarg;
@@ -6124,35 +6202,30 @@ static int32_t J9THREAD_PROC samplerThreadProc(void * entryarg)
61246202 while (!shutdownSamplerThread && // watch for shutdown signals
61256203 j9thread_sleep_interruptable ((IDATA) samplingPeriod, 0 ) == 0 ) // Anything non-0 is an error condition so we shouldn't do the sampling //!= J9THREAD_INTERRUPTED)
61266204 {
6127- #if defined(J9VM_OPT_CRIU_SUPPORT)
6128- // Post-restore, reset the start and elapsed time. The Checkpoint
6129- // phase is conceptually part of building the application; therefore
6130- // it does not make sense to expect a user who specifies an option such
6131- // as -XsamplingExpirationTime to take into account the time spent
6132- // executing in the Checkpoint phase.
6133- if (compInfo->resetStartAndElapsedTime ())
6134- {
6135- if (TR::Options::isAnyVerboseOptionSet ())
6136- TR_VerboseLog::writeLineLocked (TR_Vlog_CHECKPOINT_RESTORE, " Start and elapsed time: startTime=%6u, elapsedTime=%6u" ,
6137- (uint32_t )persistentInfo->getStartTime (), (uint32_t )persistentInfo->getElapsedTime ());
6138-
6139- persistentInfo->setStartTime (j9time_current_time_millis ());
6140- persistentInfo->setElapsedTime (0 );
6141-
6142- if (TR::Options::isAnyVerboseOptionSet ())
6143- TR_VerboseLog::writeLineLocked (TR_Vlog_CHECKPOINT_RESTORE, " Reset start and elapsed time: startTime=%6u, elapsedTime=%6u" ,
6144- (uint32_t )persistentInfo->getStartTime (), (uint32_t )persistentInfo->getElapsedTime ());
6145-
6146- // Only reset the time once
6147- compInfo->setResetStartAndElapsedTime (false );
6148- }
6149- #endif // #if defined(J9VM_OPT_CRIU_SUPPORT)
6150-
61516205 J9VMThread * currentThread;
61526206
61536207 persistentInfo->updateElapsedTime (samplingPeriod);
61546208 crtTime += samplingPeriod;
61556209
6210+ #if defined(J9VM_OPT_CRIU_SUPPORT)
6211+ if (vm->internalVMFunctions ->isCheckpointAllowed (samplerThread)
6212+ /* It's ok to not acquire the comp monitor here. Even if at this
6213+ * point a checkpoint isn't in progress but later it is, the
6214+ * checkpoint will not complete until the sampler thread suspends
6215+ * itself. Therefore, on some iteration of the enclosing while
6216+ * loop, this condition will be true and the sampler thread will
6217+ * go through the process of suspending itself. Conversely, if
6218+ * this condition is true, but after acquring the comp monitor
6219+ * (in the call to suspendSamplerThreadForCheckpoint) this condition
6220+ * isn't true (e.g., due to shutdown), then the sampler thread will
6221+ * not suspend itself.
6222+ */
6223+ && compInfo->shouldSuspendThreadsForCheckpoint ())
6224+ {
6225+ suspendSamplerThreadForCheckpoint (samplerThread,jitConfig, compInfo);
6226+ }
6227+ #endif // #if defined(J9VM_OPT_CRIU_SUPPORT)
6228+
61566229 // periodic chores
61576230 // FIXME: make a constant/macro for the period, and make it 100
61586231 if (crtTime - oldSyncTime >= 100 ) // every 100 ms
0 commit comments