From 234d49f4384ae09046ccc2a2040dd10ee7b681fe Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 11 May 2026 10:06:20 +0200 Subject: [PATCH 01/12] CRaC should fail gracefully on a second checkpoint attempt --- .../include/crlib/crlib_checkpointable_data.h | 54 +++++++++++++++++++ src/hotspot/share/runtime/crac.cpp | 17 ++++++ src/hotspot/share/runtime/crac_engine.cpp | 10 ++++ src/hotspot/share/runtime/crac_engine.hpp | 5 ++ .../linux/native/libcriuengine/criuengine.cpp | 14 +++++ 5 files changed, 100 insertions(+) create mode 100644 src/hotspot/share/include/crlib/crlib_checkpointable_data.h diff --git a/src/hotspot/share/include/crlib/crlib_checkpointable_data.h b/src/hotspot/share/include/crlib/crlib_checkpointable_data.h new file mode 100644 index 00000000000..ea8ca341f9e --- /dev/null +++ b/src/hotspot/share/include/crlib/crlib_checkpointable_data.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2025, Azul Systems, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +#ifndef CRLIB_CHECKPOINTABLE_DATA_H +#define CRLIB_CHECKPOINTABLE_DATA_H + +#include "crlib.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME "checkpointable data" +#define CRLIB_EXTENSION_CHECKPOINTABLE(api) \ + CRLIB_EXTENSION(api, crlib_checkpointable_data_t, CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME) + +typedef enum checkpointable_status { + never, // it's not able to commit checkpoint + ready, // checkpointable + ready_later // at some point it could become checkpointable +} checkpointable_status_t; + +// API for obtaining information about chackpointable status. +struct crlib_checkpointable_data { + crlib_extension_t header; + + checkpointable_status_t (*get_checkpointable_status)(crlib_conf_t *); +}; +typedef const struct crlib_checkpointable_data crlib_checkpointable_data_t; + +#ifdef __cplusplus +} // extern "C +#endif + +#endif // CRLIB_CHECKPOINTABLE_DATA_H \ No newline at end of file diff --git a/src/hotspot/share/runtime/crac.cpp b/src/hotspot/share/runtime/crac.cpp index a9c8a6d0d75..2b5a223c0af 100644 --- a/src/hotspot/share/runtime/crac.cpp +++ b/src/hotspot/share/runtime/crac.cpp @@ -449,6 +449,23 @@ void VM_Crac::doit() { DefaultStreamHandler defStreamHandler; Decoder::before_checkpoint(); + if (crac::_generation > 1) { + CracEngine engine(false); + checkpointable_status_t status = engine.get_checkpointable_status(); + switch (status) { + case never: + ok = false; + os::message_box("Checkpoint failed", "Current engine doesn't support more than 2 checkpoints."); + break; + case ready: + os::message_box("Checkpoint continue", "Current engine supports more than 2 checkpoints."); + break; + case ready_later: + ok = false; + os::message_box("Checkpoint failed", "Current engine is bussy, try checkpoint later."); + break; + } + } if (!check_fds()) { ok = false; } diff --git a/src/hotspot/share/runtime/crac_engine.cpp b/src/hotspot/share/runtime/crac_engine.cpp index 2641a804ba8..722fb3a25e8 100644 --- a/src/hotspot/share/runtime/crac_engine.cpp +++ b/src/hotspot/share/runtime/crac_engine.cpp @@ -606,3 +606,13 @@ CracEngine::ApiStatus CracEngine::prepare_image_score_api() { bool CracEngine::set_score(const char* metric, double value) { return _image_score_api->set_score(_conf, metric, value); } + +CracEngine::ApiStatus CracEngine::prepare_checkpointable_data_api() { + prepare_extension_api(_checkpointable_data_api, CRLIB_EXTENSION_RESTORE_DATA_NAME) + require_method(get_checkpointable_status) + complete_extension_api(_checkpointable_data_api) +} + +checkpointable_status_t CracEngine::get_checkpointable_status() { + return _checkpointable_data_api->get_checkpointable_status(_conf); +} \ No newline at end of file diff --git a/src/hotspot/share/runtime/crac_engine.hpp b/src/hotspot/share/runtime/crac_engine.hpp index 5866cd8255c..1533918a118 100644 --- a/src/hotspot/share/runtime/crac_engine.hpp +++ b/src/hotspot/share/runtime/crac_engine.hpp @@ -25,6 +25,7 @@ #define SHARE_RUNTIME_CRAC_ENGINE_HPP #include "crlib/crlib.h" +#include "crlib/crlib_checkpointable_data.h" #include "crlib/crlib_description.h" #include "crlib/crlib_image_constraints.h" #include "crlib/crlib_image_score.h" @@ -79,6 +80,9 @@ class CracEngine : public CHeapObj { ApiStatus prepare_image_score_api(); bool set_score(const char* metric, double value); + ApiStatus prepare_checkpointable_data_api(); + checkpointable_status_t get_checkpointable_status(); + private: char _name[MAX_ENGINE_LENGTH]; void *_lib = nullptr; @@ -90,6 +94,7 @@ class CracEngine : public CHeapObj { crlib_description_t *_description_api = nullptr; crlib_image_constraints_t *_image_constraints_api = nullptr; crlib_image_score_t *_image_score_api = nullptr; + crlib_checkpointable_data_t *_checkpointable_data_api = nullptr; crlib_conf_option_t *_options = nullptr; }; diff --git a/src/java.base/linux/native/libcriuengine/criuengine.cpp b/src/java.base/linux/native/libcriuengine/criuengine.cpp index 7574085b248..dc3b955238f 100644 --- a/src/java.base/linux/native/libcriuengine/criuengine.cpp +++ b/src/java.base/linux/native/libcriuengine/criuengine.cpp @@ -38,6 +38,7 @@ #include #include +#include "crlib_checkpointable_data.h" #include "crlib/crlib_description.h" #include "crlib/crlib_restore_data.h" #include "crlib/crlib_user_data.h" @@ -495,6 +496,10 @@ static char* get_relative_file(const char* rel) { return buf; } +checkpointable_status_t get_checkpointable_status(crlib_conf_t *) { + return ready; +} + const char* criuengine::get_criu() { char* criu = _criu_location; if (criu == nullptr) { @@ -974,12 +979,21 @@ static crlib_user_data_t user_data_extension = { destroy_user_data, }; +static crlib_checkpointable_data_t checkpointable_data_extension = { + { + CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME, + sizeof(checkpointable_data_extension) + }, + get_checkpointable_status, +}; + static const crlib_extension_t* extensions[] = { &restore_data_extension.header, &image_constraints_extension.header, &image_score_extension.header, &user_data_extension.header, &description_extension.header, + &checkpointable_data_extension.header, nullptr }; From 4c236e2d05b78855ead8d52def741eb57d60216b Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 11 May 2026 10:58:47 +0200 Subject: [PATCH 02/12] Adding simengine. --- .../linux/native/libcriuengine/criuengine.cpp | 2 +- .../share/native/libsimengine/simengine.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/java.base/linux/native/libcriuengine/criuengine.cpp b/src/java.base/linux/native/libcriuengine/criuengine.cpp index dc3b955238f..11d0b7c7625 100644 --- a/src/java.base/linux/native/libcriuengine/criuengine.cpp +++ b/src/java.base/linux/native/libcriuengine/criuengine.cpp @@ -38,7 +38,7 @@ #include #include -#include "crlib_checkpointable_data.h" +#include "crlib/crlib_checkpointable_data.h" #include "crlib/crlib_description.h" #include "crlib/crlib_restore_data.h" #include "crlib/crlib_user_data.h" diff --git a/src/java.base/share/native/libsimengine/simengine.cpp b/src/java.base/share/native/libsimengine/simengine.cpp index 0387a6e6296..b3c1afa9f78 100644 --- a/src/java.base/share/native/libsimengine/simengine.cpp +++ b/src/java.base/share/native/libsimengine/simengine.cpp @@ -36,6 +36,7 @@ #endif // LINUX #include "crcommon.hpp" +#include "crlib/crlib_checkpointable_data.h" #include "crlib/crlib_restore_data.h" #include "crlib/crlib_description.h" #include "jni.h" @@ -288,11 +289,24 @@ static crlib_description_t description_extension = { configuration_options, }; +checkpointable_status_t get_checkpointable_status(crlib_conf_t *) { + return ready; +} + +static crlib_checkpointable_data_t checkpointable_data_extension = { + { + CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME, + sizeof(checkpointable_data_extension) + }, + get_checkpointable_status, +}; + static const crlib_extension_t *extensions[] = { &restore_data_extension.header, &image_constraints_extension.header, &image_score_extension.header, &description_extension.header, + &checkpointable_data_extension.header, nullptr }; From 6573d054ee93cde515210c3fd9fb2839ebe09927 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Tue, 19 May 2026 13:26:19 +0200 Subject: [PATCH 03/12] Fix incorrect function name --- src/hotspot/share/runtime/crac.cpp | 27 ++++++++++--------- src/hotspot/share/runtime/crac_engine.cpp | 2 +- .../linux/native/libcriuengine/criuengine.cpp | 7 +++-- .../share/native/libsimengine/simengine.cpp | 2 +- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/runtime/crac.cpp b/src/hotspot/share/runtime/crac.cpp index 2b5a223c0af..b5ee4b31d6d 100644 --- a/src/hotspot/share/runtime/crac.cpp +++ b/src/hotspot/share/runtime/crac.cpp @@ -450,20 +450,21 @@ void VM_Crac::doit() { Decoder::before_checkpoint(); if (crac::_generation > 1) { - CracEngine engine(false); - checkpointable_status_t status = engine.get_checkpointable_status(); - switch (status) { - case never: - ok = false; - os::message_box("Checkpoint failed", "Current engine doesn't support more than 2 checkpoints."); + if (crac::_engine->prepare_checkpointable_data_api() == CracEngine::ApiStatus::OK) { + checkpointable_status_t status = crac::_engine->get_checkpointable_status(); + switch (status) { + case never: + ok = false; + os::message_box("Checkpoint failed", "Current engine doesn't support more than 2 checkpoints."); + break; + case ready: + os::message_box("Checkpoint continue", "Current engine supports more than 2 checkpoints."); break; - case ready: - os::message_box("Checkpoint continue", "Current engine supports more than 2 checkpoints."); - break; - case ready_later: - ok = false; - os::message_box("Checkpoint failed", "Current engine is bussy, try checkpoint later."); - break; + case ready_later: + ok = false; + os::message_box("Checkpoint failed", "Current engine is bussy, try checkpoint later."); + break; + } } } if (!check_fds()) { diff --git a/src/hotspot/share/runtime/crac_engine.cpp b/src/hotspot/share/runtime/crac_engine.cpp index 722fb3a25e8..e86f99cf20b 100644 --- a/src/hotspot/share/runtime/crac_engine.cpp +++ b/src/hotspot/share/runtime/crac_engine.cpp @@ -608,7 +608,7 @@ bool CracEngine::set_score(const char* metric, double value) { } CracEngine::ApiStatus CracEngine::prepare_checkpointable_data_api() { - prepare_extension_api(_checkpointable_data_api, CRLIB_EXTENSION_RESTORE_DATA_NAME) + prepare_extension_api(_checkpointable_data_api, CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME) require_method(get_checkpointable_status) complete_extension_api(_checkpointable_data_api) } diff --git a/src/java.base/linux/native/libcriuengine/criuengine.cpp b/src/java.base/linux/native/libcriuengine/criuengine.cpp index 11d0b7c7625..b2fc353cd15 100644 --- a/src/java.base/linux/native/libcriuengine/criuengine.cpp +++ b/src/java.base/linux/native/libcriuengine/criuengine.cpp @@ -496,8 +496,11 @@ static char* get_relative_file(const char* rel) { return buf; } -checkpointable_status_t get_checkpointable_status(crlib_conf_t *) { - return ready; +static checkpointable_status_t get_checkpointable_status(crlib_conf_t * conf) { + if (!conf->direct_map()) { + return ready; + } + return never; } const char* criuengine::get_criu() { diff --git a/src/java.base/share/native/libsimengine/simengine.cpp b/src/java.base/share/native/libsimengine/simengine.cpp index b3c1afa9f78..9880c09f8ae 100644 --- a/src/java.base/share/native/libsimengine/simengine.cpp +++ b/src/java.base/share/native/libsimengine/simengine.cpp @@ -289,7 +289,7 @@ static crlib_description_t description_extension = { configuration_options, }; -checkpointable_status_t get_checkpointable_status(crlib_conf_t *) { +static checkpointable_status_t get_checkpointable_status(crlib_conf_t *) { return ready; } From 097d1dde58ab84de656b8a0337d006aa2506e9cb Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Thu, 21 May 2026 17:34:07 +0200 Subject: [PATCH 04/12] Implement the second checkpoint hanlder in java code. --- src/hotspot/share/include/jmm.h | 1 + src/hotspot/share/include/jvm.h | 3 ++ src/hotspot/share/prims/jvm.cpp | 4 ++ src/hotspot/share/runtime/crac.cpp | 42 +++++++++++-------- src/hotspot/share/runtime/crac.hpp | 1 + src/hotspot/share/services/management.cpp | 3 +- .../crac/mirror/CheckpointableStatus.java | 39 +++++++++++++++++ .../jdk/internal/crac/mirror/Core.java | 20 +++++++++ src/java.base/share/native/libjava/CracCore.c | 5 +++ .../classes/sun/management/VMManagement.java | 1 + .../sun/management/VMManagementImpl.java | 5 +++ .../native/libmanagement/VMManagementImpl.c | 8 ++++ .../jdk/crac/management/CRaCMXBean.java | 18 ++++++++ .../crac/management/internal/CRaCImpl.java | 6 +++ 14 files changed, 137 insertions(+), 19 deletions(-) create mode 100644 src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java diff --git a/src/hotspot/share/include/jmm.h b/src/hotspot/share/include/jmm.h index 93aaf67221d..ba553b88c47 100644 --- a/src/hotspot/share/include/jmm.h +++ b/src/hotspot/share/include/jmm.h @@ -85,6 +85,7 @@ typedef enum { JMM_TOTAL_GC_CPU_TIME = 12, /* Total accumulated GC CPU time */ JMM_JVM_RESTORE_START_TIME_MS = 13, /* Time when the JVM started restore operation */ JMM_JVM_UPTIME_SINCE_RESTORE_MS = 14, /* The JVM uptime since restore */ + JMM_JVM_CHECKPOINTABLE_STATUS = 15, /* The JVM checkpointable status */ JMM_INTERNAL_ATTRIBUTE_INDEX = 100, JMM_CLASS_LOADED_BYTES = 101, /* Number of bytes loaded instance classes */ diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index 1a4bf363070..936d97fac96 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1181,6 +1181,9 @@ enum cr_fail_type { JNIEXPORT jobjectArray JNICALL JVM_Checkpoint(JNIEnv *env, jarray fd_arr, jobjectArray obj_arr, jboolean dry_run, jlong jcmd_stream); +JNIEXPORT jint JNICALL +JVM_GetCheckpointableStatus(JNIEnv *env); + JNIEXPORT void JNICALL JVM_StartRecordingDecompilations(JNIEnv *env); diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 85e58caf0ae..638a267c955 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3664,6 +3664,10 @@ JVM_ENTRY(jobjectArray, JVM_Checkpoint(JNIEnv *env, jarray fd_arr, jobjectArray return (jobjectArray) JNIHandles::make_local(THREAD, ret()); JVM_END +JVM_ENTRY(jint, JVM_GetCheckpointableStatus(JNIEnv *env)) + return crac::checkpointable_status(); +JVM_END + JVM_ENTRY(void, JVM_StartRecordingDecompilations(JNIEnv *env)) CRaCRecompiler::start_recording_decompilations(); JVM_END diff --git a/src/hotspot/share/runtime/crac.cpp b/src/hotspot/share/runtime/crac.cpp index b5ee4b31d6d..1d6e27f87a6 100644 --- a/src/hotspot/share/runtime/crac.cpp +++ b/src/hotspot/share/runtime/crac.cpp @@ -80,6 +80,29 @@ jlong crac::uptime_since_restore() { return os::javaTimeNanos() - _restore_start_nanos; } +jint crac::checkpointable_status() { + bool is_checkpointable = true; + if (crac::_generation > 1) { + if (crac::_engine->prepare_checkpointable_data_api() == CracEngine::ApiStatus::OK) { + checkpointable_status_t status = crac::_engine->get_checkpointable_status(); + switch (status) { + case never: + is_checkpointable = false; + os::message_box("Checkpoint failed", "Current engine doesn't support more than 2 checkpoints."); + break; + case ready: + break; + case ready_later: + is_checkpointable = false; + os::message_box("Checkpoint failed", "Current engine is bussy, try checkpoint later."); + break; + } + } + } + + return is_checkpointable; +} + void VM_Crac::print_resources(const char* msg, ...) { if (CRaCPrintResourcesOnCheckpoint) { va_list ap; @@ -449,24 +472,7 @@ void VM_Crac::doit() { DefaultStreamHandler defStreamHandler; Decoder::before_checkpoint(); - if (crac::_generation > 1) { - if (crac::_engine->prepare_checkpointable_data_api() == CracEngine::ApiStatus::OK) { - checkpointable_status_t status = crac::_engine->get_checkpointable_status(); - switch (status) { - case never: - ok = false; - os::message_box("Checkpoint failed", "Current engine doesn't support more than 2 checkpoints."); - break; - case ready: - os::message_box("Checkpoint continue", "Current engine supports more than 2 checkpoints."); - break; - case ready_later: - ok = false; - os::message_box("Checkpoint failed", "Current engine is bussy, try checkpoint later."); - break; - } - } - } + if (!check_fds()) { ok = false; } diff --git a/src/hotspot/share/runtime/crac.hpp b/src/hotspot/share/runtime/crac.hpp index d37a3aff1de..4427823315f 100644 --- a/src/hotspot/share/runtime/crac.hpp +++ b/src/hotspot/share/runtime/crac.hpp @@ -57,6 +57,7 @@ class crac: AllStatic { static jlong restore_start_time(); static jlong uptime_since_restore(); + static jint checkpointable_status(); static jlong monotonic_time_offset() { return _javaTimeNanos_offset; diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index d6abd7c885a..2aa34df36dc 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1008,7 +1008,8 @@ static jlong get_long_attribute(jmmLongAttribute att) { } return Management::ticks_to_ms(ticks); } - + case JMM_JVM_CHECKPOINTABLE_STATUS: + return crac::checkpointable_status(); default: return -1; } diff --git a/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java b/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java new file mode 100644 index 00000000000..f5e15efe620 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.crac.mirror; + +public enum CheckpointableStatus { + NEVER, READY, READY_LATER; + + public static CheckpointableStatus fromCode(int code) { + CheckpointableStatus[] values = values(); + if (code < 0 || code >= values.length) { + throw new IllegalArgumentException("Unknown CheckpointableStatus code: " + code); + } + return values[code]; + } +} diff --git a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java index 3442b9e2884..57914e91295 100644 --- a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java +++ b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java @@ -57,6 +57,7 @@ public class Core { private static final long JCMD_STREAM_NULL = 0; private static native Object[] checkpointRestore0(int[] fdArr, Object[] objArr, boolean dryRun, long jcmdStream); + private static native int getCheckpointableStatus0(); private static final Object checkpointRestoreLock = new Object(); private static boolean checkpointInProgress = false; @@ -274,6 +275,25 @@ private static void checkpointRestore(long jcmdStream) throws RestoreException { final List newArguments; + switch (CheckpointableStatus.fromCode(getCheckpointableStatus0())) { + case NEVER -> { + System.out.print("NEVER!!!!"); + CheckpointException ex = new CheckpointException(); + ex.addSuppressed(new Exception("Current engine doesn't support second checkpoint")); + throw ex; + } + case READY_LATER -> { + System.out.print("READY_LATER!!!!"); + CheckpointException ex = new CheckpointException(); + ex.addSuppressed(new Exception("CRaC cannot commit checkpoint right now")); + throw ex; + } + case READY -> { + // fall through to checkpoint logic below + System.out.print("READY!!!!"); + } + } + // checkpointRestoreLock protects against the simultaneous // call of checkpointRestore from different threads. synchronized (checkpointRestoreLock) { diff --git a/src/java.base/share/native/libjava/CracCore.c b/src/java.base/share/native/libjava/CracCore.c index 2934e946af7..6d2d3a81249 100644 --- a/src/java.base/share/native/libjava/CracCore.c +++ b/src/java.base/share/native/libjava/CracCore.c @@ -39,6 +39,11 @@ Java_jdk_internal_crac_mirror_Core_checkpointRestore0(JNIEnv *env, jclass ignore return JVM_Checkpoint(env, fdArr, objArr, dry_run, jcmd_stream); } +JNIEXPORT jint JNICALL +Java_jdk_internal_crac_mirror_Core_getCheckpointableStatus0(JNIEnv *env, jclass ignore) { + return JVM_GetCheckpointableStatus(env); +} + JNIEXPORT void JNICALL Java_jdk_internal_crac_mirror_Core_startRecordingDecompilations0(JNIEnv *env, jclass ignore) { JVM_StartRecordingDecompilations(env); diff --git a/src/java.management/share/classes/sun/management/VMManagement.java b/src/java.management/share/classes/sun/management/VMManagement.java index 413dc3c3d35..7cd6ccdd504 100644 --- a/src/java.management/share/classes/sun/management/VMManagement.java +++ b/src/java.management/share/classes/sun/management/VMManagement.java @@ -113,4 +113,5 @@ public interface VMManagement { // CRaC support public long getRestoreTime(); public long getUptimeSinceRestore(); + public int getCheckpointableStatus(); } diff --git a/src/java.management/share/classes/sun/management/VMManagementImpl.java b/src/java.management/share/classes/sun/management/VMManagementImpl.java index b23d4789bf7..162d151b051 100644 --- a/src/java.management/share/classes/sun/management/VMManagementImpl.java +++ b/src/java.management/share/classes/sun/management/VMManagementImpl.java @@ -280,6 +280,7 @@ public List getInternalCounters(String pattern) { // CRaC support private native long getRestoreTime0(); private native long getUptimeSinceRestore0(); + private native int getCheckpointableStatus0(); public long getRestoreTime() { return getRestoreTime0(); @@ -288,4 +289,8 @@ public long getRestoreTime() { public long getUptimeSinceRestore() { return getUptimeSinceRestore0(); } + + public int getCheckpointableStatus() { + return getCheckpointableStatus0(); + } } diff --git a/src/java.management/share/native/libmanagement/VMManagementImpl.c b/src/java.management/share/native/libmanagement/VMManagementImpl.c index 246bfbb3858..c72963193e5 100644 --- a/src/java.management/share/native/libmanagement/VMManagementImpl.c +++ b/src/java.management/share/native/libmanagement/VMManagementImpl.c @@ -348,3 +348,11 @@ Java_sun_management_VMManagementImpl_getUptimeSinceRestore0 return jmm_interface->GetLongAttribute(env, NULL, JMM_JVM_UPTIME_SINCE_RESTORE_MS); } + +JNIEXPORT jint JNICALL +Java_sun_management_VMManagementImpl_getCheckpointableStatus0 + (JNIEnv *env, jobject dummy) +{ + return (jint) jmm_interface->GetLongAttribute(env, NULL, + JMM_JVM_CHECKPOINTABLE_STATUS); +} diff --git a/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java b/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java index 48025bc989a..25bd933753f 100644 --- a/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java +++ b/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java @@ -56,6 +56,24 @@ public interface CRaCMXBean extends PlatformManagedObject { */ public long getRestoreTime(); + public enum CheckpointableStatus { + NEVER, READY, READY_LATER; + + public static CheckpointableStatus fromCode(int code) { + CheckpointableStatus[] values = values(); + if (code < 0 || code >= values.length) { + throw new IllegalArgumentException("Unknown CheckpointableStatus code: " + code); + } + return values[code]; + } + } + + /** + * + * @return true if checkpoint could be comminted, otherwise returns false. + */ + public CheckpointableStatus getCheckpointableStatus() throws IllegalStateException; + /** * Returns the implementation of the MXBean. * diff --git a/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java b/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java index 681161fc74a..5c96340e80f 100644 --- a/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java +++ b/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java @@ -52,6 +52,12 @@ public long getRestoreTime() { return vm.getRestoreTime(); } + @Override + public CRaCMXBean.CheckpointableStatus getCheckpointableStatus() { + int status = vm.getCheckpointableStatus(); + return CRaCMXBean.CheckpointableStatus.fromCode(status); + } + @Override public void checkpointRestore() throws RestoreException, CheckpointException { try { From 985ee64b008c9589192b3a074fe5034991d5ff6e Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Fri, 22 May 2026 11:03:18 +0200 Subject: [PATCH 05/12] Improve names of statuses --- .../include/crlib/crlib_checkpointable_data.h | 8 +++---- src/hotspot/share/runtime/crac.cpp | 23 ++++--------------- src/hotspot/share/runtime/crac.hpp | 2 +- src/hotspot/share/runtime/crac_engine.cpp | 2 +- src/hotspot/share/runtime/crac_engine.hpp | 2 +- .../linux/native/libcriuengine/criuengine.cpp | 2 +- .../crac/mirror/CheckpointableStatus.java | 2 +- .../jdk/internal/crac/mirror/Core.java | 18 +++++++-------- src/java.base/share/native/libjava/CracCore.c | 2 +- .../share/native/libsimengine/simengine.cpp | 2 +- .../jdk/crac/management/CRaCMXBean.java | 4 ++-- .../crac/management/internal/CRaCImpl.java | 2 +- 12 files changed, 28 insertions(+), 41 deletions(-) diff --git a/src/hotspot/share/include/crlib/crlib_checkpointable_data.h b/src/hotspot/share/include/crlib/crlib_checkpointable_data.h index ea8ca341f9e..a246def993e 100644 --- a/src/hotspot/share/include/crlib/crlib_checkpointable_data.h +++ b/src/hotspot/share/include/crlib/crlib_checkpointable_data.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2026, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,9 +34,9 @@ extern "C" { CRLIB_EXTENSION(api, crlib_checkpointable_data_t, CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME) typedef enum checkpointable_status { - never, // it's not able to commit checkpoint - ready, // checkpointable - ready_later // at some point it could become checkpointable + never_after_restore, // it's not able to commit a new checkpoint after restore + ready_late, // at some point it could become checkpointable + ready // checkpointable } checkpointable_status_t; // API for obtaining information about chackpointable status. diff --git a/src/hotspot/share/runtime/crac.cpp b/src/hotspot/share/runtime/crac.cpp index 1d6e27f87a6..f07dc75d1b9 100644 --- a/src/hotspot/share/runtime/crac.cpp +++ b/src/hotspot/share/runtime/crac.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2023, 2026, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,25 +82,12 @@ jlong crac::uptime_since_restore() { jint crac::checkpointable_status() { bool is_checkpointable = true; - if (crac::_generation > 1) { - if (crac::_engine->prepare_checkpointable_data_api() == CracEngine::ApiStatus::OK) { - checkpointable_status_t status = crac::_engine->get_checkpointable_status(); - switch (status) { - case never: - is_checkpointable = false; - os::message_box("Checkpoint failed", "Current engine doesn't support more than 2 checkpoints."); - break; - case ready: - break; - case ready_later: - is_checkpointable = false; - os::message_box("Checkpoint failed", "Current engine is bussy, try checkpoint later."); - break; - } - } + if ((crac::_generation > 1) && + (crac::_engine->prepare_checkpointable_data_api() == CracEngine::ApiStatus::OK)) { + return crac::_engine->get_checkpointable_status(); } - return is_checkpointable; + return ready; } void VM_Crac::print_resources(const char* msg, ...) { diff --git a/src/hotspot/share/runtime/crac.hpp b/src/hotspot/share/runtime/crac.hpp index 4427823315f..a15fd254ff0 100644 --- a/src/hotspot/share/runtime/crac.hpp +++ b/src/hotspot/share/runtime/crac.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2023, 2026, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/hotspot/share/runtime/crac_engine.cpp b/src/hotspot/share/runtime/crac_engine.cpp index e86f99cf20b..9d97e64008e 100644 --- a/src/hotspot/share/runtime/crac_engine.cpp +++ b/src/hotspot/share/runtime/crac_engine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2025, 2026, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/hotspot/share/runtime/crac_engine.hpp b/src/hotspot/share/runtime/crac_engine.hpp index 1533918a118..1ae4a3f0951 100644 --- a/src/hotspot/share/runtime/crac_engine.hpp +++ b/src/hotspot/share/runtime/crac_engine.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2025, 2026, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it diff --git a/src/java.base/linux/native/libcriuengine/criuengine.cpp b/src/java.base/linux/native/libcriuengine/criuengine.cpp index b2fc353cd15..e5b84cedec0 100644 --- a/src/java.base/linux/native/libcriuengine/criuengine.cpp +++ b/src/java.base/linux/native/libcriuengine/criuengine.cpp @@ -500,7 +500,7 @@ static checkpointable_status_t get_checkpointable_status(crlib_conf_t * conf) { if (!conf->direct_map()) { return ready; } - return never; + return never_after_restore; } const char* criuengine::get_criu() { diff --git a/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java b/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java index f5e15efe620..41b3e6debea 100644 --- a/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java +++ b/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java @@ -27,7 +27,7 @@ package jdk.internal.crac.mirror; public enum CheckpointableStatus { - NEVER, READY, READY_LATER; + NEVER_AFTER_RESTORE, READY_LATER, READY; public static CheckpointableStatus fromCode(int code) { CheckpointableStatus[] values = values(); diff --git a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java index 57914e91295..67bca3af670 100644 --- a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java +++ b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2017, 2026, Azul Systems, Inc. All rights reserved. * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -274,23 +274,23 @@ private static void checkpointRestore(long jcmdStream) throws CheckpointException, RestoreException { final List newArguments; - - switch (CheckpointableStatus.fromCode(getCheckpointableStatus0())) { - case NEVER -> { - System.out.print("NEVER!!!!"); + int status_code = getCheckpointableStatus0(); + switch (CheckpointableStatus.fromCode(status_code)) { + case NEVER_AFTER_RESTORE -> { CheckpointException ex = new CheckpointException(); - ex.addSuppressed(new Exception("Current engine doesn't support second checkpoint")); + ex.addSuppressed(new Exception("Current engine doesn't support second checkpoint after restore.")); throw ex; } case READY_LATER -> { - System.out.print("READY_LATER!!!!"); CheckpointException ex = new CheckpointException(); - ex.addSuppressed(new Exception("CRaC cannot commit checkpoint right now")); + ex.addSuppressed(new Exception("CRaC cannot commit checkpoint right now, try later.")); throw ex; } case READY -> { // fall through to checkpoint logic below - System.out.print("READY!!!!"); + } + default -> { + System.err.printf("Engine returned unknown checkpointable status code: %d. Proceeding with checkpoint.%n", status_code); } } diff --git a/src/java.base/share/native/libjava/CracCore.c b/src/java.base/share/native/libjava/CracCore.c index 6d2d3a81249..d4fd4fc8f02 100644 --- a/src/java.base/share/native/libjava/CracCore.c +++ b/src/java.base/share/native/libjava/CracCore.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2017, 2026, Azul Systems, Inc. All rights reserved. * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/src/java.base/share/native/libsimengine/simengine.cpp b/src/java.base/share/native/libsimengine/simengine.cpp index 9880c09f8ae..55e7738b60e 100644 --- a/src/java.base/share/native/libsimengine/simengine.cpp +++ b/src/java.base/share/native/libsimengine/simengine.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2021, 2026, Azul Systems, Inc. All rights reserved. * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * diff --git a/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java b/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java index 25bd933753f..0756269698c 100644 --- a/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java +++ b/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2022, 2026, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -57,7 +57,7 @@ public interface CRaCMXBean extends PlatformManagedObject { public long getRestoreTime(); public enum CheckpointableStatus { - NEVER, READY, READY_LATER; + NEVER_AFTER_RESTORE, READY_LATER, READY; public static CheckpointableStatus fromCode(int code) { CheckpointableStatus[] values = values(); diff --git a/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java b/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java index 5c96340e80f..605dff5ffd7 100644 --- a/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java +++ b/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2022, 2026, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From b6223e4e178a6bad5a265433b5eb8f8b10d4b960 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Fri, 22 May 2026 11:47:08 +0200 Subject: [PATCH 06/12] Remove the changes from CRaCMXBean. --- src/hotspot/share/include/jmm.h | 1 - src/hotspot/share/runtime/crac.cpp | 1 - src/hotspot/share/runtime/crac_engine.cpp | 2 +- src/hotspot/share/services/management.cpp | 3 +-- .../classes/sun/management/VMManagement.java | 1 - .../sun/management/VMManagementImpl.java | 5 ----- .../native/libmanagement/VMManagementImpl.c | 8 -------- .../jdk/crac/management/CRaCMXBean.java | 20 +------------------ .../crac/management/internal/CRaCImpl.java | 8 +------- 9 files changed, 4 insertions(+), 45 deletions(-) diff --git a/src/hotspot/share/include/jmm.h b/src/hotspot/share/include/jmm.h index ba553b88c47..93aaf67221d 100644 --- a/src/hotspot/share/include/jmm.h +++ b/src/hotspot/share/include/jmm.h @@ -85,7 +85,6 @@ typedef enum { JMM_TOTAL_GC_CPU_TIME = 12, /* Total accumulated GC CPU time */ JMM_JVM_RESTORE_START_TIME_MS = 13, /* Time when the JVM started restore operation */ JMM_JVM_UPTIME_SINCE_RESTORE_MS = 14, /* The JVM uptime since restore */ - JMM_JVM_CHECKPOINTABLE_STATUS = 15, /* The JVM checkpointable status */ JMM_INTERNAL_ATTRIBUTE_INDEX = 100, JMM_CLASS_LOADED_BYTES = 101, /* Number of bytes loaded instance classes */ diff --git a/src/hotspot/share/runtime/crac.cpp b/src/hotspot/share/runtime/crac.cpp index f07dc75d1b9..8e96e65180a 100644 --- a/src/hotspot/share/runtime/crac.cpp +++ b/src/hotspot/share/runtime/crac.cpp @@ -459,7 +459,6 @@ void VM_Crac::doit() { DefaultStreamHandler defStreamHandler; Decoder::before_checkpoint(); - if (!check_fds()) { ok = false; } diff --git a/src/hotspot/share/runtime/crac_engine.cpp b/src/hotspot/share/runtime/crac_engine.cpp index 9d97e64008e..69952b2a205 100644 --- a/src/hotspot/share/runtime/crac_engine.cpp +++ b/src/hotspot/share/runtime/crac_engine.cpp @@ -615,4 +615,4 @@ CracEngine::ApiStatus CracEngine::prepare_checkpointable_data_api() { checkpointable_status_t CracEngine::get_checkpointable_status() { return _checkpointable_data_api->get_checkpointable_status(_conf); -} \ No newline at end of file +} diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 2aa34df36dc..d6abd7c885a 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1008,8 +1008,7 @@ static jlong get_long_attribute(jmmLongAttribute att) { } return Management::ticks_to_ms(ticks); } - case JMM_JVM_CHECKPOINTABLE_STATUS: - return crac::checkpointable_status(); + default: return -1; } diff --git a/src/java.management/share/classes/sun/management/VMManagement.java b/src/java.management/share/classes/sun/management/VMManagement.java index 7cd6ccdd504..413dc3c3d35 100644 --- a/src/java.management/share/classes/sun/management/VMManagement.java +++ b/src/java.management/share/classes/sun/management/VMManagement.java @@ -113,5 +113,4 @@ public interface VMManagement { // CRaC support public long getRestoreTime(); public long getUptimeSinceRestore(); - public int getCheckpointableStatus(); } diff --git a/src/java.management/share/classes/sun/management/VMManagementImpl.java b/src/java.management/share/classes/sun/management/VMManagementImpl.java index 162d151b051..b23d4789bf7 100644 --- a/src/java.management/share/classes/sun/management/VMManagementImpl.java +++ b/src/java.management/share/classes/sun/management/VMManagementImpl.java @@ -280,7 +280,6 @@ public List getInternalCounters(String pattern) { // CRaC support private native long getRestoreTime0(); private native long getUptimeSinceRestore0(); - private native int getCheckpointableStatus0(); public long getRestoreTime() { return getRestoreTime0(); @@ -289,8 +288,4 @@ public long getRestoreTime() { public long getUptimeSinceRestore() { return getUptimeSinceRestore0(); } - - public int getCheckpointableStatus() { - return getCheckpointableStatus0(); - } } diff --git a/src/java.management/share/native/libmanagement/VMManagementImpl.c b/src/java.management/share/native/libmanagement/VMManagementImpl.c index c72963193e5..246bfbb3858 100644 --- a/src/java.management/share/native/libmanagement/VMManagementImpl.c +++ b/src/java.management/share/native/libmanagement/VMManagementImpl.c @@ -348,11 +348,3 @@ Java_sun_management_VMManagementImpl_getUptimeSinceRestore0 return jmm_interface->GetLongAttribute(env, NULL, JMM_JVM_UPTIME_SINCE_RESTORE_MS); } - -JNIEXPORT jint JNICALL -Java_sun_management_VMManagementImpl_getCheckpointableStatus0 - (JNIEnv *env, jobject dummy) -{ - return (jint) jmm_interface->GetLongAttribute(env, NULL, - JMM_JVM_CHECKPOINTABLE_STATUS); -} diff --git a/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java b/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java index 0756269698c..48025bc989a 100644 --- a/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java +++ b/src/jdk.management/share/classes/jdk/crac/management/CRaCMXBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2026, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2022, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,24 +56,6 @@ public interface CRaCMXBean extends PlatformManagedObject { */ public long getRestoreTime(); - public enum CheckpointableStatus { - NEVER_AFTER_RESTORE, READY_LATER, READY; - - public static CheckpointableStatus fromCode(int code) { - CheckpointableStatus[] values = values(); - if (code < 0 || code >= values.length) { - throw new IllegalArgumentException("Unknown CheckpointableStatus code: " + code); - } - return values[code]; - } - } - - /** - * - * @return true if checkpoint could be comminted, otherwise returns false. - */ - public CheckpointableStatus getCheckpointableStatus() throws IllegalStateException; - /** * Returns the implementation of the MXBean. * diff --git a/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java b/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java index 605dff5ffd7..681161fc74a 100644 --- a/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java +++ b/src/jdk.management/share/classes/jdk/crac/management/internal/CRaCImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2026, Azul Systems, Inc. All rights reserved. + * Copyright (c) 2022, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,12 +52,6 @@ public long getRestoreTime() { return vm.getRestoreTime(); } - @Override - public CRaCMXBean.CheckpointableStatus getCheckpointableStatus() { - int status = vm.getCheckpointableStatus(); - return CRaCMXBean.CheckpointableStatus.fromCode(status); - } - @Override public void checkpointRestore() throws RestoreException, CheckpointException { try { From 1c88fd30100a1de3b56ba6c27402b372ea2c84f4 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 25 May 2026 10:35:33 +0200 Subject: [PATCH 07/12] Update src/hotspot/share/include/crlib/crlib_checkpointable_data.h Co-authored-by: Timofei Pushkin --- src/hotspot/share/include/crlib/crlib_checkpointable_data.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/include/crlib/crlib_checkpointable_data.h b/src/hotspot/share/include/crlib/crlib_checkpointable_data.h index a246def993e..5dd7521320c 100644 --- a/src/hotspot/share/include/crlib/crlib_checkpointable_data.h +++ b/src/hotspot/share/include/crlib/crlib_checkpointable_data.h @@ -51,4 +51,4 @@ typedef const struct crlib_checkpointable_data crlib_checkpointable_data_t; } // extern "C #endif -#endif // CRLIB_CHECKPOINTABLE_DATA_H \ No newline at end of file +#endif // CRLIB_CHECKPOINTABLE_DATA_H From 4323aac3a408ad80cd56482c0f1b96db88736c77 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 25 May 2026 10:53:19 +0200 Subject: [PATCH 08/12] Apply comments, move newArguments variable. --- src/java.base/share/classes/jdk/internal/crac/mirror/Core.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java index 67bca3af670..693e5b181dd 100644 --- a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java +++ b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java @@ -273,7 +273,6 @@ public static void checkpointRestore() throws private static void checkpointRestore(long jcmdStream) throws CheckpointException, RestoreException { - final List newArguments; int status_code = getCheckpointableStatus0(); switch (CheckpointableStatus.fromCode(status_code)) { case NEVER_AFTER_RESTORE -> { @@ -294,6 +293,8 @@ private static void checkpointRestore(long jcmdStream) throws } } + final List newArguments; + // checkpointRestoreLock protects against the simultaneous // call of checkpointRestore from different threads. synchronized (checkpointRestoreLock) { From dd687efabc53f75bd1778e4620847c6be1cdf357 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 25 May 2026 10:54:44 +0200 Subject: [PATCH 09/12] Apply comment. Move checkpointable_data_extension.header on the top of extensions. --- src/java.base/linux/native/libcriuengine/criuengine.cpp | 2 +- src/java.base/share/native/libsimengine/simengine.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/linux/native/libcriuengine/criuengine.cpp b/src/java.base/linux/native/libcriuengine/criuengine.cpp index e5b84cedec0..b24c71e63d7 100644 --- a/src/java.base/linux/native/libcriuengine/criuengine.cpp +++ b/src/java.base/linux/native/libcriuengine/criuengine.cpp @@ -991,12 +991,12 @@ static crlib_checkpointable_data_t checkpointable_data_extension = { }; static const crlib_extension_t* extensions[] = { + &checkpointable_data_extension.header, &restore_data_extension.header, &image_constraints_extension.header, &image_score_extension.header, &user_data_extension.header, &description_extension.header, - &checkpointable_data_extension.header, nullptr }; diff --git a/src/java.base/share/native/libsimengine/simengine.cpp b/src/java.base/share/native/libsimengine/simengine.cpp index 55e7738b60e..fdc0f10419d 100644 --- a/src/java.base/share/native/libsimengine/simengine.cpp +++ b/src/java.base/share/native/libsimengine/simengine.cpp @@ -302,11 +302,11 @@ static crlib_checkpointable_data_t checkpointable_data_extension = { }; static const crlib_extension_t *extensions[] = { + &checkpointable_data_extension.header, &restore_data_extension.header, &image_constraints_extension.header, &image_score_extension.header, &description_extension.header, - &checkpointable_data_extension.header, nullptr }; From d4b365bc7c62147892b891cdac5699634472ad24 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 25 May 2026 10:57:21 +0200 Subject: [PATCH 10/12] Apply comments, put IllegalStateExceptions usage --- .../share/classes/jdk/internal/crac/mirror/Core.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java index 693e5b181dd..e7d2323b4a3 100644 --- a/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java +++ b/src/java.base/share/classes/jdk/internal/crac/mirror/Core.java @@ -277,12 +277,12 @@ private static void checkpointRestore(long jcmdStream) throws switch (CheckpointableStatus.fromCode(status_code)) { case NEVER_AFTER_RESTORE -> { CheckpointException ex = new CheckpointException(); - ex.addSuppressed(new Exception("Current engine doesn't support second checkpoint after restore.")); + ex.addSuppressed(new IllegalStateException("Current engine doesn't support second checkpoint after restore.")); throw ex; } case READY_LATER -> { CheckpointException ex = new CheckpointException(); - ex.addSuppressed(new Exception("CRaC cannot commit checkpoint right now, try later.")); + ex.addSuppressed(new IllegalStateException("CRaC cannot commit checkpoint right now, try later.")); throw ex; } case READY -> { From 7f1313aeb9712be6a7108bf3202037bf41f03fa0 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 25 May 2026 11:53:01 +0200 Subject: [PATCH 11/12] Fix copyright --- .../classes/jdk/internal/crac/mirror/CheckpointableStatus.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java b/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java index 41b3e6debea..67e7dfe272d 100644 --- a/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java +++ b/src/java.base/share/classes/jdk/internal/crac/mirror/CheckpointableStatus.java @@ -1,6 +1,5 @@ /* * Copyright (c) 2026, Azul Systems, Inc. All rights reserved. - * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it From dc1487e8f813309b27dd94782fae93f8711c1163 Mon Sep 17 00:00:00 2001 From: Anton Voznia Date: Mon, 25 May 2026 14:42:28 +0200 Subject: [PATCH 12/12] Applied comments. Renamed checkpointable_data -> checkpoint_availability --- ...data.h => crlib_checkpoint_availability.h} | 26 +++++++++---------- src/hotspot/share/runtime/crac.cpp | 18 +++++++++---- src/hotspot/share/runtime/crac_engine.cpp | 10 +++---- src/hotspot/share/runtime/crac_engine.hpp | 8 +++--- .../linux/native/libcriuengine/criuengine.cpp | 21 +++++++++------ .../share/native/libsimengine/simengine.cpp | 14 +++++----- 6 files changed, 55 insertions(+), 42 deletions(-) rename src/hotspot/share/include/crlib/{crlib_checkpointable_data.h => crlib_checkpoint_availability.h} (61%) diff --git a/src/hotspot/share/include/crlib/crlib_checkpointable_data.h b/src/hotspot/share/include/crlib/crlib_checkpoint_availability.h similarity index 61% rename from src/hotspot/share/include/crlib/crlib_checkpointable_data.h rename to src/hotspot/share/include/crlib/crlib_checkpoint_availability.h index 5dd7521320c..962f7dd008e 100644 --- a/src/hotspot/share/include/crlib/crlib_checkpointable_data.h +++ b/src/hotspot/share/include/crlib/crlib_checkpoint_availability.h @@ -20,8 +20,8 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ -#ifndef CRLIB_CHECKPOINTABLE_DATA_H -#define CRLIB_CHECKPOINTABLE_DATA_H +#ifndef CRLIB_CHECKPOINT_AVAILABILITY_H +#define CRLIB_CHECKPOINT_AVAILABILITY_H #include "crlib.h" @@ -29,26 +29,26 @@ extern "C" { #endif -#define CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME "checkpointable data" +#define CRLIB_EXTENSION_CHECKPOINT_AVAILABILITY_NAME "checkpointable data" #define CRLIB_EXTENSION_CHECKPOINTABLE(api) \ - CRLIB_EXTENSION(api, crlib_checkpointable_data_t, CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME) + CRLIB_EXTENSION(api, crlib_checkpoint_availability_t, CRLIB_EXTENSION_CHECKPOINT_CRLIB_CHECKPOINT_AVAILABILITY_NAME) + +typedef int crlib_checkpointable_status_t; +#define CRLIB_CHECKPOINTABLE_NEVER 0 // engine will never accept another checkpoint +#define CRLIB_CHECKPOINTABLE_NOT_YET 1 // not now; may become ready later +#define CRLIB_CHECKPOINTABLE_READY 2 // checkpoint can proceed -typedef enum checkpointable_status { - never_after_restore, // it's not able to commit a new checkpoint after restore - ready_late, // at some point it could become checkpointable - ready // checkpointable -} checkpointable_status_t; // API for obtaining information about chackpointable status. -struct crlib_checkpointable_data { +struct crlib_checkpoint_availability { crlib_extension_t header; - checkpointable_status_t (*get_checkpointable_status)(crlib_conf_t *); + crlib_checkpointable_status_t (*get_checkpointable_status)(crlib_conf_t *); }; -typedef const struct crlib_checkpointable_data crlib_checkpointable_data_t; +typedef const struct crlib_checkpoint_availability crlib_checkpoint_availability_t; #ifdef __cplusplus } // extern "C #endif -#endif // CRLIB_CHECKPOINTABLE_DATA_H +#endif // CRLIB_CHECKPOINT_AVAILABILITY_H \ No newline at end of file diff --git a/src/hotspot/share/runtime/crac.cpp b/src/hotspot/share/runtime/crac.cpp index 8e96e65180a..f949c2f90d0 100644 --- a/src/hotspot/share/runtime/crac.cpp +++ b/src/hotspot/share/runtime/crac.cpp @@ -81,13 +81,21 @@ jlong crac::uptime_since_restore() { } jint crac::checkpointable_status() { - bool is_checkpointable = true; - if ((crac::_generation > 1) && - (crac::_engine->prepare_checkpointable_data_api() == CracEngine::ApiStatus::OK)) { - return crac::_engine->get_checkpointable_status(); + if (crac::_engine->prepare_checkpoint_availability_api() == CracEngine::ApiStatus::OK) { + crlib_checkpointable_status_t status = crac::_engine->get_checkpointable_status(); + if (status == CRLIB_CHECKPOINTABLE_NEVER) { + if (crac::_generation > 1) { + return status; + } else { + // Engine doesn't support checkpoint after restore, + // but it's a first checkpoint. So return READY. + return CRLIB_CHECKPOINTABLE_READY; + } + } + return status; } - return ready; + return CRLIB_CHECKPOINTABLE_READY; } void VM_Crac::print_resources(const char* msg, ...) { diff --git a/src/hotspot/share/runtime/crac_engine.cpp b/src/hotspot/share/runtime/crac_engine.cpp index 69952b2a205..ca3bd7282d4 100644 --- a/src/hotspot/share/runtime/crac_engine.cpp +++ b/src/hotspot/share/runtime/crac_engine.cpp @@ -607,12 +607,12 @@ bool CracEngine::set_score(const char* metric, double value) { return _image_score_api->set_score(_conf, metric, value); } -CracEngine::ApiStatus CracEngine::prepare_checkpointable_data_api() { - prepare_extension_api(_checkpointable_data_api, CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME) +CracEngine::ApiStatus CracEngine::prepare_checkpoint_availability_api() { + prepare_extension_api(_checkpoint_availability_api, CRLIB_EXTENSION_CHECKPOINT_AVAILABILITY_NAME) require_method(get_checkpointable_status) - complete_extension_api(_checkpointable_data_api) + complete_extension_api(_checkpoint_availability_api) } -checkpointable_status_t CracEngine::get_checkpointable_status() { - return _checkpointable_data_api->get_checkpointable_status(_conf); +crlib_checkpointable_status_t CracEngine::get_checkpointable_status() { + return _checkpoint_availability_api->get_checkpointable_status(_conf); } diff --git a/src/hotspot/share/runtime/crac_engine.hpp b/src/hotspot/share/runtime/crac_engine.hpp index 1ae4a3f0951..b4f4b0a3270 100644 --- a/src/hotspot/share/runtime/crac_engine.hpp +++ b/src/hotspot/share/runtime/crac_engine.hpp @@ -25,7 +25,7 @@ #define SHARE_RUNTIME_CRAC_ENGINE_HPP #include "crlib/crlib.h" -#include "crlib/crlib_checkpointable_data.h" +#include "crlib/crlib_checkpoint_availability.h" #include "crlib/crlib_description.h" #include "crlib/crlib_image_constraints.h" #include "crlib/crlib_image_score.h" @@ -80,8 +80,8 @@ class CracEngine : public CHeapObj { ApiStatus prepare_image_score_api(); bool set_score(const char* metric, double value); - ApiStatus prepare_checkpointable_data_api(); - checkpointable_status_t get_checkpointable_status(); + ApiStatus prepare_checkpoint_availability_api(); + crlib_checkpointable_status_t get_checkpointable_status(); private: char _name[MAX_ENGINE_LENGTH]; @@ -94,7 +94,7 @@ class CracEngine : public CHeapObj { crlib_description_t *_description_api = nullptr; crlib_image_constraints_t *_image_constraints_api = nullptr; crlib_image_score_t *_image_score_api = nullptr; - crlib_checkpointable_data_t *_checkpointable_data_api = nullptr; + crlib_checkpoint_availability_t *_checkpoint_availability_api = nullptr; crlib_conf_option_t *_options = nullptr; }; diff --git a/src/java.base/linux/native/libcriuengine/criuengine.cpp b/src/java.base/linux/native/libcriuengine/criuengine.cpp index b24c71e63d7..27ba5eeea37 100644 --- a/src/java.base/linux/native/libcriuengine/criuengine.cpp +++ b/src/java.base/linux/native/libcriuengine/criuengine.cpp @@ -38,7 +38,7 @@ #include #include -#include "crlib/crlib_checkpointable_data.h" +#include "crlib/crlib_checkpoint_availability.h" #include "crlib/crlib_description.h" #include "crlib/crlib_restore_data.h" #include "crlib/crlib_user_data.h" @@ -496,11 +496,16 @@ static char* get_relative_file(const char* rel) { return buf; } -static checkpointable_status_t get_checkpointable_status(crlib_conf_t * conf) { +static crlib_checkpointable_status_t get_checkpointable_status(crlib_conf_t * conf) { if (!conf->direct_map()) { - return ready; + return CRLIB_CHECKPOINTABLE_READY; } - return never_after_restore; + + // With direct_map, restored memory pages are mmap'd directly from the + // checkpoint image file rather than copied into anonymous memory. A second + // checkpoint would overwrite that same image, corrupting the live mappings + // of the running process. CRIU has no safe way to re-checkpoint in this mode. + return CRLIB_CHECKPOINTABLE_NEVER; } const char* criuengine::get_criu() { @@ -982,17 +987,17 @@ static crlib_user_data_t user_data_extension = { destroy_user_data, }; -static crlib_checkpointable_data_t checkpointable_data_extension = { +static crlib_checkpoint_availability_t checkpoint_availability_extension = { { - CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME, - sizeof(checkpointable_data_extension) + CRLIB_EXTENSION_CHECKPOINT_AVAILABILITY_NAME, + sizeof(checkpoint_availability_extension) }, get_checkpointable_status, }; static const crlib_extension_t* extensions[] = { - &checkpointable_data_extension.header, &restore_data_extension.header, + &checkpoint_availability_extension.header, &image_constraints_extension.header, &image_score_extension.header, &user_data_extension.header, diff --git a/src/java.base/share/native/libsimengine/simengine.cpp b/src/java.base/share/native/libsimengine/simengine.cpp index fdc0f10419d..66823953cf7 100644 --- a/src/java.base/share/native/libsimengine/simengine.cpp +++ b/src/java.base/share/native/libsimengine/simengine.cpp @@ -36,7 +36,7 @@ #endif // LINUX #include "crcommon.hpp" -#include "crlib/crlib_checkpointable_data.h" +#include "crlib/crlib_checkpoint_availability.h" #include "crlib/crlib_restore_data.h" #include "crlib/crlib_description.h" #include "jni.h" @@ -289,21 +289,21 @@ static crlib_description_t description_extension = { configuration_options, }; -static checkpointable_status_t get_checkpointable_status(crlib_conf_t *) { - return ready; +static crlib_checkpointable_status_t get_checkpointable_status(crlib_conf_t *) { + return CRLIB_CHECKPOINTABLE_READY; } -static crlib_checkpointable_data_t checkpointable_data_extension = { +static crlib_checkpoint_availability checkpoint_availability_extension = { { - CRLIB_EXTENSION_CHECKPOINTABLE_DATA_NAME, - sizeof(checkpointable_data_extension) + CRLIB_EXTENSION_CHECKPOINT_AVAILABILITY_NAME, + sizeof(checkpoint_availability_extension) }, get_checkpointable_status, }; static const crlib_extension_t *extensions[] = { - &checkpointable_data_extension.header, &restore_data_extension.header, + &checkpoint_availability_extension.header, &image_constraints_extension.header, &image_score_extension.header, &description_extension.header,