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

@ -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();