mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
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:
parent
9d230ea87d
commit
63009f90ec
30 changed files with 386 additions and 55 deletions
|
@ -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();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue