diff --git a/src/hotspot/share/include/crlib/crlib_description.h b/src/hotspot/share/include/crlib/crlib_description.h index 6b6884a3a0a..0dccbe02e7f 100644 --- a/src/hotspot/share/include/crlib/crlib_description.h +++ b/src/hotspot/share/include/crlib/crlib_description.h @@ -50,13 +50,10 @@ struct crlib_description { // Returns a valid C-string with a formatted list of configuration keys supported by the engine // with their descriptions, or null on error. // - // Some keys can be excluded if they are not supposed to be set by a user but rather by the - // application the engine is linked to. - // // Example: // " // * do_stuff= (default: true) — whether to do stuff.\n - // * args= (default: \"\") — other arguments. + // * args= (default: \"\") — other arguments.\n // " const char *(*configuration_doc)(crlib_conf_t *); diff --git a/src/hotspot/share/runtime/crac.cpp b/src/hotspot/share/runtime/crac.cpp index 021036fb515..7b1abb5ef5f 100644 --- a/src/hotspot/share/runtime/crac.cpp +++ b/src/hotspot/share/runtime/crac.cpp @@ -31,6 +31,7 @@ #include "logging/logConfiguration.hpp" #include "memory/allocation.hpp" #include "memory/oopFactory.hpp" +#include "nmt/memTag.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/crac_engine.hpp" @@ -50,6 +51,7 @@ #include "os.inline.hpp" #include "utilities/defaultStream.hpp" #include "utilities/globalDefinitions.hpp" +#include "utilities/growableArray.hpp" #include "utilities/ostream.hpp" static jlong _restore_start_time; @@ -323,6 +325,17 @@ void crac::print_engine_info_and_exit() { tty->print_raw_cr("Configuration options:"); tty->print_raw(conf_doc); // Doc string ends with CR by convention + const char * const *controlled_opts = CracEngine::vm_controlled_options(); + tty->cr(); + tty->print_raw("Configuration options controlled by the JVM: "); + for (const auto *opt = controlled_opts; *opt != nullptr; opt++) { + tty->print_raw(*opt); + if (*(opt + 1) != nullptr) { + tty->print_raw(", "); + } + } + tty->cr(); + vm_exit(0); ShouldNotReachHere(); } diff --git a/src/hotspot/share/runtime/crac_engine.cpp b/src/hotspot/share/runtime/crac_engine.cpp index ac8798c7d37..b5ae02bbf7a 100644 --- a/src/hotspot/share/runtime/crac_engine.cpp +++ b/src/hotspot/share/runtime/crac_engine.cpp @@ -1,9 +1,33 @@ +/* + * 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. + */ + #include "precompiled.hpp" #include "crlib/crlib.h" #include "crlib/crlib_restore_data.h" #include "logging/log.hpp" #include "memory/allStatic.hpp" +#include "nmt/memTag.hpp" #include "runtime/crac_engine.hpp" #include "runtime/globals.hpp" #include "runtime/os.hpp" @@ -15,8 +39,19 @@ #include // CRaC engine configuration options JVM sets directly instead of relaying from the user -#define ENGINE_OPT_IMAGE_LOCATION "image_location" -#define ENGINE_OPT_EXEC_LOCATION "exec_location" +#define VM_CONTROLLED_ENGINE_OPTS(OPT) \ + OPT(image_location) \ + OPT(exec_location) \ + +#define ARRAY_ELEM(opt) #opt, +static constexpr const char * const vm_controlled_engine_opts[] = { + VM_CONTROLLED_ENGINE_OPTS(ARRAY_ELEM) nullptr +}; +#undef ARRAY_ELEM + +#define DEFINE_OPT_VAR(opt) static constexpr const char engine_opt_##opt[] = #opt; +VM_CONTROLLED_ENGINE_OPTS(DEFINE_OPT_VAR) +#undef DEFINE_OPT_VAR #ifdef _WINDOWS static char *strsep(char **strp, const char *delim) { @@ -35,6 +70,10 @@ static char *strsep(char **strp, const char *delim) { } #endif // _WINDOWS +const char * const *CracEngine::vm_controlled_options() { + return vm_controlled_engine_opts; +} + static bool find_engine(const char *dll_dir, char *path, size_t path_size, bool *is_library) { // Try to interpret as a file path if (os::is_path_absolute(CRaCEngine)) { @@ -111,8 +150,8 @@ static bool find_engine(const char *dll_dir, char *path, size_t path_size, bool static bool configure_image_location(const crlib_api_t &api, crlib_conf_t *conf, const char *image_location) { precond(image_location != nullptr && image_location[0] != '\0'); - if (!api.configure(conf, ENGINE_OPT_IMAGE_LOCATION, image_location)) { - log_error(crac)("CRaC engine failed to configure: '" ENGINE_OPT_IMAGE_LOCATION "' = '%s'", image_location); + if (!api.configure(conf, engine_opt_image_location, image_location)) { + log_error(crac)("CRaC engine failed to configure: '%s' = '%s'", engine_opt_image_location, image_location); return false; } return true; @@ -156,10 +195,10 @@ static crlib_conf_t *create_conf(const crlib_api_t &api, const char *image_locat } if (exec_location != nullptr) { // Only passed when using crexec - guarantee(api.can_configure(conf, ENGINE_OPT_EXEC_LOCATION), - "crexec does not support an internal option: " ENGINE_OPT_EXEC_LOCATION); - if (!api.configure(conf, ENGINE_OPT_EXEC_LOCATION, exec_location)) { - log_error(crac)("crexec failed to configure: '" ENGINE_OPT_EXEC_LOCATION "' = '%s'", exec_location); + guarantee(api.can_configure(conf, engine_opt_exec_location), + "crexec does not support expected option: %s", engine_opt_exec_location); + if (!api.configure(conf, engine_opt_exec_location, exec_location)) { + log_error(crac)("crexec failed to configure: '%s' = '%s'", engine_opt_exec_location, exec_location); api.destroy_conf(conf); return nullptr; } @@ -169,6 +208,11 @@ static crlib_conf_t *create_conf(const crlib_api_t &api, const char *image_locat return conf; } + CStringSet vm_controlled_keys; +#define PUT_CONTROLLED_KEY(opt) vm_controlled_keys.put_when_absent(engine_opt_##opt, false); + VM_CONTROLLED_ENGINE_OPTS(PUT_CONTROLLED_KEY) +#undef PUT_CONTROLLED_KEY + char *engine_options = os::strdup_check_oom(CRaCEngineOptions, mtInternal); char *const engine_options_start = engine_options; CStringSet keys; @@ -177,9 +221,8 @@ static crlib_conf_t *create_conf(const crlib_api_t &api, const char *image_locat const char *key = strsep(&key_value, "="); const char *value = key_value != nullptr ? key_value : ""; assert(key != nullptr, "Should have terminated before"); - if (strcmp(key, ENGINE_OPT_IMAGE_LOCATION) == 0 || - (exec_location != nullptr && strcmp(key, ENGINE_OPT_EXEC_LOCATION) == 0)) { - log_warning(crac)("Internal CRaC engine option provided, skipping: %s", key); + if (vm_controlled_keys.contains(key)) { + log_warning(crac)("VM-controlled CRaC engine option provided, skipping: %s", key); continue; } { diff --git a/src/hotspot/share/runtime/crac_engine.hpp b/src/hotspot/share/runtime/crac_engine.hpp index 7764626f7ed..d031cd6e405 100644 --- a/src/hotspot/share/runtime/crac_engine.hpp +++ b/src/hotspot/share/runtime/crac_engine.hpp @@ -36,6 +36,8 @@ // CRaC engine library wrapper. class CracEngine : public CHeapObj { public: + static const char * const *vm_controlled_options(); + explicit CracEngine(const char *image_location = nullptr); ~CracEngine(); diff --git a/src/java.base/share/native/libcrexec/crexec.cpp b/src/java.base/share/native/libcrexec/crexec.cpp index 706338e5559..075deb869b3 100644 --- a/src/java.base/share/native/libcrexec/crexec.cpp +++ b/src/java.base/share/native/libcrexec/crexec.cpp @@ -362,18 +362,16 @@ static const char *description(crlib_conf_t *conf) { } static const char *configuration_doc(crlib_conf_t *conf) { - // Internal options which are expected to be set by the program crexec is linked to are omitted - // since users are not supposed to pass them directly: - // * image_location= (no default) - path to a directory with checkpoint/restore files. - // * exec_location= (no default) - path to the engine executable. return + "* image_location= (no default) - path to a directory with checkpoint/restore files.\n" + "* exec_location= (no default) - path to the engine executable.\n" "* keep_running= (default: false) - keep the process running after the checkpoint " "or kill it.\n" "* direct_map= (default: true) - on restore, map process data directly from saved " "files. This may speedup the restore but the resulting process will not be the same as before " "the checkpoint.\n" "* args= (default: \"\") - free space-separated arguments passed directly to the " - "engine executable, e.g. \"--arg1 --arg2 --arg3\"."; + "engine executable, e.g. \"--arg1 --arg2 --arg3\".\n"; } static const char * const *configurable_keys(crlib_conf_t *conf) { diff --git a/test/jdk/jdk/crac/engineOptions/ParsingTest.java b/test/jdk/jdk/crac/engineOptions/ParsingTest.java index a9cf0bc91e8..b332276b84b 100644 --- a/test/jdk/jdk/crac/engineOptions/ParsingTest.java +++ b/test/jdk/jdk/crac/engineOptions/ParsingTest.java @@ -81,7 +81,7 @@ public void test_engines() throws Exception { public void test_options() throws Exception { test("simengine", ""); test("simengine", "image_location=cr", 0, - "Internal CRaC engine option provided, skipping: image_location"); + "VM-controlled CRaC engine option provided, skipping: image_location"); if (Platform.isLinux()) { test("criuengine", Arrays.asList("keep_running=true,args=-v -v -v -v"), 0, Arrays.asList(