8247589: Implementation of Alpine Linux/x64 Port

Co-authored-by: Mikael Vidstedt <mikael@openjdk.org>
Co-authored-by: Alexander Scherbatiy <alexsch@openjdk.org>
Co-authored-by: Axel Siebenborn <asiebenborn@openjdk.org>
Co-authored-by: Aleksei Voitylov <avoitylov@openjdk.org>
Reviewed-by: alanb, erikj, dholmes
This commit is contained in:
Aleksei Voitylov 2020-10-13 09:35:58 +00:00 committed by Alexander Scherbatiy
parent 9d230ea87d
commit 63009f90ec
30 changed files with 386 additions and 55 deletions

View File

@ -53,6 +53,7 @@ define create-info-file
$(call info-file-item, "JAVA_VERSION_DATE", "$(VERSION_DATE)")
$(call info-file-item, "OS_NAME", "$(RELEASE_FILE_OS_NAME)")
$(call info-file-item, "OS_ARCH", "$(RELEASE_FILE_OS_ARCH)")
$(call info-file-item, "LIBC", "$(RELEASE_FILE_LIBC)")
endef
# Param 1 - The file containing the MODULES list

View File

@ -30,6 +30,17 @@
DIR=`dirname $0`
OUT=`. $DIR/autoconf-config.guess`
# Detect C library.
# Use '-gnu' suffix on systems that use glibc.
# Use '-musl' suffix on systems that use the musl libc.
echo $OUT | grep -- -linux- > /dev/null 2> /dev/null
if test $? = 0; then
libc_vendor=`ldd --version 2>&1 | sed -n '1s/.*\(musl\).*/\1/p'`
if [ x"${libc_vendor}" = x"musl" ]; then
OUT=`echo $OUT | sed 's/-gnu/-musl/'`
fi
fi
# Test and fix cygwin on x86_64
echo $OUT | grep 86-pc-cygwin > /dev/null 2> /dev/null
if test $? != 0; then

View File

@ -29,6 +29,11 @@
DIR=`dirname $0`
if echo $* | grep linux-musl >/dev/null ; then
echo $*
exit
fi
# Allow wsl
if echo $* | grep x86_64-pc-wsl >/dev/null ; then
echo $*

View File

@ -54,11 +54,13 @@ IMAGES_OUTPUTDIR := $(patsubst $(OUTPUTDIR)%,$(BUILDJDK_OUTPUTDIR)%,$(IMAGES_OUT
OPENJDK_BUILD_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@
OPENJDK_BUILD_CPU_LEGACY_LIB := @OPENJDK_BUILD_CPU_LEGACY_LIB@
OPENJDK_BUILD_LIBC := @OPENJDK_BUILD_LIBC@
OPENJDK_TARGET_CPU := @OPENJDK_BUILD_CPU@
OPENJDK_TARGET_CPU_ARCH := @OPENJDK_BUILD_CPU_ARCH@
OPENJDK_TARGET_CPU_BITS := @OPENJDK_BUILD_CPU_BITS@
OPENJDK_TARGET_CPU_ENDIAN := @OPENJDK_BUILD_CPU_ENDIAN@
OPENJDK_TARGET_CPU_LEGACY := @OPENJDK_BUILD_CPU_LEGACY@
OPENJDK_TARGET_LIBC := @OPENJDK_BUILD_LIBC@
OPENJDK_TARGET_OS_INCLUDE_SUBDIR := @OPENJDK_BUILD_OS_INCLUDE_SUBDIR@
HOTSPOT_TARGET_OS := @HOTSPOT_BUILD_OS@
@ -66,6 +68,7 @@ HOTSPOT_TARGET_OS_TYPE := @HOTSPOT_BUILD_OS_TYPE@
HOTSPOT_TARGET_CPU := @HOTSPOT_BUILD_CPU@
HOTSPOT_TARGET_CPU_ARCH := @HOTSPOT_BUILD_CPU_ARCH@
HOTSPOT_TARGET_CPU_DEFINE := @HOTSPOT_BUILD_CPU_DEFINE@
HOTSPOT_TARGET_LIBC := @HOTSPOT_BUILD_LIBC@
CFLAGS_JDKLIB := @OPENJDK_BUILD_CFLAGS_JDKLIB@
CXXFLAGS_JDKLIB := @OPENJDK_BUILD_CXXFLAGS_JDKLIB@

View File

@ -564,6 +564,11 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER],
fi
fi
OS_CFLAGS="$OS_CFLAGS -DLIBC=$OPENJDK_TARGET_LIBC"
if test "x$OPENJDK_TARGET_LIBC" = xmusl; then
OS_CFLAGS="$OS_CFLAGS -DMUSL_LIBC"
fi
# Where does this really belong??
if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then
PICFLAG="-fPIC"

View File

@ -220,6 +220,24 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_OS],
esac
])
# Support macro for PLATFORM_EXTRACT_TARGET_AND_BUILD.
# Converts autoconf style OS name to OpenJDK style, into
# VAR_LIBC.
AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_LIBC],
[
case "$1" in
*linux*-musl)
VAR_LIBC=musl
;;
*linux*-gnu)
VAR_LIBC=gnu
;;
*)
VAR_LIBC=default
;;
esac
])
# Expects $host_os $host_cpu $build_os and $build_cpu
# and $with_target_bits to have been setup!
#
@ -237,9 +255,10 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
AC_SUBST(OPENJDK_TARGET_AUTOCONF_NAME)
AC_SUBST(OPENJDK_BUILD_AUTOCONF_NAME)
# Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU variables.
# Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU/LIBC variables.
PLATFORM_EXTRACT_VARS_FROM_OS($build_os)
PLATFORM_EXTRACT_VARS_FROM_CPU($build_cpu)
PLATFORM_EXTRACT_VARS_FROM_LIBC($build_os)
# ..and setup our own variables. (Do this explicitly to facilitate searching)
OPENJDK_BUILD_OS="$VAR_OS"
if test "x$VAR_OS_TYPE" != x; then
@ -256,6 +275,7 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
OPENJDK_BUILD_CPU_ARCH="$VAR_CPU_ARCH"
OPENJDK_BUILD_CPU_BITS="$VAR_CPU_BITS"
OPENJDK_BUILD_CPU_ENDIAN="$VAR_CPU_ENDIAN"
OPENJDK_BUILD_LIBC="$VAR_LIBC"
AC_SUBST(OPENJDK_BUILD_OS)
AC_SUBST(OPENJDK_BUILD_OS_TYPE)
AC_SUBST(OPENJDK_BUILD_OS_ENV)
@ -263,13 +283,20 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
AC_SUBST(OPENJDK_BUILD_CPU_ARCH)
AC_SUBST(OPENJDK_BUILD_CPU_BITS)
AC_SUBST(OPENJDK_BUILD_CPU_ENDIAN)
AC_SUBST(OPENJDK_BUILD_LIBC)
AC_MSG_CHECKING([openjdk-build os-cpu])
AC_MSG_RESULT([$OPENJDK_BUILD_OS-$OPENJDK_BUILD_CPU])
# Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU variables.
if test "x$OPENJDK_BUILD_OS" = "xlinux"; then
AC_MSG_CHECKING([openjdk-build C library])
AC_MSG_RESULT([$OPENJDK_BUILD_LIBC])
fi
# Convert the autoconf OS/CPU value to our own data, into the VAR_OS/CPU/LIBC variables.
PLATFORM_EXTRACT_VARS_FROM_OS($host_os)
PLATFORM_EXTRACT_VARS_FROM_CPU($host_cpu)
PLATFORM_EXTRACT_VARS_FROM_LIBC($host_os)
# ... and setup our own variables. (Do this explicitly to facilitate searching)
OPENJDK_TARGET_OS="$VAR_OS"
if test "x$VAR_OS_TYPE" != x; then
@ -287,6 +314,7 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
OPENJDK_TARGET_CPU_BITS="$VAR_CPU_BITS"
OPENJDK_TARGET_CPU_ENDIAN="$VAR_CPU_ENDIAN"
OPENJDK_TARGET_OS_UPPERCASE=`$ECHO $OPENJDK_TARGET_OS | $TR 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
OPENJDK_TARGET_LIBC="$VAR_LIBC"
AC_SUBST(OPENJDK_TARGET_OS)
AC_SUBST(OPENJDK_TARGET_OS_TYPE)
@ -296,9 +324,15 @@ AC_DEFUN([PLATFORM_EXTRACT_TARGET_AND_BUILD],
AC_SUBST(OPENJDK_TARGET_CPU_ARCH)
AC_SUBST(OPENJDK_TARGET_CPU_BITS)
AC_SUBST(OPENJDK_TARGET_CPU_ENDIAN)
AC_SUBST(OPENJDK_TARGET_LIBC)
AC_MSG_CHECKING([openjdk-target os-cpu])
AC_MSG_RESULT([$OPENJDK_TARGET_OS-$OPENJDK_TARGET_CPU])
if test "x$OPENJDK_TARGET_OS" = "xlinux"; then
AC_MSG_CHECKING([openjdk-target C library])
AC_MSG_RESULT([$OPENJDK_TARGET_LIBC])
fi
])
# Check if a reduced build (32-bit on 64-bit platforms) is requested, and modify behaviour
@ -420,7 +454,13 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER],
else
OPENJDK_$1_CPU_BUNDLE="$OPENJDK_$1_CPU"
fi
OPENJDK_$1_BUNDLE_PLATFORM="${OPENJDK_$1_OS_BUNDLE}-${OPENJDK_$1_CPU_BUNDLE}"
OPENJDK_$1_LIBC_BUNDLE=""
if test "x$OPENJDK_$1_LIBC" = "xmusl"; then
OPENJDK_$1_LIBC_BUNDLE="-$OPENJDK_$1_LIBC"
fi
OPENJDK_$1_BUNDLE_PLATFORM="${OPENJDK_$1_OS_BUNDLE}-${OPENJDK_$1_CPU_BUNDLE}${OPENJDK_$1_LIBC_BUNDLE}"
AC_SUBST(OPENJDK_$1_BUNDLE_PLATFORM)
if test "x$COMPILE_TYPE" = "xcross"; then
@ -493,6 +533,9 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER],
fi
AC_SUBST(HOTSPOT_$1_CPU_DEFINE)
HOTSPOT_$1_LIBC=$OPENJDK_$1_LIBC
AC_SUBST(HOTSPOT_$1_LIBC)
# For historical reasons, the OS include directories have odd names.
OPENJDK_$1_OS_INCLUDE_SUBDIR="$OPENJDK_TARGET_OS"
if test "x$OPENJDK_TARGET_OS" = "xwindows"; then
@ -518,9 +561,11 @@ AC_DEFUN([PLATFORM_SET_RELEASE_FILE_OS_VALUES],
RELEASE_FILE_OS_NAME="AIX"
fi
RELEASE_FILE_OS_ARCH=${OPENJDK_TARGET_CPU}
RELEASE_FILE_LIBC=${OPENJDK_TARGET_LIBC}
AC_SUBST(RELEASE_FILE_OS_NAME)
AC_SUBST(RELEASE_FILE_OS_ARCH)
AC_SUBST(RELEASE_FILE_LIBC)
])
AC_DEFUN([PLATFORM_SET_MODULE_TARGET_OS_VALUES],

View File

@ -80,6 +80,8 @@ OPENJDK_TARGET_CPU_ARCH:=@OPENJDK_TARGET_CPU_ARCH@
OPENJDK_TARGET_CPU_BITS:=@OPENJDK_TARGET_CPU_BITS@
OPENJDK_TARGET_CPU_ENDIAN:=@OPENJDK_TARGET_CPU_ENDIAN@
OPENJDK_TARGET_LIBC:=@OPENJDK_TARGET_LIBC@
COMPILE_TYPE:=@COMPILE_TYPE@
# Legacy support
@ -95,6 +97,8 @@ HOTSPOT_TARGET_CPU := @HOTSPOT_TARGET_CPU@
HOTSPOT_TARGET_CPU_ARCH := @HOTSPOT_TARGET_CPU_ARCH@
HOTSPOT_TARGET_CPU_DEFINE := @HOTSPOT_TARGET_CPU_DEFINE@
HOTSPOT_TARGET_LIBC := @HOTSPOT_TARGET_LIBC@
OPENJDK_TARGET_BUNDLE_PLATFORM:=@OPENJDK_TARGET_BUNDLE_PLATFORM@
JDK_ARCH_ABI_PROP_NAME := @JDK_ARCH_ABI_PROP_NAME@
@ -109,6 +113,8 @@ OPENJDK_BUILD_CPU_ARCH:=@OPENJDK_BUILD_CPU_ARCH@
OPENJDK_BUILD_CPU_BITS:=@OPENJDK_BUILD_CPU_BITS@
OPENJDK_BUILD_CPU_ENDIAN:=@OPENJDK_BUILD_CPU_ENDIAN@
OPENJDK_BUILD_LIBC:=@OPENJDK_BUILD_LIBC@
OPENJDK_BUILD_OS_INCLUDE_SUBDIR:=@OPENJDK_TARGET_OS_INCLUDE_SUBDIR@
# Target platform value in ModuleTarget class file attribute.
@ -117,6 +123,7 @@ OPENJDK_MODULE_TARGET_PLATFORM:=@OPENJDK_MODULE_TARGET_PLATFORM@
# OS_* properties in release file
RELEASE_FILE_OS_NAME:=@RELEASE_FILE_OS_NAME@
RELEASE_FILE_OS_ARCH:=@RELEASE_FILE_OS_ARCH@
RELEASE_FILE_LIBC:=@RELEASE_FILE_LIBC@
SOURCE_DATE := @SOURCE_DATE@
ENABLE_REPRODUCIBLE_BUILD := @ENABLE_REPRODUCIBLE_BUILD@

View File

@ -104,7 +104,6 @@
# include <string.h>
# include <syscall.h>
# include <sys/sysinfo.h>
# include <gnu/libc-version.h>
# include <sys/ipc.h>
# include <sys/shm.h>
# include <link.h>
@ -137,6 +136,17 @@
// for timer info max values which include all bits
#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
#ifdef MUSL_LIBC
// dlvsym is not a part of POSIX
// and musl libc doesn't implement it.
static void *dlvsym(void *handle,
const char *symbol,
const char *version) {
// load the latest version of symbol
return dlsym(handle, symbol);
}
#endif
enum CoredumpFilterBit {
FILE_BACKED_PVT_BIT = 1 << 2,
FILE_BACKED_SHARED_BIT = 1 << 3,
@ -156,7 +166,7 @@ int (*os::Linux::_pthread_setname_np)(pthread_t, const char*) = NULL;
pthread_t os::Linux::_main_thread;
int os::Linux::_page_size = -1;
bool os::Linux::_supports_fast_thread_cpu_time = false;
const char * os::Linux::_glibc_version = NULL;
const char * os::Linux::_libc_version = NULL;
const char * os::Linux::_libpthread_version = NULL;
size_t os::Linux::_default_large_page_size = 0;
@ -510,17 +520,24 @@ void os::Linux::libpthread_init() {
#error "glibc too old (< 2.3.2)"
#endif
#ifdef MUSL_LIBC
// confstr() from musl libc returns EINVAL for
// _CS_GNU_LIBC_VERSION and _CS_GNU_LIBPTHREAD_VERSION
os::Linux::set_libc_version("musl - unknown");
os::Linux::set_libpthread_version("musl - unknown");
#else
size_t n = confstr(_CS_GNU_LIBC_VERSION, NULL, 0);
assert(n > 0, "cannot retrieve glibc version");
char *str = (char *)malloc(n, mtInternal);
confstr(_CS_GNU_LIBC_VERSION, str, n);
os::Linux::set_glibc_version(str);
os::Linux::set_libc_version(str);
n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
assert(n > 0, "cannot retrieve pthread version");
str = (char *)malloc(n, mtInternal);
confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
os::Linux::set_libpthread_version(str);
#endif
}
/////////////////////////////////////////////////////////////////////////////
@ -2211,7 +2228,7 @@ void os::get_summary_os_info(char* buf, size_t buflen) {
void os::Linux::print_libversion_info(outputStream* st) {
// libc, pthread
st->print("libc: ");
st->print("%s ", os::Linux::glibc_version());
st->print("%s ", os::Linux::libc_version());
st->print("%s ", os::Linux::libpthread_version());
st->cr();
}
@ -3070,6 +3087,8 @@ bool os::Linux::libnuma_init() {
if (handle != NULL) {
set_numa_node_to_cpus(CAST_TO_FN_PTR(numa_node_to_cpus_func_t,
libnuma_dlsym(handle, "numa_node_to_cpus")));
set_numa_node_to_cpus_v2(CAST_TO_FN_PTR(numa_node_to_cpus_v2_func_t,
libnuma_v2_dlsym(handle, "numa_node_to_cpus")));
set_numa_max_node(CAST_TO_FN_PTR(numa_max_node_func_t,
libnuma_dlsym(handle, "numa_max_node")));
set_numa_num_configured_nodes(CAST_TO_FN_PTR(numa_num_configured_nodes_func_t,
@ -3208,6 +3227,26 @@ void os::Linux::rebuild_cpu_to_node_map() {
FREE_C_HEAP_ARRAY(unsigned long, cpu_map);
}
int os::Linux::numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) {
// use the latest version of numa_node_to_cpus if available
if (_numa_node_to_cpus_v2 != NULL) {
// libnuma bitmask struct
struct bitmask {
unsigned long size; /* number of bits in the map */
unsigned long *maskp;
};
struct bitmask mask;
mask.maskp = (unsigned long *)buffer;
mask.size = bufferlen * 8;
return _numa_node_to_cpus_v2(node, &mask);
} else if (_numa_node_to_cpus != NULL) {
return _numa_node_to_cpus(node, buffer, bufferlen);
}
return -1;
}
int os::Linux::get_node_by_cpu(int cpu_id) {
if (cpu_to_node() != NULL && cpu_id >= 0 && cpu_id < cpu_to_node()->length()) {
return cpu_to_node()->at(cpu_id);
@ -3219,6 +3258,7 @@ GrowableArray<int>* os::Linux::_cpu_to_node;
GrowableArray<int>* os::Linux::_nindex_to_node;
os::Linux::sched_getcpu_func_t os::Linux::_sched_getcpu;
os::Linux::numa_node_to_cpus_func_t os::Linux::_numa_node_to_cpus;
os::Linux::numa_node_to_cpus_v2_func_t os::Linux::_numa_node_to_cpus_v2;
os::Linux::numa_max_node_func_t os::Linux::_numa_max_node;
os::Linux::numa_num_configured_nodes_func_t os::Linux::_numa_num_configured_nodes;
os::Linux::numa_available_func_t os::Linux::_numa_available;
@ -4321,6 +4361,40 @@ jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) {
extern void report_error(char* file_name, int line_no, char* title,
char* format, ...);
// Some linux distributions (notably: Alpine Linux) include the
// grsecurity in the kernel. Of particular interest from a JVM perspective
// is PaX (https://pax.grsecurity.net/), which adds some security features
// related to page attributes. Specifically, the MPROTECT PaX functionality
// (https://pax.grsecurity.net/docs/mprotect.txt) prevents dynamic
// code generation by disallowing a (previously) writable page to be
// marked as executable. This is, of course, exactly what HotSpot does
// for both JIT compiled method, as well as for stubs, adapters, etc.
//
// Instead of crashing "lazily" when trying to make a page executable,
// this code probes for the presence of PaX and reports the failure
// eagerly.
static void check_pax(void) {
// Zero doesn't generate code dynamically, so no need to perform the PaX check
#ifndef ZERO
size_t size = os::Linux::page_size();
void* p = ::mmap(NULL, size, PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
if (p == MAP_FAILED) {
log_debug(os)("os_linux.cpp: check_pax: mmap failed (%s)" , os::strerror(errno));
vm_exit_out_of_memory(size, OOM_MMAP_ERROR, "failed to allocate memory for PaX check.");
}
int res = ::mprotect(p, size, PROT_WRITE|PROT_EXEC);
if (res == -1) {
log_debug(os)("os_linux.cpp: check_pax: mprotect failed (%s)" , os::strerror(errno));
vm_exit_during_initialization(
"Failed to mark memory page as executable - check if grsecurity/PaX is enabled");
}
::munmap(p, size);
#endif
}
// this is called _before_ most of the global arguments have been parsed
void os::init(void) {
char dummy; // used to get a guess on initial stack address
@ -4354,6 +4428,8 @@ void os::init(void) {
Linux::_pthread_setname_np =
(int(*)(pthread_t, const char*))dlsym(RTLD_DEFAULT, "pthread_setname_np");
check_pax();
os::Posix::init();
initial_time_count = javaTimeNanos();
@ -4493,7 +4569,7 @@ jint os::init_2(void) {
Linux::libpthread_init();
Linux::sched_getcpu_init();
log_info(os)("HotSpot is running with %s, %s",
Linux::glibc_version(), Linux::libpthread_version());
Linux::libc_version(), Linux::libpthread_version());
if (UseNUMA || UseNUMAInterleaving) {
Linux::numa_init();

View File

@ -42,7 +42,7 @@ class Linux {
static address _initial_thread_stack_bottom;
static uintptr_t _initial_thread_stack_size;
static const char *_glibc_version;
static const char *_libc_version;
static const char *_libpthread_version;
static bool _supports_fast_thread_cpu_time;
@ -69,7 +69,7 @@ class Linux {
static int commit_memory_impl(char* addr, size_t bytes,
size_t alignment_hint, bool exec);
static void set_glibc_version(const char *s) { _glibc_version = s; }
static void set_libc_version(const char *s) { _libc_version = s; }
static void set_libpthread_version(const char *s) { _libpthread_version = s; }
static void rebuild_cpu_to_node_map();
@ -142,7 +142,7 @@ class Linux {
static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
// GNU libc and libpthread version strings
static const char *glibc_version() { return _glibc_version; }
static const char *libc_version() { return _libc_version; }
static const char *libpthread_version() { return _libpthread_version; }
static void libpthread_init();
@ -183,6 +183,7 @@ class Linux {
typedef int (*sched_getcpu_func_t)(void);
typedef int (*numa_node_to_cpus_func_t)(int node, unsigned long *buffer, int bufferlen);
typedef int (*numa_node_to_cpus_v2_func_t)(int node, void *mask);
typedef int (*numa_max_node_func_t)(void);
typedef int (*numa_num_configured_nodes_func_t)(void);
typedef int (*numa_available_func_t)(void);
@ -199,6 +200,7 @@ class Linux {
static sched_getcpu_func_t _sched_getcpu;
static numa_node_to_cpus_func_t _numa_node_to_cpus;
static numa_node_to_cpus_v2_func_t _numa_node_to_cpus_v2;
static numa_max_node_func_t _numa_max_node;
static numa_num_configured_nodes_func_t _numa_num_configured_nodes;
static numa_available_func_t _numa_available;
@ -220,6 +222,7 @@ class Linux {
static void set_sched_getcpu(sched_getcpu_func_t func) { _sched_getcpu = func; }
static void set_numa_node_to_cpus(numa_node_to_cpus_func_t func) { _numa_node_to_cpus = func; }
static void set_numa_node_to_cpus_v2(numa_node_to_cpus_v2_func_t func) { _numa_node_to_cpus_v2 = func; }
static void set_numa_max_node(numa_max_node_func_t func) { _numa_max_node = func; }
static void set_numa_num_configured_nodes(numa_num_configured_nodes_func_t func) { _numa_num_configured_nodes = func; }
static void set_numa_available(numa_available_func_t func) { _numa_available = func; }
@ -249,9 +252,7 @@ class Linux {
public:
static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; }
static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) {
return _numa_node_to_cpus != NULL ? _numa_node_to_cpus(node, buffer, bufferlen) : -1;
}
static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen);
static int numa_max_node() { return _numa_max_node != NULL ? _numa_max_node() : -1; }
static int numa_num_configured_nodes() {
return _numa_num_configured_nodes != NULL ? _numa_num_configured_nodes() : -1;

View File

@ -75,7 +75,6 @@
# include <pwd.h>
# include <poll.h>
# include <ucontext.h>
# include <fpu_control.h>
#define REG_FP 29
#define REG_LR 30

View File

@ -2294,6 +2294,13 @@ WB_ENTRY(void, WB_WaitUnsafe(JNIEnv* env, jobject wb, jint time))
os::naked_short_sleep(time);
WB_END
WB_ENTRY(jstring, WB_GetLibcName(JNIEnv* env, jobject o))
ThreadToNativeFromVM ttn(thread);
jstring info_string = env->NewStringUTF(XSTR(LIBC));
CHECK_JNI_EXCEPTION_(env, NULL);
return info_string;
WB_END
#define CC (char*)
static JNINativeMethod methods[] = {
@ -2546,6 +2553,7 @@ static JNINativeMethod methods[] = {
{CC"getKlassMetadataSize", CC"(Ljava/lang/Class;)I",(void*)&WB_GetKlassMetadataSize},
{CC"isJVMTIIncluded", CC"()Z", (void*)&WB_IsJVMTIIncluded},
{CC"waitUnsafe", CC"(I)V", (void*)&WB_WaitUnsafe},
{CC"getLibcName", CC"()Ljava/lang/String;", (void*)&WB_GetLibcName},
};

View File

@ -257,12 +257,18 @@ const char* Abstract_VM_Version::internal_vm_info_string() {
#define FLOAT_ARCH_STR XSTR(FLOAT_ARCH)
#endif
#ifdef MUSL_LIBC
#define LIBC_STR "-" XSTR(LIBC)
#else
#define LIBC_STR ""
#endif
#ifndef HOTSPOT_BUILD_TIME
#define HOTSPOT_BUILD_TIME __DATE__ " " __TIME__
#endif
#define INTERNAL_VERSION_SUFFIX VM_RELEASE ")" \
" for " OS "-" CPU FLOAT_ARCH_STR \
" for " OS "-" CPU FLOAT_ARCH_STR LIBC_STR \
" JRE (" VERSION_STRING "), built on " HOTSPOT_BUILD_TIME \
" by " XSTR(HOTSPOT_BUILD_USER) " with " HOTSPOT_BUILD_COMPILER

View File

@ -230,6 +230,14 @@ RequiresSetenv(const char *jvmpath) {
char *dmllp = NULL;
char *p; /* a utility pointer */
#ifdef MUSL_LIBC
/*
* The musl library loader requires LD_LIBRARY_PATH to be set in order
* to correctly resolve the dependency libjava.so has on libjvm.so.
*/
return JNI_TRUE;
#endif
#ifdef AIX
/* We always have to set the LIBPATH on AIX because ld doesn't support $ORIGIN. */
return JNI_TRUE;

View File

@ -279,8 +279,17 @@ static attach_state_t ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len
return ATTACH_THREAD_DEAD;
}
}
// strerror_r() API function is not compatible in different implementations:
// GNU-specific: char *strerror_r(int errnum, char *buf, size_t buflen);
// XSI-compliant: int strerror_r(int errnum, char *buf, size_t buflen);
char buf[200];
#if defined(__GLIBC__) && defined(_GNU_SOURCE)
char* msg = strerror_r(errno, buf, sizeof(buf));
#else
int rc = strerror_r(errno, buf, sizeof(buf));
char* msg = (rc == 0) ? (char*)buf : "Unknown";
#endif
snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg);
print_error("%s\n", err_buf);
return ATTACH_FAIL;

View File

@ -32,6 +32,12 @@
#include <stdlib.h>
#include <stdarg.h>
#ifdef LINUX
// Note. On Alpine Linux pthread.h includes calloc/malloc functions declaration.
// We need to include pthread.h before the following stdlib names poisoning.
#include <pthread.h>
#endif
#ifdef DEBUG
/* Just to make sure these interfaces are not used here. */
#undef free

View File

@ -73,6 +73,7 @@ requires.properties= \
vm.graal.enabled \
vm.compiler1.enabled \
vm.compiler2.enabled \
vm.musl \
docker.support \
test.vm.gc.nvdimm

View File

@ -30,6 +30,7 @@ import static java.util.stream.Collectors.toList;
import static jdk.test.lib.process.ProcessTools.createJavaProcessBuilder;
import static jdk.test.lib.Platform.isWindows;
import jdk.test.lib.Utils;
import jdk.test.lib.Platform;
import jtreg.SkippedException;
import java.io.BufferedReader;
@ -193,7 +194,14 @@ public class TestInheritFD {
}
static boolean findOpenLogFile(Collection<String> fileNames) {
String pid = Long.toString(ProcessHandle.current().pid());
String[] command = lsofCommand().orElseThrow(() ->
new RuntimeException("lsof like command not found"));
String lsof = command[0];
boolean isBusybox = Platform.isBusybox(lsof);
return fileNames.stream()
// lsof from busybox does not support "-p" option
.filter(fileName -> !isBusybox || fileName.contains(pid))
.filter(fileName -> fileName.contains(LOG_SUFFIX))
.findAny()
.isPresent();

View File

@ -33,6 +33,7 @@
#include <assert.h>
#include <jni.h>
#include <jvm.h>
#include <alloca.h>
#include <signal.h>
#include <string.h>
@ -91,6 +92,21 @@ void set_signal_handler() {
}
}
size_t get_java_stacksize () {
pthread_attr_t attr;
JDK1_1InitArgs jdk_args;
memset(&jdk_args, 0, (sizeof jdk_args));
jdk_args.version = JNI_VERSION_1_1;
JNI_GetDefaultJavaVMInitArgs(&jdk_args);
if (jdk_args.javaStackSize <= 0) {
fprintf(stderr, "Test ERROR. Can't get a valid value for the default stacksize.\n");
exit(7);
}
return jdk_args.javaStackSize;
}
void *run_java_overflow (void *p) {
JNIEnv *env;
jclass class_id;
@ -258,14 +274,20 @@ int main (int argc, const char** argv) {
exit(7);
}
size_t stack_size = get_java_stacksize();
pthread_t thr;
pthread_attr_t thread_attr;
pthread_attr_init(&thread_attr);
pthread_attr_setstacksize(&thread_attr, stack_size);
if (argc > 1 && strcmp(argv[1], "test_java_overflow") == 0) {
printf("\nTesting JAVA_OVERFLOW\n");
printf("Testing stack guard page behaviour for other thread\n");
pthread_create (&thr, NULL, run_java_overflow, NULL);
pthread_join (thr, NULL);
pthread_create(&thr, &thread_attr, run_java_overflow, NULL);
pthread_join(thr, NULL);
printf("Testing stack guard page behaviour for initial thread\n");
run_java_overflow(NULL);
@ -277,8 +299,8 @@ int main (int argc, const char** argv) {
printf("\nTesting NATIVE_OVERFLOW\n");
printf("Testing stack guard page behaviour for other thread\n");
pthread_create (&thr, NULL, run_native_overflow, NULL);
pthread_join (thr, NULL);
pthread_create(&thr, &thread_attr, run_native_overflow, NULL);
pthread_join(thr, NULL);
printf("Testing stack guard page behaviour for initial thread\n");
run_native_overflow(NULL);

View File

@ -26,7 +26,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __GLIBC__
#include <gnu/libc-version.h>
#endif
// Declare the thread local variable(s) in the main executable. This can be
// used to demonstrate the issues associated with the on-stack static TLS blocks
@ -54,6 +57,7 @@ JNIEnv* create_vm(JavaVM **jvm, char* argTLS) {
return env;
}
#ifdef __GLIBC__
// glibc 2.15 introduced __pthread_get_minstack
int glibc_has_pthread_get_minstack() {
const char* glibc_vers = gnu_get_libc_version();
@ -66,6 +70,11 @@ int glibc_has_pthread_get_minstack() {
printf("This version does not provide __pthread_get_minstack\n");
return 0;
}
#else
int glibc_has_pthread_get_minstack() {
return 0;
}
#endif
int run(jboolean addTLS) {
JavaVM *jvm;

View File

@ -26,6 +26,9 @@ import java.lang.management.*;
* @test
* @bug 8205878 8206954
* @requires os.family != "windows"
* @comment Calling pthread_getcpuclockid() with invalid pid leads to undefined
* behavior in musl libc (see 8240187).
* @requires !vm.musl
* @summary Basic test of Thread and ThreadMXBean queries on a natively
* attached thread that has failed to detach before terminating.
* @comment The native code only supports POSIX so no windows testing

View File

@ -52,6 +52,7 @@ requires.properties= \
vm.compiler1.enabled \
vm.compiler2.enabled \
vm.cds \
vm.musl \
vm.debug \
vm.hasSA \
vm.hasJFR \

View File

@ -25,6 +25,9 @@
* @test
* @bug 8164512 8191360
* @requires vm.compMode != "Xcomp"
* @comment Under musl, dlclose is a no-op. The static variable 'count' in libnative.c
* keeps its value across a GC and the check in Test.java fails.
* @requires !vm.musl
* @summary verify if the native library is unloaded when the class loader is GC'ed
* @build p.Test
* @run main/othervm/native -Xcheck:jni NativeLibraryTest

View File

@ -31,6 +31,7 @@
* @key intermittent
* @summary Basic tests for Process and Environment Variable code
* @modules java.base/java.lang:open
* @library /test/lib
* @run main/othervm/timeout=300 Basic
* @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=fork Basic
* @author Martin Buchholz
@ -40,6 +41,7 @@
* @test
* @modules java.base/java.lang:open
* @requires (os.family == "linux")
* @library /test/lib
* @run main/othervm/timeout=300 -Djdk.lang.Process.launchMechanism=posix_spawn Basic
*/
@ -63,6 +65,8 @@ import static java.lang.System.out;
import static java.lang.Boolean.TRUE;
import static java.util.AbstractMap.SimpleImmutableEntry;
import jdk.test.lib.Platform;
public class Basic {
/* used for Windows only */
@ -400,8 +404,8 @@ public class Basic {
if (failed != 0) throw new Error("null PATH");
} else if (action.equals("PATH search algorithm")) {
equal(System.getenv("PATH"), "dir1:dir2:");
check(new File("/bin/true").exists());
check(new File("/bin/false").exists());
check(new File(TrueExe.path()).exists());
check(new File(FalseExe.path()).exists());
String[] cmd = {"prog"};
ProcessBuilder pb1 = new ProcessBuilder(cmd);
ProcessBuilder pb2 = new ProcessBuilder(cmd);
@ -442,13 +446,13 @@ public class Basic {
checkPermissionDenied(pb);
// continue searching if EACCES
copy("/bin/true", "dir2/prog");
copy(TrueExe.path(), "dir2/prog");
equal(run(pb).exitValue(), True.exitValue());
new File("dir1/prog").delete();
new File("dir2/prog").delete();
new File("dir2/prog").mkdirs();
copy("/bin/true", "dir1/prog");
copy(TrueExe.path(), "dir1/prog");
equal(run(pb).exitValue(), True.exitValue());
// Check empty PATH component means current directory.
@ -464,10 +468,10 @@ public class Basic {
pb.command(command);
File prog = new File("./prog");
// "Normal" binaries
copy("/bin/true", "./prog");
copy(TrueExe.path(), "./prog");
equal(run(pb).exitValue(),
True.exitValue());
copy("/bin/false", "./prog");
copy(FalseExe.path(), "./prog");
equal(run(pb).exitValue(),
False.exitValue());
prog.delete();
@ -522,12 +526,12 @@ public class Basic {
new File("dir2/prog").delete();
new File("prog").delete();
new File("dir3").mkdirs();
copy("/bin/true", "dir1/prog");
copy("/bin/false", "dir3/prog");
copy(TrueExe.path(), "dir1/prog");
copy(FalseExe.path(), "dir3/prog");
pb.environment().put("PATH","dir3");
equal(run(pb).exitValue(), True.exitValue());
copy("/bin/true", "dir3/prog");
copy("/bin/false", "dir1/prog");
copy(TrueExe.path(), "dir3/prog");
copy(FalseExe.path(), "dir1/prog");
equal(run(pb).exitValue(), False.exitValue());
} finally {
@ -662,6 +666,43 @@ public class Basic {
}
}
// On Alpine Linux, /bin/true and /bin/false are just links to /bin/busybox.
// Some tests copy /bin/true and /bin/false to files with a different filename.
// However, copying the busbox executable into a file with a different name
// won't result in the expected return codes. As workaround, we create
// executable files that can be copied and produce the expected return
// values.
private static class TrueExe {
public static String path() { return path; }
private static final String path = path0();
private static String path0(){
if (!Platform.isBusybox("/bin/true")) {
return "/bin/true";
} else {
File trueExe = new File("true");
setFileContents(trueExe, "#!/bin/true\n");
trueExe.setExecutable(true);
return trueExe.getAbsolutePath();
}
}
}
private static class FalseExe {
public static String path() { return path; }
private static final String path = path0();
private static String path0(){
if (!Platform.isBusybox("/bin/false")) {
return "/bin/false";
} else {
File falseExe = new File("false");
setFileContents(falseExe, "#!/bin/false\n");
falseExe.setExecutable(true);
return falseExe.getAbsolutePath();
}
}
}
static class EnglishUnix {
private static final Boolean is =
(! Windows.is() && isEnglish("LANG") && isEnglish("LC_ALL"));
@ -1965,7 +2006,7 @@ public class Basic {
//----------------------------------------------------------------
try {
new File("suBdiR").mkdirs();
copy("/bin/true", "suBdiR/unliKely");
copy(TrueExe.path(), "suBdiR/unliKely");
final ProcessBuilder pb =
new ProcessBuilder(new String[]{"unliKely"});
pb.environment().put("PATH", "suBdiR");

View File

@ -24,6 +24,7 @@
/*
* @test
* @bug 8072611
* @requires (os.family == "windows")
* @summary ProcessBuilder Redirect to file appending on Windows should work with long file names
* @author Thomas Stuefe
*/
@ -38,11 +39,6 @@ public class RedirectWithLongFilename {
public static void main(String[] args) throws Exception {
// windows only
if (!Basic.Windows.is()) {
return;
}
// Redirect ProcessBuilder output to a file whose pathlen is > 255.
Path tmpDir = Paths.get(System.getProperty("java.io.tmpdir"));
File dir2 = null;

View File

@ -298,7 +298,14 @@ public class InfoTest {
}
if (info.command().isPresent()) {
String command = info.command().get();
String expected = Platform.isWindows() ? "sleep.exe" : "sleep";
String expected = "sleep";
if (Platform.isWindows()) {
expected = "sleep.exe";
} else if (Platform.isBusybox("/bin/sleep")) {
// With busybox sleep is just a sym link to busybox.
// The busbox executable is seen as ProcessHandle.Info command.
expected = "busybox";
}
Assert.assertTrue(command.endsWith(expected), "Command: expected: \'" +
expected + "\', actual: " + command);

View File

@ -25,11 +25,24 @@
* @test
* @bug 4780570 4731671 6354700 6367077 6670965 4882974
* @summary Checks for LD_LIBRARY_PATH and execution on *nixes
* @requires os.family != "windows" & !vm.musl & os.family != "aix"
* @library /test/lib
* @modules jdk.compiler
* jdk.zipfs
* @compile -XDignore.symbol.file ExecutionEnvironment.java
* @run main/othervm ExecutionEnvironment
* @run main/othervm -DexpandedLdLibraryPath=false ExecutionEnvironment
*/
/*
* @test
* @bug 4780570 4731671 6354700 6367077 6670965 4882974
* @summary Checks for LD_LIBRARY_PATH and execution on *nixes
* @requires os.family == "aix" | vm.musl
* @library /test/lib
* @modules jdk.compiler
* jdk.zipfs
* @compile -XDignore.symbol.file ExecutionEnvironment.java
* @run main/othervm -DexpandedLdLibraryPath=true ExecutionEnvironment
*/
/*
@ -83,6 +96,9 @@ public class ExecutionEnvironment extends TestHelper {
static final File testJarFile = new File("EcoFriendly.jar");
static final boolean IS_EXPANDED_LD_LIBRARY_PATH =
Boolean.getBoolean("expandedLdLibraryPath");
public ExecutionEnvironment() {
createTestJar();
}
@ -137,14 +153,16 @@ public class ExecutionEnvironment extends TestHelper {
for (String x : LD_PATH_STRINGS) {
if (!tr.contains(x)) {
if (TestHelper.isAIX && x.startsWith(LD_LIBRARY_PATH)) {
if (IS_EXPANDED_LD_LIBRARY_PATH && x.startsWith(LD_LIBRARY_PATH)) {
// AIX does not support the '-rpath' linker options so the
// launchers have to prepend the jdk library path to 'LIBPATH'.
String aixLibPath = LD_LIBRARY_PATH + "=" +
// The musl library loader requires LD_LIBRARY_PATH to be set in
// order to correctly resolve the dependency libjava.so has on libjvm.so.
String libPath = LD_LIBRARY_PATH + "=" +
System.getenv(LD_LIBRARY_PATH) +
System.getProperty("path.separator") + LD_LIBRARY_PATH_VALUE;
if (!tr.matches(aixLibPath)) {
flagError(tr, "FAIL: did not get <" + aixLibPath + ">");
if (!tr.matches(libPath)) {
flagError(tr, "FAIL: did not get <" + libPath + ">");
}
}
else {
@ -260,10 +278,6 @@ public class ExecutionEnvironment extends TestHelper {
}
}
public static void main(String... args) throws Exception {
if (isWindows) {
System.err.println("Warning: test not applicable to windows");
return;
}
ExecutionEnvironment ee = new ExecutionEnvironment();
ee.run(args);
}

View File

@ -26,9 +26,21 @@
* @bug 7029048 8217340 8217216
* @summary Ensure that the launcher defends against user settings of the
* LD_LIBRARY_PATH environment variable on Unixes
* @requires os.family != "windows" & os.family != "mac" & !vm.musl & os.family != "aix"
* @library /test/lib
* @compile -XDignore.symbol.file ExecutionEnvironment.java Test7029048.java
* @run main Test7029048
* @run main/othervm -DexpandedLdLibraryPath=false Test7029048
*/
/**
* @test
* @bug 7029048 8217340 8217216
* @summary Ensure that the launcher defends against user settings of the
* LD_LIBRARY_PATH environment variable on Unixes
* @requires os.family == "aix" | vm.musl
* @library /test/lib
* @compile -XDignore.symbol.file ExecutionEnvironment.java Test7029048.java
* @run main/othervm -DexpandedLdLibraryPath=true Test7029048
*/
import java.io.File;
@ -59,6 +71,9 @@ public class Test7029048 extends TestHelper {
private static final File dstClientDir = new File(dstLibDir, "client");
private static final File dstClientLibjvm = new File(dstClientDir, LIBJVM);
static final boolean IS_EXPANDED_LD_LIBRARY_PATH =
Boolean.getBoolean("expandedLdLibraryPath");
static String getValue(String name, List<String> in) {
for (String x : in) {
String[] s = x.split("=");
@ -155,7 +170,7 @@ public class Test7029048 extends TestHelper {
}
desc = "LD_LIBRARY_PATH should not be set (no libjvm.so)";
if (TestHelper.isAIX) {
if (IS_EXPANDED_LD_LIBRARY_PATH) {
printSkipMessage(desc);
continue;
}
@ -165,7 +180,7 @@ public class Test7029048 extends TestHelper {
recursiveDelete(dstLibDir);
}
desc = "LD_LIBRARY_PATH should not be set (no directory)";
if (TestHelper.isAIX) {
if (IS_EXPANDED_LD_LIBRARY_PATH) {
printSkipMessage(desc);
continue;
}
@ -193,15 +208,11 @@ public class Test7029048 extends TestHelper {
}
private static void printSkipMessage(String description) {
System.out.printf("Skipping test case '%s' because the Aix launcher" +
" adds the paths in any case.%n", description);
System.out.printf("Skipping test case '%s' because the Aix and musl launchers" +
" add the paths in any case.%n", description);
}
public static void main(String... args) throws Exception {
if (TestHelper.isWindows || TestHelper.isMacOSX) {
System.out.println("Note: applicable on neither Windows nor MacOSX");
return;
}
if (!TestHelper.haveServerVM) {
System.out.println("Note: test relies on server vm, not found, exiting");
return;

View File

@ -115,6 +115,7 @@ public class VMProps implements Callable<Map<String, String>> {
map.put("vm.compiler1.enabled", this::isCompiler1Enabled);
map.put("vm.compiler2.enabled", this::isCompiler2Enabled);
map.put("docker.support", this::dockerSupport);
map.put("vm.musl", this::isMusl);
map.put("release.implementor", this::implementor);
map.put("test.vm.gc.nvdimm", this::isNvdimmTestEnabled);
vmGC(map); // vm.gc.X = true/false
@ -514,6 +515,15 @@ public class VMProps implements Callable<Map<String, String>> {
return (p.exitValue() == 0);
}
/**
* Checks musl libc.
*
* @return true if musl libc is used.
*/
protected String isMusl() {
return Boolean.toString(WB.getLibcName().contains("musl"));
}
private String implementor() {
try (InputStream in = new BufferedInputStream(new FileInputStream(
System.getProperty("java.home") + "/release"))) {

View File

@ -109,6 +109,18 @@ public class Platform {
return isOs("linux");
}
public static boolean isBusybox(String tool) {
try {
Path toolpath = Paths.get(tool);
return !isWindows()
&& Files.isSymbolicLink(toolpath)
&& Paths.get("/bin/busybox")
.equals(Files.readSymbolicLink(toolpath));
} catch (IOException ignore) {
return false;
}
}
public static boolean isOSX() {
return isOs("mac");
}

View File

@ -616,6 +616,9 @@ public class WhiteBox {
// ThreadSMR GC safety check for threadObj
public native void checkThreadObjOfTerminatingThread(Thread target);
// libc name
public native String getLibcName();
public native boolean isJVMTIIncluded();
public native void waitUnsafe(int time_ms);