diff --git a/openjdk-17.spec b/openjdk-17.spec index 5b3ee7ceb12f5f23c0954d6816f51746e41ebed1..0d485fef2d690fa528c65ae5789ac0100d7afbc0 100644 --- a/openjdk-17.spec +++ b/openjdk-17.spec @@ -920,7 +920,7 @@ Provides: java-src%{?1} = %{epoch}:%{version}-%{release} Name: java-%{javaver}-%{origin} Version: %{newjavaver}.%{buildver} -Release: 1 +Release: 2 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages @@ -1075,6 +1075,8 @@ Patch83: huawei-AArch64-Incorrect-matching-rule.patch #17.0.16 Patch84: huawei-remove-provides-in-kaeprovider-module-info.patch +Patch85: support-numactl.patch +Patch86: simplify-the-parameters-for-appcds.patch ############################################ # @@ -1377,6 +1379,8 @@ pushd %{top_level_dir_name} %patch 82 -p1 %patch 83 -p1 %patch 84 -p1 +%patch 85 -p1 +%patch 86 -p1 popd # openjdk %endif @@ -2001,6 +2005,10 @@ cjc.mainProgram(args) -- the returns from copy_jdk_configs.lua should not affect %changelog +* Tue Aug 5 2025 neu-mobi 1:17.0.16.8-2 +- add support-numactl.patch +- add simplify-the-parameters-for-appcds.patch + * Thu Jul 17 2025 benshuai5d 1:17.0.16.8-1 - add huawei-remove-provides-in-kaeprovider-module-info.patch diff --git a/simplify-the-parameters-for-appcds.patch b/simplify-the-parameters-for-appcds.patch new file mode 100644 index 0000000000000000000000000000000000000000..b8a43f06c9c342c05846734dcb8775358a5c0f2e --- /dev/null +++ b/simplify-the-parameters-for-appcds.patch @@ -0,0 +1,313 @@ +From f3ae69f4bf36d8276bdb6b24d6095d55a0cfd08f Mon Sep 17 00:00:00 2001 +Date: Tue, 5 Aug 2025 15:49:17 +0800 +Subject: simplify the parameters for appcds + +--- + src/hotspot/cpu/aarch64/globals_aarch64.hpp | 7 +- + .../linux_aarch64/thread_linux_aarch64.cpp | 209 ++++++++++++++++++ + .../linux_aarch64/thread_linux_aarch64.hpp | 2 + + src/hotspot/share/cds/filemap.cpp | 16 +- + src/hotspot/share/runtime/thread.cpp | 2 + + 5 files changed, 228 insertions(+), 8 deletions(-) + +diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp +index cae9fb60c..9e65abc2f 100644 +--- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp ++++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp +@@ -122,7 +122,12 @@ define_pd_global(intx, InlineSmallCode, 1000); + range(1, 99) \ + product(bool, UseTBI, false, EXPERIMENTAL, \ + "Use the \"Top Byte Ignore\" feature for ZGC." \ +- "And use 64 bit literal addresses instead of 48 bit.") ++ "And use 64 bit literal addresses instead of 48 bit.") \ ++ product(ccstr, AutoSharedArchivePath, NULL, \ ++ "Auto enable the AppCDS feature" \ ++ "the path save classlist and jsa file") \ ++ product(bool, PrintAutoAppCDS, false, \ ++ "Print path and some information about AutoSharedArchivePath") + + // end of ARCH_FLAGS + +diff --git a/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp +index fca22629b..2cb62173e 100644 +--- a/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp ++++ b/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.cpp +@@ -23,10 +23,20 @@ + * + */ + ++#include "os_linux.inline.hpp" + #include "precompiled.hpp" ++#if INCLUDE_AGGRESSIVE_CDS ++#include "jbooster/jbooster_globals.hpp" ++#endif ++#include "runtime/arguments.hpp" + #include "runtime/frame.inline.hpp" ++#include "runtime/globals.hpp" ++#include "runtime/globals_extension.hpp" ++#include "runtime/java.hpp" + #include "runtime/thread.inline.hpp" + ++#include ++ + frame JavaThread::pd_last_frame() { + assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); + return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); +@@ -90,3 +100,202 @@ bool JavaThread::pd_get_top_frame(frame* fr_addr, void* ucontext, bool isInJava) + } + + void JavaThread::cache_global_variables() { } ++ ++static char* get_java_executable_path() { ++ const char* java_home = Arguments::get_property("java.home"); ++ if (java_home != NULL) { ++ char* path = NEW_C_HEAP_ARRAY(char, MAXPATHLEN, mtInternal); ++ jio_snprintf(path, MAXPATHLEN, "%s/bin/java", java_home); ++ return path; ++ } ++ return os::strdup("java"); ++} ++ ++static char* get_complete_classpath() { ++ const char* env_cp = Arguments::get_property("env.class.path"); ++ if (env_cp == NULL || env_cp[0] == '\0') { ++ env_cp = ::getenv("CLASSPATH"); ++ } ++ return (char *)env_cp; ++} ++ ++static bool can_read_classlist(const char* class_list_path) { ++ int fd = open(class_list_path, O_RDWR | O_CREAT, 0644); ++ if (fd < 0) return false; ++ return flock(fd, LOCK_EX | LOCK_NB) == 0; ++} ++ ++static void construct_path(char *dest, size_t dest_size, const char *base, const char *suffix) { ++ size_t base_len = strlen(base); ++ size_t suffix_len = strlen(suffix); ++ guarantee(base_len + suffix_len < dest_size, "base path too long!"); ++ ++ jio_snprintf(dest, dest_size, "%s%s", base, suffix); ++} ++ ++static void create_jsa(const char* class_list_path, const char* appcds_path, const JavaVMInitArgs* original_args) { ++ pid_t pid = fork(); ++ if (pid == 0) { ++ // child process running on background ++ setsid(); ++ signal(SIGHUP, SIG_IGN); ++ const char* classpath = get_complete_classpath(); ++ if (classpath == NULL) { ++ classpath = "."; ++ } ++ char* java_path = get_java_executable_path(); ++ int arg_count = Arguments::num_jvm_args(); ++ char** vm_args = Arguments::jvm_args_array(); ++ ++ int total_args = arg_count + 9; ++ char** args = NEW_C_HEAP_ARRAY(char*, total_args + 1, mtInternal); ++ int idx = 0; ++ ++ args[idx++] = java_path; ++ args[idx++] = os::strdup("-Xshare:dump"); ++ args[idx++] = os::strdup("-XX:+UnlockDiagnosticVMOptions"); ++ args[idx++] = os::strdup("-XX:+SkipSharedClassPathCheck"); ++ ++ char shared_class_list_file[PATH_MAX]; ++ construct_path(shared_class_list_file, sizeof(shared_class_list_file), "-XX:SharedClassListFile=", class_list_path); ++ args[idx++] = os::strdup(shared_class_list_file); ++ ++ char shared_archive_file[PATH_MAX]; ++ construct_path(shared_archive_file, sizeof(shared_archive_file), "-XX:SharedArchiveFile=", appcds_path); ++ args[idx++] = os::strdup(shared_archive_file); ++ ++ args[idx++] = os::strdup("-classpath"); ++ args[idx++] = os::strdup(classpath); ++ for (int i = 0; i < arg_count; i++) { ++ if (vm_args[i] != NULL && strstr(vm_args[i], "AutoSharedArchivePath") == NULL) { ++ args[idx++] = os::strdup(vm_args[i]); ++ } ++ } ++ args[idx++] = os::strdup("-version"); ++ args[idx] = NULL; ++ ++ if (PrintAutoAppCDS) { ++ int i = 0; ++ while (args[i] != NULL) { ++ tty->print_cr("args[%d] = %s", i, args[i]); ++ i++; ++ } ++ } ++ execv(java_path, args); ++ } ++} ++ ++void JavaThread::handle_appcds_for_executor(const JavaVMInitArgs* args) { ++ if (FLAG_IS_DEFAULT(AutoSharedArchivePath)) { ++ return; ++ } ++ ++ if (AutoSharedArchivePath == NULL) { ++ warning("AutoSharedArchivePath should not be empty. Please set the specific path."); ++ return; ++ } ++ ++ static char base_path[JVM_MAXPATHLEN] = {'\0'}; ++ jio_snprintf(base_path, sizeof(base_path), "%s", AutoSharedArchivePath); ++ ++ struct stat st; ++ if (stat(base_path, &st) != 0) { ++ if (mkdir(base_path, 0755) != 0) { ++ vm_exit_during_initialization(err_msg("can't create dirs %s : %s", base_path, os::strerror(errno))); ++ } ++ } ++ ++ char class_list_path[PATH_MAX]; ++ char appcds_path[PATH_MAX]; ++#if INCLUDE_AGGRESSIVE_CDS ++ char aggrecds_path[PATH_MAX]; ++#endif ++ ++ construct_path(class_list_path, sizeof(class_list_path), base_path, "/appcds.lst"); ++ construct_path(appcds_path, sizeof(appcds_path), base_path, "/appcds.jsa"); ++#if INCLUDE_AGGRESSIVE_CDS ++ construct_path(aggrecds_path, sizeof(aggrecds_path), base_path, "/aggrecds.jsa"); ++#endif ++ ++ if (PrintAutoAppCDS) { ++ tty->print_cr("classlist file : %s", class_list_path); ++ tty->print_cr("appcds jsa file : %s", appcds_path); ++#if INCLUDE_AGGRESSIVE_CDS ++ if (UseAggressiveCDS) { ++ tty->print_cr("aggressive jsa file : %s", aggrecds_path); ++ } ++#endif ++ } ++ ++ const char* class_list_ptr = class_list_path; ++ const char* appcds_ptr = appcds_path; ++#if INCLUDE_AGGRESSIVE_CDS ++ const char* aggrecds_ptr = aggrecds_path; ++ ++ if (UseAggressiveCDS) { ++ if (stat(aggrecds_path, &st) == 0) { ++ if (PrintAutoAppCDS) { ++ tty->print_cr("Use Aggressive JSA.\n"); ++ } ++ UnlockDiagnosticVMOptions = true; ++ UnlockExperimentalVMOptions = true; ++ SkipSharedClassPathCheck = true; ++ UseSharedSpaces = true; ++ RequireSharedSpaces = true; ++ JVMFlagAccess::set_ccstr(JVMFlag::find_declared_flag((char*)"SharedArchiveFile"), &aggrecds_ptr, JVMFlagOrigin::COMMAND_LINE); ++ return; ++ } ++ } ++#endif ++ ++ if (stat(appcds_path, &st) == 0) { ++#if INCLUDE_AGGRESSIVE_CDS ++ if (UseAggressiveCDS) { ++ if (PrintAutoAppCDS) { ++ tty->print_cr("Generate Aggressive JSA.\n"); ++ } ++ } ++#endif ++ UnlockDiagnosticVMOptions = true; ++ UnlockExperimentalVMOptions = true; ++ SkipSharedClassPathCheck = true; ++ UseSharedSpaces = true; ++ RequireSharedSpaces = true; ++ JVMFlagAccess::set_ccstr(JVMFlag::find_declared_flag((char*)"SharedArchiveFile"), &appcds_ptr, JVMFlagOrigin::COMMAND_LINE); ++#if INCLUDE_AGGRESSIVE_CDS ++ if (UseAggressiveCDS) { ++ DynamicDumpSharedSpaces = true; ++ JVMFlagAccess::set_ccstr(JVMFlag::find_declared_flag((char*)"ArchiveClassesAtExit"), &aggrecds_ptr, JVMFlagOrigin::COMMAND_LINE); ++ } ++#endif ++ return; ++ } ++ ++ if (stat(class_list_path, &st) == 0) { ++ if (!can_read_classlist(class_list_path)) { ++ if (PrintAutoAppCDS) { ++ tty->print_cr("classlist is generating, can't create jsa by %d now.", os::current_process_id()); ++ } ++ return; ++ } ++ if (stat(appcds_path, &st) != 0) { ++ if (PrintAutoAppCDS) { ++ tty->print_cr("generate JSA file by %d.", os::current_process_id()); ++ } ++ create_jsa(class_list_path, appcds_path, args); ++ } ++ } else { ++ if (!can_read_classlist(class_list_path)) { ++ return; ++ } ++ if (PrintAutoAppCDS) { ++ tty->print_cr("generate classlist file by %d.", os::current_process_id()); ++ } ++ if (NUMANodesRandom != 0) { ++ NUMANodesRandom = 0; ++ } ++ UseSharedSpaces = false; ++ RequireSharedSpaces = false; ++ JVMFlagAccess::set_ccstr(JVMFlag::find_declared_flag((char*)"DumpLoadedClassList"), &class_list_ptr, JVMFlagOrigin::COMMAND_LINE); ++ } ++} +diff --git a/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.hpp +index 5a1f273c5..a2bbe248f 100644 +--- a/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.hpp ++++ b/src/hotspot/os_cpu/linux_aarch64/thread_linux_aarch64.hpp +@@ -49,4 +49,6 @@ public: + + static Thread *aarch64_get_thread_helper(); + ++ static void handle_appcds_for_executor(const JavaVMInitArgs* args); ++ + #endif // OS_CPU_LINUX_AARCH64_THREAD_LINUX_AARCH64_HPP +diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp +index 13a9f22a9..ed56fbc6b 100644 +--- a/src/hotspot/share/cds/filemap.cpp ++++ b/src/hotspot/share/cds/filemap.cpp +@@ -406,14 +406,16 @@ bool SharedClassPathEntry::validate(bool is_class_path) const { + bool ok = true; + log_info(class, path)("checking shared classpath entry: %s", name); + if (os::stat(name, &st) != 0 && is_class_path) { +- if (!SkipSharedClassPathCheck || !is_dir()) { +- // If the archived module path entry does not exist at runtime, it is not fatal +- // (no need to invalid the shared archive) because the shared runtime visibility check +- // filters out any archived module classes that do not have a matching runtime +- // module path location. +- FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name); ++ if (!SkipSharedClassPathCheck) { ++ if (!is_dir()) { ++ // If the archived module path entry does not exist at runtime, it is not fatal ++ // (no need to invalid the shared archive) because the shared runtime visibility check ++ // filters out any archived module classes that do not have a matching runtime ++ // module path location. ++ FileMapInfo::fail_continue("Required classpath entry does not exist: %s", name); ++ } ++ ok = false; + } +- ok = false; + } else if (is_dir()) { + if (!SkipSharedClassPathCheck && !os::dir_is_empty(name)) { + FileMapInfo::fail_continue("directory is not empty: %s", name); +diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp +index 5e674d41b..2a97c8bf5 100644 +--- a/src/hotspot/share/runtime/thread.cpp ++++ b/src/hotspot/share/runtime/thread.cpp +@@ -2775,6 +2775,8 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { + + os::init_before_ergo(); + ++ AARCH64_ONLY(JavaThread::handle_appcds_for_executor(args)); ++ + jint ergo_result = Arguments::apply_ergo(); + if (ergo_result != JNI_OK) return ergo_result; + +-- +2.23.0 + diff --git a/support-numactl.patch b/support-numactl.patch new file mode 100644 index 0000000000000000000000000000000000000000..17dd866e0f29cc9a172b899aadc4415a8cb7fe93 --- /dev/null +++ b/support-numactl.patch @@ -0,0 +1,409 @@ +From d63317496fde652292243b0cd09090e81c1f6e64 Mon Sep 17 00:00:00 2001 +Date: Tue, 5 Aug 2025 16:05:11 +0800 +Subject: support numactl + +--- + make/data/hotspot-symbols/symbols-shared | 1 + + src/hotspot/cpu/riscv/vm_version_riscv.cpp | 4 + + src/hotspot/cpu/x86/vm_version_x86.cpp | 7 ++ + src/hotspot/os/linux/os_linux.cpp | 93 +++++++++++++++++++++- + src/hotspot/os/linux/os_linux.hpp | 52 ++++++++++++ + src/hotspot/share/prims/jni.cpp | 6 ++ + src/hotspot/share/runtime/globals.hpp | 13 +++ + src/java.base/share/native/include/jni.h | 3 + + src/java.base/share/native/libjli/java.c | 2 + + src/java.base/share/native/libjli/java.h | 3 + + src/java.base/unix/native/libjli/java_md.c | 6 ++ + 11 files changed, 189 insertions(+), 1 deletion(-) + +diff --git a/make/data/hotspot-symbols/symbols-shared b/make/data/hotspot-symbols/symbols-shared +index ab6adf06d..4fa6c1d2f 100644 +--- a/make/data/hotspot-symbols/symbols-shared ++++ b/make/data/hotspot-symbols/symbols-shared +@@ -29,6 +29,7 @@ jio_vfprintf + jio_vsnprintf + JNI_CreateJavaVM + JNI_GetCreatedJavaVMs ++JNI_SetCParam + JNI_GetDefaultJavaVMInitArgs + JVM_FindClassFromBootLoader + JVM_InitAgentProperties +diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +index 6d3640b7f..a60d1c876 100644 +--- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp ++++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp +@@ -161,6 +161,10 @@ void VM_Version::initialize() { + FLAG_SET_DEFAULT(UsePopCountInstruction, false); + } + ++ if (NUMANodesRandom != 0) { ++ FLAG_SET_DEFAULT(NUMANodesRandom, 0); ++ warning("NUMANodesRandom is not supported in this VM."); ++ } + #ifdef COMPILER2 + c2_initialize(); + #endif // COMPILER2 +diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp +index a6b7d27e2..49e69446f 100644 +--- a/src/hotspot/cpu/x86/vm_version_x86.cpp ++++ b/src/hotspot/cpu/x86/vm_version_x86.cpp +@@ -998,6 +998,13 @@ void VM_Version::get_processor_features() { + FLAG_SET_DEFAULT(UseSHA256Intrinsics, false); + } + ++#ifdef _LP64 ++ if (NUMANodesRandom != 0) { ++ FLAG_SET_DEFAULT(NUMANodesRandom, 0); ++ warning("NUMANodesRandom is not supported in this VM."); ++ } ++#endif ++ + #ifdef _LP64 + // These are only supported on 64-bit + if (UseSHA && supports_avx2() && supports_bmi2()) { +diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp +index 90f766f25..ef3addc5e 100644 +--- a/src/hotspot/os/linux/os_linux.cpp ++++ b/src/hotspot/os/linux/os_linux.cpp +@@ -161,6 +161,8 @@ enum CoredumpFilterBit { + + //////////////////////////////////////////////////////////////////////////////// + // global variables ++extern char** argv_for_execvp; ++ + julong os::Linux::_physical_memory = 0; + + address os::Linux::_initial_thread_stack_bottom = NULL; +@@ -3093,6 +3095,77 @@ static bool numa_syscall_check() { + return true; + } + ++void os::Linux::parse_numa_nodes() { ++ if (NUMANodes == NULL && NUMANodesRandom == 0) { ++ return; ++ } ++ const char* numa_nodes = NUMANodes; ++ // Max length for "%d-%d" is 24 ++ char buf[24] = {0}; ++ if (NUMANodesRandom != 0) { ++ int nodes_to_bind = NUMANodesRandom; ++ int nodes_num = Linux::numa_max_node() + 1; ++ const int MAX_NUMA = 1000000; ++ if (nodes_num > 0 && ++ nodes_num < MAX_NUMA && ++ nodes_to_bind > 0 && ++ nodes_to_bind < nodes_num) { ++ int bound = 1; ++ while (bound < nodes_to_bind) { ++ bound *= 2; ++ } ++ struct timeval tv; ++ gettimeofday(&tv,NULL); ++ srand(tv.tv_usec); ++ int first = 0; ++ if (nodes_num > bound) { ++ first = rand() % (nodes_num / bound) * bound; ++ } ++ if (bound != nodes_to_bind) { ++ first += rand() % (1 + bound - nodes_to_bind); ++ } ++ os::snprintf(buf, sizeof(buf), "%d-%d", first, first + nodes_to_bind - 1); ++ numa_nodes = buf; ++ if (LogNUMANodes) { ++ warning("NUMANodes is converted to %s, with total %d nodes!", buf, nodes_num); ++ } ++ } else { ++ if (LogNUMANodes) { ++ warning("The count of nodes to bind should be less that the count of all nodes, Skip!"); ++ } ++ return; ++ } ++ } ++ bitmask* mask = os::Linux::numa_parse_nodestring_all(numa_nodes); ++ if (!mask) { ++ if (LogNUMANodes) { ++ warning("<%s> is invalid", numa_nodes); ++ } ++ return; ++ } ++ if (os::Linux::numa_bitmask_equal(mask, os::Linux::_numa_membind_bitmask)) { ++ os::Linux::numa_bitmask_free(mask); ++ if (LogNUMANodes) { ++ warning("Mempolicy is not changed, param: %s", numa_nodes); ++ } ++ return; ++ } ++ errno = 0; ++ os::Linux::numa_run_on_node_mask(mask); ++ if (errno) { ++ perror("sched_setaffinity"); ++ } ++ errno = 0; ++ os::Linux::numa_set_membind(mask); ++ int errtmp = errno; ++ os::Linux::numa_bitmask_free(mask); ++ if (errtmp) { ++ perror("numa_set_membind"); ++ } else { ++ execvp(*argv_for_execvp, argv_for_execvp); ++ } ++} ++ + bool os::Linux::libnuma_init() { + // Requires sched_getcpu() and numa dependent syscalls support + if ((sched_getcpu() != -1) && numa_syscall_check()) { +@@ -3113,7 +3186,7 @@ bool os::Linux::libnuma_init() { + set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t, + libnuma_dlsym(handle, "numa_interleave_memory"))); + set_numa_interleave_memory_v2(CAST_TO_FN_PTR(numa_interleave_memory_v2_func_t, +- libnuma_v2_dlsym(handle, "numa_interleave_memory"))); ++ libnuma_v2_dlsym(handle, "numa_interleave_memory"))); + set_numa_set_bind_policy(CAST_TO_FN_PTR(numa_set_bind_policy_func_t, + libnuma_dlsym(handle, "numa_set_bind_policy"))); + set_numa_bitmask_isbitset(CAST_TO_FN_PTR(numa_bitmask_isbitset_func_t, +@@ -3128,6 +3201,16 @@ bool os::Linux::libnuma_init() { + libnuma_dlsym(handle, "numa_move_pages"))); + set_numa_set_preferred(CAST_TO_FN_PTR(numa_set_preferred_func_t, + libnuma_dlsym(handle, "numa_set_preferred"))); ++ set_numa_parse_nodestring_all(CAST_TO_FN_PTR(numa_parse_nodestring_all_func_t, ++ libnuma_dlsym(handle, "numa_parse_nodestring_all"))); ++ set_numa_run_on_node_mask(CAST_TO_FN_PTR(numa_run_on_node_mask_func_t, ++ libnuma_v2_dlsym(handle, "numa_run_on_node_mask"))); ++ set_numa_bitmask_equal(CAST_TO_FN_PTR(numa_bitmask_equal_func_t, ++ libnuma_v2_dlsym(handle, "numa_bitmask_equal"))); ++ set_numa_set_membind(CAST_TO_FN_PTR(numa_set_membind_func_t, ++ libnuma_v2_dlsym(handle, "numa_set_membind"))); ++ set_numa_bitmask_free(CAST_TO_FN_PTR(numa_bitmask_free_func_t, ++ libnuma_dlsym(handle, "numa_bitmask_free"))); + + if (numa_available() != -1) { + set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes")); +@@ -3135,6 +3218,9 @@ bool os::Linux::libnuma_init() { + set_numa_nodes_ptr((struct bitmask **)libnuma_dlsym(handle, "numa_nodes_ptr")); + set_numa_interleave_bitmask(_numa_get_interleave_mask()); + set_numa_membind_bitmask(_numa_get_membind()); ++ if (isbound_to_all_node()) { ++ parse_numa_nodes(); ++ } + // Create an index -> node mapping, since nodes are not always consecutive + _nindex_to_node = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(0, mtInternal); + rebuild_nindex_to_node_map(); +@@ -3317,6 +3403,11 @@ os::Linux::numa_get_interleave_mask_func_t os::Linux::_numa_get_interleave_mask; + os::Linux::numa_move_pages_func_t os::Linux::_numa_move_pages; + os::Linux::numa_set_preferred_func_t os::Linux::_numa_set_preferred; + os::Linux::NumaAllocationPolicy os::Linux::_current_numa_policy; ++os::Linux::numa_parse_nodestring_all_func_t os::Linux::_numa_parse_nodestring_all; ++os::Linux::numa_run_on_node_mask_func_t os::Linux::_numa_run_on_node_mask; ++os::Linux::numa_bitmask_equal_func_t os::Linux::_numa_bitmask_equal; ++os::Linux::numa_set_membind_func_t os::Linux::_numa_set_membind; ++os::Linux::numa_bitmask_free_func_t os::Linux::_numa_bitmask_free; + unsigned long* os::Linux::_numa_all_nodes; + struct bitmask* os::Linux::_numa_all_nodes_ptr; + struct bitmask* os::Linux::_numa_nodes_ptr; +diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp +index 594173e58..c6566f97f 100644 +--- a/src/hotspot/os/linux/os_linux.hpp ++++ b/src/hotspot/os/linux/os_linux.hpp +@@ -139,6 +139,7 @@ class Linux { + static void load_plugin_library(); + static void libpthread_init(); + static void sched_getcpu_init(); ++ static void parse_numa_nodes(); + static bool libnuma_init(); + static void* libnuma_dlsym(void* handle, const char* name); + // libnuma v2 (libnuma_1.2) symbols +@@ -209,6 +210,11 @@ class Linux { + typedef struct bitmask* (*numa_get_interleave_mask_func_t)(void); + typedef long (*numa_move_pages_func_t)(int pid, unsigned long count, void **pages, const int *nodes, int *status, int flags); + typedef void (*numa_set_preferred_func_t)(int node); ++ typedef struct bitmask* (*numa_parse_nodestring_all_func_t)(const char*); ++ typedef int (*numa_run_on_node_mask_func_t)(struct bitmask* mask); ++ typedef void (*numa_set_membind_func_t)(struct bitmask* mask); ++ typedef int (*numa_bitmask_equal_func_t)(struct bitmask* mask, struct bitmask* mask1); ++ typedef void (*numa_bitmask_free_func_t)(struct bitmask* mask); + typedef void (*numa_set_bind_policy_func_t)(int policy); + typedef int (*numa_bitmask_isbitset_func_t)(struct bitmask *bmp, unsigned int n); + typedef int (*numa_distance_func_t)(int node1, int node2); +@@ -257,6 +263,11 @@ class Linux { + static numa_get_interleave_mask_func_t _numa_get_interleave_mask; + static numa_move_pages_func_t _numa_move_pages; + static numa_set_preferred_func_t _numa_set_preferred; ++ static numa_parse_nodestring_all_func_t _numa_parse_nodestring_all; ++ static numa_run_on_node_mask_func_t _numa_run_on_node_mask; ++ static numa_bitmask_equal_func_t _numa_bitmask_equal; ++ static numa_set_membind_func_t _numa_set_membind; ++ static numa_bitmask_free_func_t _numa_bitmask_free; + static unsigned long* _numa_all_nodes; + static struct bitmask* _numa_all_nodes_ptr; + static struct bitmask* _numa_nodes_ptr; +@@ -279,6 +290,11 @@ class Linux { + static void set_numa_get_interleave_mask(numa_get_interleave_mask_func_t func) { _numa_get_interleave_mask = func; } + static void set_numa_move_pages(numa_move_pages_func_t func) { _numa_move_pages = func; } + static void set_numa_set_preferred(numa_set_preferred_func_t func) { _numa_set_preferred = func; } ++ static void set_numa_parse_nodestring_all(numa_parse_nodestring_all_func_t func) { _numa_parse_nodestring_all = func; } ++ static void set_numa_run_on_node_mask(numa_run_on_node_mask_func_t func) { _numa_run_on_node_mask = func; } ++ static void set_numa_bitmask_equal(numa_bitmask_equal_func_t func) { _numa_bitmask_equal = func; } ++ static void set_numa_set_membind(numa_set_membind_func_t func) { _numa_set_membind = func; } ++ static void set_numa_bitmask_free(numa_bitmask_free_func_t func) { _numa_bitmask_free = func; } + static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; } + static void set_numa_all_nodes_ptr(struct bitmask **ptr) { _numa_all_nodes_ptr = (ptr == NULL ? NULL : *ptr); } + static void set_numa_nodes_ptr(struct bitmask **ptr) { _numa_nodes_ptr = (ptr == NULL ? NULL : *ptr); } +@@ -493,6 +509,42 @@ class Linux { + } + } + ++ static bool isbound_to_all_node() { ++ if (_numa_membind_bitmask != NULL && _numa_max_node != NULL && _numa_bitmask_isbitset != NULL) { ++ unsigned int highest_node_number = _numa_max_node(); ++ for (unsigned int node = 0; node <= highest_node_number; node++) { ++ if (!_numa_bitmask_isbitset(_numa_membind_bitmask, node)) { ++ return false; ++ } ++ } ++ } ++ return true; ++ } ++ ++ static bitmask* numa_parse_nodestring_all(const char* s) { ++ return _numa_parse_nodestring_all != NULL ? _numa_parse_nodestring_all(s) : NULL; ++ } ++ ++ static int numa_run_on_node_mask(bitmask* bitmask) { ++ return _numa_run_on_node_mask != NULL ? _numa_run_on_node_mask(bitmask) : -1; ++ } ++ ++ static int numa_bitmask_equal(bitmask* bitmask, struct bitmask* bitmask1) { ++ return _numa_bitmask_equal != NULL ? _numa_bitmask_equal(bitmask, bitmask1) : 1; ++ } ++ ++ static void numa_set_membind(bitmask* bitmask) { ++ if (_numa_set_membind != NULL) { ++ _numa_set_membind(bitmask); ++ } ++ } ++ ++ static void numa_bitmask_free(bitmask* bitmask) { ++ if (_numa_bitmask_free != NULL) { ++ _numa_bitmask_free(bitmask); ++ } ++ } ++ + #if INCLUDE_AGGRESSIVE_CDS + static void jboosterAggressiveCDS_do(uintptr_t related_data[], address ik, address class_loader, address pd, address thread) { + if (_jboosterAggressiveCDS_do != NULL) { +diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp +index fee9fdfbc..e9a51b012 100644 +--- a/src/hotspot/share/prims/jni.cpp ++++ b/src/hotspot/share/prims/jni.cpp +@@ -3579,6 +3579,12 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { + DT_RETURN_MARK_DECL(CreateJavaVM, jint + , HOTSPOT_JNI_CREATEJAVAVM_RETURN(_ret_ref)); + ++const char** argv_for_execvp; ++ ++_JNI_IMPORT_OR_EXPORT_ void JNICALL JNI_SetCParam(char** raw_argv) { ++ argv_for_execvp = (const char**)raw_argv; ++} ++ + static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { + HOTSPOT_JNI_CREATEJAVAVM_ENTRY((void **) vm, penv, args); + +diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp +index 4f02cb31a..eb5733b4d 100644 +--- a/src/hotspot/share/runtime/globals.hpp ++++ b/src/hotspot/share/runtime/globals.hpp +@@ -224,6 +224,19 @@ const intx ObjectAlignmentInBytes = 8; + "Maximum number of pages to include in the page scan procedure") \ + range(0, max_uintx) \ + \ ++ product(bool, LogNUMANodes, false, \ ++ "Print NUMANodes") \ ++ \ ++ product(ccstr, NUMANodes, NULL, \ ++ "This parameter provides the same functionality as" \ ++ "'numactl --all -N -m '." \ ++ " can be '0-2', '0,1,2', 'all' and so on.") \ ++ \ ++ product(uintx, NUMANodesRandom, 0, \ ++ "Number of continuous nodes to bind" \ ++ "with the first node randomly chosen." \ ++ "NUMANodesRandom has higher priority than NUMANodes") \ ++ \ + product(bool, UseAES, false, \ + "Control whether AES instructions are used when available") \ + \ +diff --git a/src/java.base/share/native/include/jni.h b/src/java.base/share/native/include/jni.h +index aa0cdf5c2..81593cf58 100644 +--- a/src/java.base/share/native/include/jni.h ++++ b/src/java.base/share/native/include/jni.h +@@ -1962,6 +1962,9 @@ JNI_GetDefaultJavaVMInitArgs(void *args); + _JNI_IMPORT_OR_EXPORT_ jint JNICALL + JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); + ++_JNI_IMPORT_OR_EXPORT_ void JNICALL ++JNI_SetCParam(char **raw_argv); ++ + _JNI_IMPORT_OR_EXPORT_ jint JNICALL + JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); + +diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c +index 18c515d86..b8be8b2f7 100644 +--- a/src/java.base/share/native/libjli/java.c ++++ b/src/java.base/share/native/libjli/java.c +@@ -287,6 +287,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ + + ifn.CreateJavaVM = 0; + ifn.GetDefaultJavaVMInitArgs = 0; ++ ifn.raw_argv = argv; + + if (JLI_IsTraceLauncher()) { + start = CurrentTimeMicros(); +@@ -1460,6 +1461,7 @@ InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) + i, args.options[i].optionString); + } + ++ ifn->SetCParam(ifn->raw_argv); + r = ifn->CreateJavaVM(pvm, (void **)penv, &args); + JLI_MemFree(options); + return r == JNI_OK; +diff --git a/src/java.base/share/native/libjli/java.h b/src/java.base/share/native/libjli/java.h +index f768b58a0..3a583a022 100644 +--- a/src/java.base/share/native/libjli/java.h ++++ b/src/java.base/share/native/libjli/java.h +@@ -77,13 +77,16 @@ + * Pointers to the needed JNI invocation API, initialized by LoadJavaVM. + */ + typedef jint (JNICALL *CreateJavaVM_t)(JavaVM **pvm, void **env, void *args); ++typedef void (JNICALL *SetCParam_t)(char** raw_argv); + typedef jint (JNICALL *GetDefaultJavaVMInitArgs_t)(void *args); + typedef jint (JNICALL *GetCreatedJavaVMs_t)(JavaVM **vmBuf, jsize bufLen, jsize *nVMs); + + typedef struct { + CreateJavaVM_t CreateJavaVM; ++ SetCParam_t SetCParam; + GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs; + GetCreatedJavaVMs_t GetCreatedJavaVMs; ++ char** raw_argv; + } InvocationFunctions; + + JNIEXPORT int JNICALL +diff --git a/src/java.base/unix/native/libjli/java_md.c b/src/java.base/unix/native/libjli/java_md.c +index 71c162b18..907087a22 100644 +--- a/src/java.base/unix/native/libjli/java_md.c ++++ b/src/java.base/unix/native/libjli/java_md.c +@@ -551,6 +551,12 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) + return JNI_FALSE; + } + ++ ifn->SetCParam = (SetCParam_t) ++ dlsym(libjvm, "JNI_SetCParam"); ++ if (ifn->SetCParam == NULL) { ++ JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); ++ return JNI_FALSE; ++ } + ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) + dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); + if (ifn->GetDefaultJavaVMInitArgs == NULL) { +-- +2.23.0 +