From 411af6b22f7324ed90a8ab6b5617dc470b8bf33c Mon Sep 17 00:00:00 2001 From: Dominik Hassler Date: Sat, 16 Nov 2024 13:03:47 +0000 Subject: [PATCH 1/4] openjdk11: update to 11.0.25+9 --- build/openjdk11/build.sh | 2 +- ..._share_native_libsplashscreen_libpng_pngpriv.h | 15 --------------- build/openjdk11/patches/series | 1 - 3 files changed, 1 insertion(+), 17 deletions(-) delete mode 100644 build/openjdk11/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h diff --git a/build/openjdk11/build.sh b/build/openjdk11/build.sh index 30e43f1402..577a4a9363 100755 --- a/build/openjdk11/build.sh +++ b/build/openjdk11/build.sh @@ -17,7 +17,7 @@ . ../../lib/build.sh PROG=openjdk -VER=11.0.24+8 +VER=11.0.25+9 PKG=runtime/java/openjdk11 SUMMARY="openjdk ${VER%%.*}" DESC="Open-source implementation of the eleventh edition of the " diff --git a/build/openjdk11/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h b/build/openjdk11/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h deleted file mode 100644 index 6e0efc6426..0000000000 --- a/build/openjdk11/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h +++ /dev/null @@ -1,15 +0,0 @@ -$NetBSD$ - -Fix build on SunOS in C99 mode. - ---- src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h.orig 2019-01-08 12:44:59.000000000 +0000 -+++ src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h -@@ -63,7 +63,7 @@ - * Windows/Visual Studio) there is no effect; the OS specific tests below are - * still required (as of 2011-05-02.) - */ --#ifndef _POSIX_SOURCE -+#if (!defined(__sun) || (__STDC_VERSION__-0 < 199901L)) && !defined(_POSIX_SOURCE) - # define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ - #endif - diff --git a/build/openjdk11/patches/series b/build/openjdk11/patches/series index 7ac96944d4..6cac35dce8 100644 --- a/build/openjdk11/patches/series +++ b/build/openjdk11/patches/series @@ -23,7 +23,6 @@ patch-src_hotspot_os_solaris_os__solaris.cpp -p0 patch-src_hotspot_share_gc_g1_g1Analytics.cpp -p0 patch-src_hotspot_share_utilities_globalDefinitions__gcc.hpp -p0 patch-src_java.base_solaris_native_libnio_ch_DevPollArrayWrapper.c -p0 -patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h -p0 patch-src_jdk.crypto.ec_share_native_libsunec_ECC__JNI.cpp -p0 tribblix-agent-mt.patch -p0 tribblix-attachListener_solaris.patch -p0 From 9cbeb329b3b187e1a221232fdf343a45ac00b232 Mon Sep 17 00:00:00 2001 From: Dominik Hassler Date: Sat, 16 Nov 2024 13:15:01 +0000 Subject: [PATCH 2/4] openjdk17: update to 17.0.13+11 --- build/openjdk17/build.sh | 2 +- build/openjdk17/patches/illumos-port-20.patch | 13 +++ .../patches/java-solaris-sparc.patch | 94 +++++++------------ ...re_native_libsplashscreen_libpng_pngpriv.h | 15 --- build/openjdk17/patches/series | 2 +- 5 files changed, 49 insertions(+), 77 deletions(-) create mode 100644 build/openjdk17/patches/illumos-port-20.patch delete mode 100644 build/openjdk17/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h diff --git a/build/openjdk17/build.sh b/build/openjdk17/build.sh index 6922e5dc68..1c2590367a 100755 --- a/build/openjdk17/build.sh +++ b/build/openjdk17/build.sh @@ -17,7 +17,7 @@ . ../../lib/build.sh PROG=openjdk -VER=17.0.12+7 +VER=17.0.13+11 PKG=runtime/java/openjdk17 SUMMARY="openjdk ${VER%%.*}" DESC="Open-source implementation of the seventeenth edition of the " diff --git a/build/openjdk17/patches/illumos-port-20.patch b/build/openjdk17/patches/illumos-port-20.patch new file mode 100644 index 0000000000..96a01761a4 --- /dev/null +++ b/build/openjdk17/patches/illumos-port-20.patch @@ -0,0 +1,13 @@ +--- a/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c Thu Jun 8 15:06:27 2023 ++++ b/src/java.desktop/unix/native/libawt_xawt/awt/screencast_pipewire.c Mon Jun 12 09:15:47 2023 +@@ -37,6 +37,10 @@ + #include "gtk_interface.h" + #include "gtk3_interface.h" + ++#ifndef MAX ++#define MAX(a,b) ((a) > (b) ? (a) : (b)) ++#endif ++ + int DEBUG_SCREENCAST_ENABLED = FALSE; + + #define EXCEPTION_CHECK_DESCRIBE() if ((*env)->ExceptionCheck(env)) { \ diff --git a/build/openjdk17/patches/java-solaris-sparc.patch b/build/openjdk17/patches/java-solaris-sparc.patch index 4aa42c540a..a9272c26bf 100644 --- a/build/openjdk17/patches/java-solaris-sparc.patch +++ b/build/openjdk17/patches/java-solaris-sparc.patch @@ -184,7 +184,7 @@ +++ new/make/autoconf/flags-cflags.m4 2020-05-20 17:58:30.108347798 -0700 @@ -421,9 +421,6 @@ if test "x$OPENJDK_TARGET_OS" = xlinux; then - CFLAGS_OS_DEF_JVM="-DLINUX" + CFLAGS_OS_DEF_JVM="-DLINUX -D_FILE_OFFSET_BITS=64" CFLAGS_OS_DEF_JDK="-D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" - elif test "x$OPENJDK_TARGET_OS" = xsolaris; then - CFLAGS_OS_DEF_JVM="-DSOLARIS" @@ -793,7 +793,7 @@ ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true) LIBVERIFY_OPTIMIZATION := LOW endif -@@ -106,7 +102,6 @@ +@@ -107,7 +103,6 @@ LIBS := $(BUILD_LIBFDLIBM_TARGET), \ LIBS_unix := -ljvm, \ LIBS_linux := $(LIBDL), \ @@ -801,7 +801,7 @@ LIBS_aix := $(LIBDL) $(LIBM),\ LIBS_macosx := -framework CoreFoundation \ -framework Foundation \ -@@ -215,7 +210,6 @@ +@@ -216,7 +211,6 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := $(LIBZ_LIBS), \ LIBS_linux := $(LIBDL) -lpthread, \ @@ -859,7 +859,7 @@ LIBS_aix := $(LIBDL),\ LIBS_macosx := -lmlib_image \ -framework Cocoa \ -@@ -389,7 +388,6 @@ +@@ -392,7 +391,6 @@ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LIBS_unix := -lawt -ljvm -ljava, \ LIBS_linux := $(LIBM) $(LIBDL), \ @@ -867,7 +867,7 @@ )) $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT) -@@ -447,7 +445,7 @@ +@@ -450,7 +448,7 @@ -DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H \ -DHB_NO_PRAGMA_GCC_DIAGNOSTIC endif @@ -876,7 +876,7 @@ HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHB_NO_VISIBILITY endif -@@ -621,10 +619,7 @@ +@@ -627,10 +625,7 @@ ifeq ($(call isTargetOs, macosx), true) JAWT_LIBS := -lawt_lwawt else @@ -888,7 +888,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) JAWT_LIBS += -lawt_xawt else -@@ -651,7 +646,6 @@ +@@ -657,7 +652,6 @@ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \ LIBS_unix := $(JAWT_LIBS) $(JDKLIB_LIBS), \ @@ -1208,7 +1208,7 @@ #endif /* !_JAVASOFT_JVM_MD_H_ */ --- old/src/hotspot/os/posix/os_posix.cpp 2020-05-20 17:59:42.965746713 -0700 +++ new/src/hotspot/os/posix/os_posix.cpp 2020-05-20 17:59:42.629740261 -0700 -@@ -490,7 +490,7 @@ +@@ -491,7 +491,7 @@ st->print("%d", sysconf(_SC_CHILD_MAX)); print_rlimit(st, ", THREADS", RLIMIT_THREADS); @@ -1217,7 +1217,7 @@ print_rlimit(st, ", NPROC", RLIMIT_NPROC); #endif -@@ -508,12 +508,6 @@ +@@ -509,12 +509,6 @@ print_rlimit(st, ", MEMLOCK", RLIMIT_MEMLOCK, true); #endif @@ -1230,7 +1230,7 @@ // MacOS; The maximum size (in bytes) to which a process's resident set size may grow. #if defined(__APPLE__) print_rlimit(st, ", RSS", RLIMIT_RSS, true); -@@ -984,7 +978,7 @@ +@@ -985,7 +979,7 @@ // page size which again depends on the concrete system the VM is running // on. Space for libc guard pages is not included in this size. jint os::Posix::set_minimum_stack_sizes() { @@ -1239,7 +1239,7 @@ _java_thread_min_stack_allowed = _java_thread_min_stack_allowed + StackOverflow::stack_guard_zone_size() + -@@ -1305,8 +1299,7 @@ +@@ -1306,8 +1300,7 @@ if ((status = pthread_mutexattr_settype(_mutexAttr, PTHREAD_MUTEX_NORMAL)) != 0) { fatal("pthread_mutexattr_settype: %s", os::strerror(status)); } @@ -1249,7 +1249,7 @@ } static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t) = NULL; -@@ -1521,7 +1514,6 @@ +@@ -1522,7 +1515,6 @@ // Shared pthread_mutex/cond based PlatformEvent implementation. // Not currently usable by Solaris. @@ -1257,7 +1257,7 @@ // PlatformEvent // -@@ -1951,8 +1943,6 @@ +@@ -1952,8 +1944,6 @@ return OS_OK; } } @@ -1377,7 +1377,7 @@ --- old/src/hotspot/share/runtime/globals.hpp 2020-05-20 18:00:31.194672744 -0700 +++ new/src/hotspot/share/runtime/globals.hpp 2020-05-20 18:00:30.854666216 -0700 -@@ -693,10 +693,6 @@ +@@ -696,10 +696,6 @@ product_pd(bool, DontYieldALot, \ "Throw away obvious excess yield calls") \ \ @@ -1388,7 +1388,7 @@ product(bool, DisablePrimordialThreadGuardPages, false, EXPERIMENTAL, \ "Disable the use of stack guard pages if the JVM is loaded " \ "on the primordial process thread") \ -@@ -750,10 +746,6 @@ +@@ -753,10 +749,6 @@ "When true prevents OS-level spurious, or premature, wakeups " \ "from Object.wait (Ignored for Windows)") \ \ @@ -1399,7 +1399,7 @@ product(bool, ReduceSignalUsage, false, \ "Reduce the use of OS signals in Java and/or the VM") \ \ -@@ -1677,10 +1669,8 @@ +@@ -1680,10 +1672,8 @@ product(intx, ThreadPriorityPolicy, 0, \ "0 : Normal. "\ " VM chooses priorities that are appropriate for normal "\ @@ -1412,7 +1412,7 @@ " priorities. However, with ThreadPriorityPolicy=0, VM will "\ " not use the highest possible native priority, "\ " THREAD_PRIORITY_TIME_CRITICAL, as it may interfere with "\ -@@ -2029,8 +2019,7 @@ +@@ -2032,8 +2022,7 @@ "do not map the archive") \ range(0, 2) \ \ @@ -1439,7 +1439,7 @@ if (PrintFlagsFinal || PrintFlagsRanges) { --- old/src/hotspot/share/runtime/os.hpp 2020-05-20 18:00:34.390734111 -0700 +++ new/src/hotspot/share/runtime/os.hpp 2020-05-20 18:00:34.014726891 -0700 -@@ -493,7 +493,7 @@ +@@ -494,7 +494,7 @@ static void free_thread(OSThread* osthread); @@ -1448,7 +1448,7 @@ static intx current_thread_id(); static int current_process_id(); -@@ -842,10 +842,8 @@ +@@ -848,10 +848,8 @@ // JVMTI & JVM monitoring and management support // The thread_cpu_time() and current_thread_cpu_time() are only // supported if is_thread_cpu_time_supported() returns true. @@ -2121,7 +2121,7 @@ } static const char* -@@ -452,7 +445,7 @@ +@@ -456,7 +449,7 @@ #endif /* vfork(2) is deprecated on Darwin */ @@ -2130,7 +2130,7 @@ static pid_t vforkChild(ChildStuff *c) { volatile pid_t resultPid; -@@ -606,7 +599,7 @@ +@@ -612,7 +605,7 @@ startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { switch (c->mode) { /* vfork(2) is deprecated on Darwin*/ @@ -3992,7 +3992,7 @@ #ifdef __linux__ #include #include // makedev macros -@@ -389,8 +382,7 @@ +@@ -390,8 +383,7 @@ /* system calls that might not be available at run time */ @@ -4120,7 +4120,7 @@ */ --- old/src/java.desktop/share/classes/sun/font/FileFontStrike.java 2020-05-20 18:01:46.908126498 -0700 +++ new/src/java.desktop/share/classes/sun/font/FileFontStrike.java 2020-05-20 18:01:46.528119201 -0700 -@@ -222,24 +222,6 @@ +@@ -224,24 +224,6 @@ !((TrueTypeFont)fileFont).useEmbeddedBitmapsForSize(intPtSize)) { useNatives = true; } @@ -5409,32 +5409,6 @@ long dbgsysCurrentTimeMillis() { struct timeval t; ---- old/src/jdk.jdwp.agent/unix/native/libjdwp/exec_md.c 2020-05-20 18:03:33.146166346 -0700 -+++ new/src/jdk.jdwp.agent/unix/native/libjdwp/exec_md.c 2020-05-20 18:03:32.810159893 -0700 -@@ -30,14 +30,6 @@ - #include "sys.h" - #include "util.h" - --#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX) -- /* Linux, BSD, AIX */ -- #define FORK() fork() --#else -- /* Solaris (make sure we always get the POSIX-specified behavior) */ -- #define FORK() fork1() --#endif -- - static char *skipWhitespace(char *p) { - while ((*p != '\0') && isspace(*p)) { - p++; -@@ -100,7 +92,7 @@ - } - argv[i] = NULL; /* NULL terminate */ - -- if ((pid = FORK()) == 0) { -+ if ((pid = fork()) == 0) { - /* Child process */ - int i; - long max_fd; --- old/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java 2020-05-20 18:03:35.234206438 -0700 +++ new/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java 2020-05-20 18:03:34.898199985 -0700 @@ -34,7 +34,6 @@ @@ -5618,7 +5592,7 @@ -#endif - -/* Function types to support dynamic linking of socket API extension functions -- * for SCTP. This is so that there is no linkage depandancy during build or +- * for SCTP. This is so that there is no linkage dependency during build or - * runtime for libsctp.*/ -typedef int sctp_getladdrs_func(int sock, sctp_assoc_t id, void **addrs); -typedef int sctp_freeladdrs_func(void* addrs); @@ -7001,7 +6975,7 @@ - -// The attach mechanism on Solaris is implemented using the Doors IPC -// mechanism. The first tool to attempt to attach causes the attach --// listener thread to startup. This thread creats a door that is +-// listener thread to startup. This thread creates a door that is -// associated with a function that enqueues an operation to the attach -// listener. The door is attached to a file in the file system so that -// client (tools) can locate it. To enqueue an operation to the VM the @@ -7288,7 +7262,7 @@ - - // create a pair of connected sockets. Store the file descriptor - // for one end in the operation and enqueue the operation. The -- // file descriptor for the other end wil be returned to the client. +- // file descriptor for the other end will be returned to the client. - if (res == 0) { - int s[2]; - if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) { @@ -7389,7 +7363,7 @@ - if (dd >= 0) { - set_door_descriptor(dd); - set_door_path(door_path); -- log_trace(attach)("door file %s created succesfully", door_path); +- log_trace(attach)("door file %s created successfully", door_path); - } else { - // unable to create door, attach it to file, or rename file into place - ::unlink(initial_path); @@ -11653,7 +11627,7 @@ -// -// Assumptions: -// + We assume that all threads in the process belong to the same --// scheduling class. IE. an homogenous process. +-// scheduling class. IE. a homogeneous process. -// + Must be root or in IA group to change change "interactive" attribute. -// Priocntl() will fail silently. The only indication of failure is when -// we read-back the value and notice that it hasn't changed. @@ -12014,8 +11988,8 @@ -// -// ThreadPriorityPolicy=1 -// This mode causes the priority table to get filled with --// linear values. NormPriority get's mapped to 50% of the --// Maximum priority an so on. This will cause VM threads +-// linear values. NormPriority gets mapped to 50% of the +-// Maximum priority and so on. This will cause VM threads -// to get unfair treatment against other Solaris processes -// which do not explicitly alter their thread priorities. - @@ -12375,7 +12349,7 @@ - } - - // Calculate theoretical max. size of Threads to guard gainst -- // artifical out-of-memory situations, where all available address- +- // artificial out-of-memory situations, where all available address- - // space has been reserved by thread stacks. Default stack size is 1Mb. - size_t pre_thread_stack_size = (JavaThread::stack_size_at_create()) ? - JavaThread::stack_size_at_create() : (1*K*K); @@ -17115,7 +17089,7 @@ -class EventPortSelectorImpl - extends SelectorImpl -{ -- // maximum number of events to retrive in one call to port_getn +- // maximum number of events to retrieve in one call to port_getn - static final int MAX_EVENTS = Math.min(IOUtil.fdLimit()-1, 1024); - - // port file descriptor @@ -21364,7 +21338,7 @@ - J->bcp = bcp; - - /* On x86 with C2 JVM: native frame may have wrong regs[R_FP] -- * For example: JVM_SuspendThread frame poins to the top interpreted frame. +- * For example: JVM_SuspendThread frame points to the top interpreted frame. - * If we call is_method(J, methodPtr) before codecache_contains(J, pc) - * then we go over and omit both: nmethod and I2CAdapter frames. - * Note, that regs[R_PC] is always correct if frame defined correctly. @@ -21626,7 +21600,7 @@ -// generic error messages -#define JVM_ERR_OUT_OF_MEMORY "out of memory (native heap)" -#define JVM_ERR_INVALID_PARAM "invalid input parameter(s)" --#define JVM_ERR_NULL_PARAM "input paramater is NULL" +-#define JVM_ERR_NULL_PARAM "input parameter is NULL" - -// error messages for attach -#define JVM_ERR_CANT_OPEN_DOOR "cannot open door file" diff --git a/build/openjdk17/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h b/build/openjdk17/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h deleted file mode 100644 index 6e0efc6426..0000000000 --- a/build/openjdk17/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h +++ /dev/null @@ -1,15 +0,0 @@ -$NetBSD$ - -Fix build on SunOS in C99 mode. - ---- src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h.orig 2019-01-08 12:44:59.000000000 +0000 -+++ src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h -@@ -63,7 +63,7 @@ - * Windows/Visual Studio) there is no effect; the OS specific tests below are - * still required (as of 2011-05-02.) - */ --#ifndef _POSIX_SOURCE -+#if (!defined(__sun) || (__STDC_VERSION__-0 < 199901L)) && !defined(_POSIX_SOURCE) - # define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ - #endif - diff --git a/build/openjdk17/patches/series b/build/openjdk17/patches/series index 7cf9be4b35..401f2a9a5f 100644 --- a/build/openjdk17/patches/series +++ b/build/openjdk17/patches/series @@ -18,6 +18,7 @@ illumos-port-16.patch illumos-port-17.patch illumos-port-18.patch illumos-port-19.patch +illumos-port-20.patch illumos-signal-1.patch illumos-signal-2.patch illumos-signal-3.patch @@ -30,7 +31,6 @@ patch-src_hotspot_os__cpu_solaris__x86_atomic__solaris__x86.hpp -p0 patch-src_hotspot_os__cpu_solaris__x86_bytes__solaris__x86.inline.hpp -p0 patch-src_hotspot_os__cpu_solaris__x86_prefetch__solaris__x86.inline.hpp -p0 patch-src_hotspot_share_gc_g1_g1Analytics.cpp -p0 -patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h -p0 tribblix-demangle1.patch -p0 tribblix-demangle4.patch -p0 tribblix-flags-cflags.patch -p0 From 18647a8e8e4cc222c65910bad896bb49d4d54530 Mon Sep 17 00:00:00 2001 From: Dominik Hassler Date: Sat, 16 Nov 2024 13:45:38 +0000 Subject: [PATCH 3/4] openjdk21: update to 21.0.5+11 --- build/openjdk21/build.sh | 2 +- .../illumos-cpu_microcode_revision.patch | 25 - build/openjdk21/patches/illumos-port-15.patch | 23 - build/openjdk21/patches/illumos-port-9.patch | 93 - .../openjdk21/patches/illumos-safefetch.patch | 61 - .../patches/java-solaris-sparc.patch | 7708 +---------------- ...re_native_libsplashscreen_libpng_pngpriv.h | 15 - .../patches/restore_os_cpu_solaris_x86.patch | 1887 ++++ .../patches/restore_os_solaris.patch | 5846 +++++++++++++ build/openjdk21/patches/series | 8 +- .../patches/tribblix-demangle1.patch | 29 - 11 files changed, 7752 insertions(+), 7945 deletions(-) delete mode 100644 build/openjdk21/patches/illumos-cpu_microcode_revision.patch delete mode 100644 build/openjdk21/patches/illumos-port-15.patch delete mode 100644 build/openjdk21/patches/illumos-port-9.patch delete mode 100644 build/openjdk21/patches/illumos-safefetch.patch delete mode 100644 build/openjdk21/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h create mode 100644 build/openjdk21/patches/restore_os_cpu_solaris_x86.patch create mode 100644 build/openjdk21/patches/restore_os_solaris.patch delete mode 100644 build/openjdk21/patches/tribblix-demangle1.patch diff --git a/build/openjdk21/build.sh b/build/openjdk21/build.sh index a8098c8c22..520838e706 100755 --- a/build/openjdk21/build.sh +++ b/build/openjdk21/build.sh @@ -17,7 +17,7 @@ . ../../lib/build.sh PROG=openjdk -VER=21.0.4+7 +VER=21.0.5+11 PKG=runtime/java/openjdk21 SUMMARY="openjdk ${VER%%.*}" DESC="Open-source implementation of the twenty-first edition of the " diff --git a/build/openjdk21/patches/illumos-cpu_microcode_revision.patch b/build/openjdk21/patches/illumos-cpu_microcode_revision.patch deleted file mode 100644 index c5829f6930..0000000000 --- a/build/openjdk21/patches/illumos-cpu_microcode_revision.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp Tue Jul 28 18:40:12 2020 -+++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp Tue Jul 28 19:48:19 2020 -@@ -44,5 +44,7 @@ - static void setup_fpu(); - #endif // AMD64 -+ -+ static juint cpu_microcode_revision(); - - static jlong rdtsc(); - ---- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp Tue Jul 28 18:40:12 2020 -+++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp Tue Jul 28 19:50:48 2020 -@@ -294,6 +294,12 @@ - } - - -+juint os::cpu_microcode_revision() { -+ juint result = 0; -+ // to implement this, look at the source for ucodeadm -v -+ return result; -+} -+ - bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, - ucontext_t* uc, JavaThread* thread) { - diff --git a/build/openjdk21/patches/illumos-port-15.patch b/build/openjdk21/patches/illumos-port-15.patch deleted file mode 100644 index 4acb221f8a..0000000000 --- a/build/openjdk21/patches/illumos-port-15.patch +++ /dev/null @@ -1,23 +0,0 @@ - -This fixes the following frequently seen warning - - SIGSEGV happened inside stack but outside yellow and red zone. - -diff --git a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp -index c5a72c791..9d9ab5618 100644 ---- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp -+++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp -@@ -293,8 +293,11 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, - // Handle ALL stack overflow variations here - if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { - address addr = (address) info->si_addr; -- if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { -- return 1; // continue -+ if (thread->is_in_full_stack(addr)) { -+ // stack overflow -+ if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { -+ return true; // continue -+ } - } - } - diff --git a/build/openjdk21/patches/illumos-port-9.patch b/build/openjdk21/patches/illumos-port-9.patch deleted file mode 100644 index 361059e650..0000000000 --- a/build/openjdk21/patches/illumos-port-9.patch +++ /dev/null @@ -1,93 +0,0 @@ ---- a/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp Fri Oct 16 12:20:06 2020 -+++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp Fri Oct 16 14:58:59 2020 -@@ -219,42 +219,12 @@ - return frame(sp, fp, epc); - } - --bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { -- address pc = (address) os::Solaris::ucontext_get_pc(uc); -- if (Interpreter::contains(pc)) { -- // interpreter performs stack banging after the fixed frame header has -- // been generated while the compilers perform it before. To maintain -- // semantic consistency between interpreted and compiled frames, the -- // method returns the Java sender of the current frame. -- *fr = os::fetch_frame_from_context(uc); -- if (!fr->is_first_java_frame()) { -- // get_frame_at_stack_banging_point() is only called when we -- // have well defined stacks so java_sender() calls do not need -- // to assert safe_for_sender() first. -- *fr = fr->java_sender(); -- } -- } else { -- // more complex code with compiled code -- assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); -- CodeBlob* cb = CodeCache::find_blob(pc); -- if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { -- // Not sure where the pc points to, fallback to default -- // stack overflow handling -- return false; -- } else { -- // in compiled code, the stack banging is performed just after the return pc -- // has been pushed on the stack -- intptr_t* fp = os::Solaris::ucontext_get_fp(uc); -- intptr_t* sp = os::Solaris::ucontext_get_sp(uc); -- *fr = frame(sp + 1, fp, (address)*sp); -- if (!fr->is_java_frame()) { -- // See java_sender() comment above. -- *fr = fr->java_sender(); -- } -- } -- } -- assert(fr->is_java_frame(), "Safety check"); -- return true; -+frame os::fetch_compiled_frame_from_context(const void* ucVoid) { -+ const ucontext_t* uc = (const ucontext_t*)ucVoid; -+ frame fr = os::fetch_frame_from_context(uc); -+ // in compiled code, the stack banging is performed just after the return pc -+ // has been pushed on the stack -+ return frame(fr.sp() + 1, fr.fp(), (address)*(fr.sp())); - } - - frame os::get_sender_for_C_frame(frame* fr) { -@@ -323,39 +293,8 @@ - // Handle ALL stack overflow variations here - if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { - address addr = (address) info->si_addr; -- if (thread->in_stack_yellow_reserved_zone(addr)) { -- if (thread->thread_state() == _thread_in_Java) { -- if (thread->in_stack_reserved_zone(addr)) { -- frame fr; -- if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) { -- assert(fr.is_java_frame(), "Must be Java frame"); -- frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); -- if (activation.sp() != NULL) { -- thread->disable_stack_reserved_zone(); -- if (activation.is_interpreted_frame()) { -- thread->set_reserved_stack_activation((address)( -- activation.fp() + frame::interpreter_frame_initial_sp_offset)); -- } else { -- thread->set_reserved_stack_activation((address)activation.unextended_sp()); -- } -- return true; -- } -- } -- } -- // Throw a stack overflow exception. Guard pages will be reenabled -- // while unwinding the stack. -- thread->disable_stack_yellow_reserved_zone(); -- stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); -- } else { -- // Thread was in the vm or native code. Return and try to finish. -- thread->disable_stack_yellow_reserved_zone(); -- return true; -- } -- } else if (thread->in_stack_red_zone(addr)) { -- // Fatal red zone violation. Disable the guard pages and fall through -- // to handle_unexpected_exception way down below. -- thread->disable_stack_red_zone(); -- tty->print_raw_cr("An irrecoverable stack overflow has occurred."); -+ if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { -+ return 1; // continue - } - } - diff --git a/build/openjdk21/patches/illumos-safefetch.patch b/build/openjdk21/patches/illumos-safefetch.patch deleted file mode 100644 index da285258c9..0000000000 --- a/build/openjdk21/patches/illumos-safefetch.patch +++ /dev/null @@ -1,61 +0,0 @@ ---- /dev/null Fri Apr 22 12:35:21 2022 -+++ a/src/hotspot/os_cpu/solaris_x86/safefetch_solaris_x86_64.S Fri Apr 22 12:29:28 2022 -@@ -0,0 +1,58 @@ -+# -+# Copyright (c) 2022 SAP SE. All rights reserved. -+# Copyright (c) 2022, Oracle and/or its affiliates. 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. -+# -+ .globl SafeFetch32_impl -+ .globl SafeFetchN_impl -+ .globl _SafeFetch32_fault -+ .globl _SafeFetchN_fault -+ .globl _SafeFetch32_continuation -+ .globl _SafeFetchN_continuation -+ -+ .text -+ -+ -+ # Support for int SafeFetch32(int* address, int defaultval); -+ # -+ # %rdi : address -+ # %esi : defaultval -+ .type SafeFetch32_impl,@function -+SafeFetch32_impl: -+_SafeFetch32_fault: -+ movl (%rdi), %eax # load target value, may fault -+ ret -+_SafeFetch32_continuation: -+ movl %esi, %eax # return default -+ ret -+ -+ # Support for intptr_t SafeFetchN(intptr_t* address, intptr_t defaultval); -+ # -+ # %rdi : address -+ # %rsi : defaultval -+ .type SafeFetchN_impl,@function -+SafeFetchN_impl: -+_SafeFetchN_fault: -+ movq (%rdi), %rax # load target value, may fault -+ ret -+_SafeFetchN_continuation: -+ movq %rsi, %rax # return default -+ ret diff --git a/build/openjdk21/patches/java-solaris-sparc.patch b/build/openjdk21/patches/java-solaris-sparc.patch index bcffd937ba..1b0bc890f6 100644 --- a/build/openjdk21/patches/java-solaris-sparc.patch +++ b/build/openjdk21/patches/java-solaris-sparc.patch @@ -728,7 +728,7 @@ LIBS_aix := $(LIBDL),\ LIBS_macosx := -lmlib_image \ -framework Cocoa \ -@@ -396,7 +395,6 @@ +@@ -403,7 +402,6 @@ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LIBS_unix := -lawt -ljvm -ljava, \ LIBS_linux := $(LIBM) $(LIBDL), \ @@ -736,7 +736,7 @@ )) $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT) -@@ -454,7 +452,7 @@ +@@ -461,7 +459,7 @@ -DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H \ -DHB_NO_PRAGMA_GCC_DIAGNOSTIC endif @@ -745,7 +745,7 @@ HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHB_NO_VISIBILITY endif -@@ -625,10 +623,7 @@ +@@ -635,10 +633,7 @@ ifeq ($(call isTargetOs, macosx), true) JAWT_LIBS := -lawt_lwawt else @@ -757,7 +757,7 @@ ifeq ($(ENABLE_HEADLESS_ONLY), false) JAWT_LIBS += -lawt_xawt else -@@ -655,7 +650,6 @@ +@@ -665,7 +660,6 @@ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \ LIBS_unix := $(JAWT_LIBS) $(JDKLIB_LIBS), \ @@ -822,7 +822,7 @@ --- old/make/modules/jdk.hotspot.agent/Lib.gmk 2020-05-20 17:59:21.653337499 -0700 +++ new/make/modules/jdk.hotspot.agent/Lib.gmk 2020-05-20 17:59:21.257329896 -0700 -@@ -67,11 +67,10 @@ +@@ -68,11 +68,10 @@ CFLAGS := $(CFLAGS_JDKLIB) $(SA_CFLAGS), \ CXXFLAGS := $(CXXFLAGS_JDKLIB) $(SA_CFLAGS) $(SA_CXXFLAGS), \ EXTRA_SRC := $(LIBSA_EXTRA_SRC), \ @@ -864,7 +864,7 @@ ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true) LIBMANAGEMENT_EXT_OPTIMIZATION := LOW endif -@@ -48,7 +48,6 @@ +@@ -49,7 +49,6 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(JDKLIB_LIBS), \ @@ -1170,7 +1170,7 @@ --- old/src/hotspot/share/runtime/globals.hpp 2020-05-20 18:00:31.194672744 -0700 +++ new/src/hotspot/share/runtime/globals.hpp 2020-05-20 18:00:30.854666216 -0700 -@@ -1596,10 +1596,8 @@ +@@ -1599,10 +1599,8 @@ product(int, ThreadPriorityPolicy, 0, \ "0 : Normal. "\ " VM chooses priorities that are appropriate for normal "\ @@ -1183,7 +1183,7 @@ " priorities. However, with ThreadPriorityPolicy=0, VM will "\ " not use the highest possible native priority, "\ " THREAD_PRIORITY_TIME_CRITICAL, as it may interfere with "\ -@@ -1881,8 +1879,7 @@ +@@ -1884,8 +1882,7 @@ product(bool, WhiteBoxAPI, false, DIAGNOSTIC, \ "Enable internal testing APIs") \ \ @@ -1409,7 +1409,7 @@ #include --- old/src/hotspot/share/utilities/vmError.cpp 2020-05-20 18:00:48.214999546 -0700 +++ new/src/hotspot/share/utilities/vmError.cpp 2020-05-20 18:00:47.822992019 -0700 -@@ -1890,8 +1890,6 @@ +@@ -1891,8 +1891,6 @@ out.print_raw ("# Executing "); #if defined(LINUX) || defined(_ALLBSD_SOURCE) out.print_raw ("/bin/sh -c "); @@ -1418,7 +1418,7 @@ #elif defined(_WINDOWS) out.print_raw ("cmd /C "); #endif -@@ -1956,8 +1954,6 @@ +@@ -1957,8 +1955,6 @@ tty->print("# Executing "); #if defined(LINUX) tty->print ("/bin/sh -c "); @@ -1819,7 +1819,7 @@ static pid_t vforkChild(ChildStuff *c) { volatile pid_t resultPid; -@@ -609,7 +602,7 @@ +@@ -618,7 +611,7 @@ startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { switch (c->mode) { /* vfork(2) is deprecated on Darwin*/ @@ -3286,7 +3286,7 @@ #ifdef __linux__ #include #include // makedev macros -@@ -381,8 +374,7 @@ +@@ -382,8 +375,7 @@ /* system calls that might not be available at run time */ @@ -4343,7 +4343,7 @@ -#endif - -/* Function types to support dynamic linking of socket API extension functions -- * for SCTP. This is so that there is no linkage depandancy during build or +- * for SCTP. This is so that there is no linkage dependency during build or - * runtime for libsctp.*/ -typedef int sctp_getladdrs_func(int sock, sctp_assoc_t id, void **addrs); -typedef int sctp_freeladdrs_func(void* addrs); @@ -5612,7682 +5612,6 @@ -endif - -################################################################################ ---- old/src/hotspot/os/solaris/attachListener_solaris.cpp 2020-05-20 18:09:27.484969868 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,749 +0,0 @@ --/* -- * Copyright (c) 2005, 2019, Oracle and/or its affiliates. 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 "logging/log.hpp" --#include "runtime/interfaceSupport.inline.hpp" --#include "runtime/os.inline.hpp" --#include "services/attachListener.hpp" --#include "services/dtraceAttacher.hpp" --#include "utilities/vmError.hpp" -- --#include --#include --#include --#include --#include --#include --#include -- --// stropts.h uses STR in stream ioctl defines --#undef STR --#include --#undef STR --#define STR(a) #a -- --// The attach mechanism on Solaris is implemented using the Doors IPC --// mechanism. The first tool to attempt to attach causes the attach --// listener thread to startup. This thread creats a door that is --// associated with a function that enqueues an operation to the attach --// listener. The door is attached to a file in the file system so that --// client (tools) can locate it. To enqueue an operation to the VM the --// client calls through the door which invokes the enqueue function in --// this process. The credentials of the client are checked and if the --// effective uid matches this process then the operation is enqueued. --// When an operation completes the attach listener is required to send the --// operation result and any result data to the client. In this implementation --// the result is returned via a UNIX domain socket. A pair of connected --// sockets (socketpair) is created in the enqueue function and the file --// descriptor for one of the sockets is returned to the client as the --// return from the door call. The other end is retained in this process. --// When the operation completes the result is sent to the client and --// the socket is closed. -- --// forward reference --class SolarisAttachOperation; -- --class SolarisAttachListener: AllStatic { -- private: -- -- // the path to which we attach the door file descriptor -- static char _door_path[PATH_MAX+1]; -- static volatile bool _has_door_path; -- -- // door descriptor returned by door_create -- static int _door_descriptor; -- -- static bool _atexit_registered; -- -- // mutex to protect operation list -- static pthread_mutex_t _mutex; -- -- // semaphore to wakeup listener thread -- static sema_t _wakeup; -- -- static pthread_mutex_t* mutex() { return &_mutex; } -- static sema_t* wakeup() { return &_wakeup; } -- -- // enqueued operation list -- static SolarisAttachOperation* _head; -- static SolarisAttachOperation* _tail; -- -- static SolarisAttachOperation* head() { return _head; } -- static void set_head(SolarisAttachOperation* head) { _head = head; } -- -- static SolarisAttachOperation* tail() { return _tail; } -- static void set_tail(SolarisAttachOperation* tail) { _tail = tail; } -- -- // create the door -- static int create_door(); -- -- public: -- enum { -- ATTACH_PROTOCOL_VER = 1 // protocol version -- }; -- enum { -- ATTACH_ERROR_BADREQUEST = 100, // error code returned by -- ATTACH_ERROR_BADVERSION = 101, // the door call -- ATTACH_ERROR_RESOURCE = 102, -- ATTACH_ERROR_INTERNAL = 103, -- ATTACH_ERROR_DENIED = 104 -- }; -- -- static void set_door_path(char* path) { -- if (path == NULL) { -- _door_path[0] = '\0'; -- _has_door_path = false; -- } else { -- strncpy(_door_path, path, PATH_MAX); -- _door_path[PATH_MAX] = '\0'; // ensure it's nul terminated -- _has_door_path = true; -- } -- } -- -- static void set_door_descriptor(int dd) { _door_descriptor = dd; } -- -- // initialize the listener -- static int init(); -- -- static bool has_door_path() { return _has_door_path; } -- static char* door_path() { return _door_path; } -- static int door_descriptor() { return _door_descriptor; } -- -- // enqueue an operation -- static void enqueue(SolarisAttachOperation* op); -- -- // dequeue an operation -- static SolarisAttachOperation* dequeue(); --}; -- -- --// SolarisAttachOperation is an AttachOperation that additionally encapsulates --// a socket connection to the requesting client/tool. SolarisAttachOperation --// can additionally be held in a linked list. -- --class SolarisAttachOperation: public AttachOperation { -- private: -- friend class SolarisAttachListener; -- -- // connection to client -- int _socket; -- -- // linked list support -- SolarisAttachOperation* _next; -- -- SolarisAttachOperation* next() { return _next; } -- void set_next(SolarisAttachOperation* next) { _next = next; } -- -- public: -- void complete(jint res, bufferedStream* st); -- -- int socket() const { return _socket; } -- void set_socket(int s) { _socket = s; } -- -- SolarisAttachOperation(char* name) : AttachOperation(name) { -- set_socket(-1); -- set_next(NULL); -- } --}; -- --// statics --char SolarisAttachListener::_door_path[PATH_MAX+1]; --volatile bool SolarisAttachListener::_has_door_path; --int SolarisAttachListener::_door_descriptor = -1; --bool SolarisAttachListener::_atexit_registered = false; --pthread_mutex_t SolarisAttachListener::_mutex; --sema_t SolarisAttachListener::_wakeup; --SolarisAttachOperation* SolarisAttachListener::_head = NULL; --SolarisAttachOperation* SolarisAttachListener::_tail = NULL; -- --// Supporting class to help split a buffer into individual components --class ArgumentIterator : public StackObj { -- private: -- char* _pos; -- char* _end; -- public: -- ArgumentIterator(char* arg_buffer, size_t arg_size) { -- _pos = arg_buffer; -- _end = _pos + arg_size - 1; -- } -- char* next() { -- if (*_pos == '\0') { -- // advance the iterator if possible (null arguments) -- if (_pos < _end) { -- _pos += 1; -- } -- return NULL; -- } -- char* res = _pos; -- char* next_pos = strchr(_pos, '\0'); -- if (next_pos < _end) { -- next_pos++; -- } -- _pos = next_pos; -- return res; -- } --}; -- --// Calls from the door function to check that the client credentials --// match this process. Returns 0 if credentials okay, otherwise -1. --static int check_credentials() { -- ucred_t *cred_info = NULL; -- int ret = -1; // deny by default -- -- // get client credentials -- if (door_ucred(&cred_info) == -1) { -- return -1; // unable to get them, deny -- } -- -- // get euid/egid from ucred_free -- uid_t ucred_euid = ucred_geteuid(cred_info); -- gid_t ucred_egid = ucred_getegid(cred_info); -- -- // check that the effective uid/gid matches -- if (os::Posix::matches_effective_uid_and_gid_or_root(ucred_euid, ucred_egid)) { -- ret = 0; // allow -- } -- -- ucred_free(cred_info); -- return ret; --} -- -- --// Parses the argument buffer to create an AttachOperation that we should --// enqueue to the attach listener. --// The buffer is expected to be formatted as follows: --// 00000 --// where is the version number (must be "1"), is the command --// name ("load, "datadump", ...) and is an argument. --// --static SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) { -- // assume bad request until parsed -- *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST; -- -- if (arg_size < 2 || argp[arg_size-1] != '\0') { -- return NULL; // no ver or not null terminated -- } -- -- // Use supporting class to iterate over the buffer -- ArgumentIterator args(argp, arg_size); -- -- // First check the protocol version -- char* ver = args.next(); -- if (ver == NULL) { -- return NULL; -- } -- if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) { -- *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION; -- return NULL; -- } -- -- // Get command name and create the operation -- char* name = args.next(); -- if (name == NULL || strlen(name) > AttachOperation::name_length_max) { -- return NULL; -- } -- SolarisAttachOperation* op = new SolarisAttachOperation(name); -- -- // Iterate over the arguments -- for (int i=0; iset_arg(i, NULL); -- } else { -- if (strlen(arg) > AttachOperation::arg_length_max) { -- delete op; -- return NULL; -- } -- op->set_arg(i, arg); -- } -- } -- -- // return operation -- *err = 0; -- return op; --} -- --// This is door function which the client executes via a door_call. --extern "C" { -- static void enqueue_proc(void* cookie, char* argp, size_t arg_size, -- door_desc_t* dt, uint_t n_desc) -- { -- int return_fd = -1; -- SolarisAttachOperation* op = NULL; -- -- // wait up to 10 seconds for listener to be up and running -- jint res = 0; -- int sleep_count = 0; -- while (!AttachListener::is_initialized()) { -- sleep(1); // 1 second -- sleep_count++; -- if (sleep_count > 10) { // try for 10 seconds -- debug_only(warning("door_call when not enabled")); -- res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL; -- break; -- } -- } -- -- // check client credentials -- if (res == 0) { -- if (check_credentials() != 0) { -- res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED; -- } -- } -- -- // if we are stopped at ShowMessageBoxOnError then maybe we can -- // load a diagnostic library -- if (res == 0 && VMError::is_error_reported()) { -- if (ShowMessageBoxOnError) { -- // TBD - support loading of diagnostic library here -- } -- -- // can't enqueue operation after fatal error -- res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; -- } -- -- // create the operation -- if (res == 0) { -- int err; -- op = create_operation(argp, arg_size, &err); -- res = (op == NULL) ? (jint)err : 0; -- } -- -- // create a pair of connected sockets. Store the file descriptor -- // for one end in the operation and enqueue the operation. The -- // file descriptor for the other end wil be returned to the client. -- if (res == 0) { -- int s[2]; -- if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) { -- delete op; -- res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; -- } else { -- op->set_socket(s[0]); -- return_fd = s[1]; -- SolarisAttachListener::enqueue(op); -- } -- } -- -- // Return 0 (success) + file descriptor, or non-0 (error) -- if (res == 0) { -- door_desc_t desc; -- // DOOR_RELEASE flag makes sure fd is closed after passing it to -- // the client. See door_return(3DOOR) man page. -- desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; -- desc.d_data.d_desc.d_descriptor = return_fd; -- door_return((char*)&res, sizeof(res), &desc, 1); -- } else { -- door_return((char*)&res, sizeof(res), NULL, 0); -- } -- } --} -- --// atexit hook to detach the door and remove the file --extern "C" { -- static void listener_cleanup() { -- int dd = SolarisAttachListener::door_descriptor(); -- if (dd >= 0) { -- SolarisAttachListener::set_door_descriptor(-1); -- ::close(dd); -- } -- if (SolarisAttachListener::has_door_path()) { -- char* path = SolarisAttachListener::door_path(); -- ::fdetach(path); -- ::unlink(path); -- SolarisAttachListener::set_door_path(NULL); -- } -- } --} -- --// Create the door --int SolarisAttachListener::create_door() { -- char door_path[PATH_MAX+1]; -- char initial_path[PATH_MAX+1]; -- int fd, res; -- -- // register exit function -- if (!_atexit_registered) { -- _atexit_registered = true; -- ::atexit(listener_cleanup); -- } -- -- // create the door descriptor -- int dd = ::door_create(enqueue_proc, NULL, 0); -- if (dd < 0) { -- return -1; -- } -- -- // create initial file to attach door descriptor -- snprintf(door_path, sizeof(door_path), "%s/.java_pid%d", -- os::get_temp_directory(), os::current_process_id()); -- snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path); -- RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd); -- if (fd == -1) { -- log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno); -- ::door_revoke(dd); -- return -1; -- } -- assert(fd >= 0, "bad file descriptor"); -- ::close(fd); -- -- // attach the door descriptor to the file -- if ((res = ::fattach(dd, initial_path)) == -1) { -- // if busy then detach and try again -- if (errno == EBUSY) { -- ::fdetach(initial_path); -- res = ::fattach(dd, initial_path); -- } -- if (res == -1) { -- log_debug(attach)("unable to create door - fattach failed (%d)", errno); -- ::door_revoke(dd); -- dd = -1; -- } -- } -- -- // rename file so that clients can attach -- if (dd >= 0) { -- if (::rename(initial_path, door_path) == -1) { -- ::close(dd); -- ::fdetach(initial_path); -- log_debug(attach)("unable to create door - rename %s to %s failed (%d)", initial_path, door_path, errno); -- dd = -1; -- } -- } -- if (dd >= 0) { -- set_door_descriptor(dd); -- set_door_path(door_path); -- log_trace(attach)("door file %s created succesfully", door_path); -- } else { -- // unable to create door, attach it to file, or rename file into place -- ::unlink(initial_path); -- return -1; -- } -- -- return 0; --} -- --// Initialization - create the door, locks, and other initialization --int SolarisAttachListener::init() { -- if (create_door()) { -- return -1; -- } -- -- int status = pthread_mutex_init(&_mutex, NULL); -- assert_status(status==0, status, "mutex_init"); -- -- status = ::sema_init(&_wakeup, 0, NULL, NULL); -- assert_status(status==0, status, "sema_init"); -- -- set_head(NULL); -- set_tail(NULL); -- -- return 0; --} -- --// Dequeue an operation --SolarisAttachOperation* SolarisAttachListener::dequeue() { -- for (;;) { -- int res; -- -- // wait for somebody to enqueue something -- while ((res = ::sema_wait(wakeup())) == EINTR) -- ; -- if (res) { -- warning("sema_wait failed: %s", os::strerror(res)); -- return NULL; -- } -- -- // lock the list -- res = pthread_mutex_lock(mutex()); -- assert(res == 0, "mutex_lock failed"); -- -- // remove the head of the list -- SolarisAttachOperation* op = head(); -- if (op != NULL) { -- set_head(op->next()); -- if (head() == NULL) { -- set_tail(NULL); -- } -- } -- -- // unlock -- pthread_mutex_unlock(mutex()); -- -- // if we got an operation when return it. -- if (op != NULL) { -- return op; -- } -- } --} -- --// Enqueue an operation --void SolarisAttachListener::enqueue(SolarisAttachOperation* op) { -- // lock list -- int res = pthread_mutex_lock(mutex()); -- assert(res == 0, "mutex_lock failed"); -- -- // enqueue at tail -- op->set_next(NULL); -- if (head() == NULL) { -- set_head(op); -- } else { -- tail()->set_next(op); -- } -- set_tail(op); -- -- // wakeup the attach listener -- RESTARTABLE(::sema_post(wakeup()), res); -- assert(res == 0, "sema_post failed"); -- -- // unlock -- pthread_mutex_unlock(mutex()); --} -- -- --// support function - writes the (entire) buffer to a socket --static int write_fully(int s, char* buf, int len) { -- do { -- int n = ::write(s, buf, len); -- if (n == -1) { -- if (errno != EINTR) return -1; -- } else { -- buf += n; -- len -= n; -- } -- } -- while (len > 0); -- return 0; --} -- --// Complete an operation by sending the operation result and any result --// output to the client. At this time the socket is in blocking mode so --// potentially we can block if there is a lot of data and the client is --// non-responsive. For most operations this is a non-issue because the --// default send buffer is sufficient to buffer everything. In the future --// if there are operations that involves a very big reply then it the --// socket could be made non-blocking and a timeout could be used. -- --void SolarisAttachOperation::complete(jint res, bufferedStream* st) { -- if (this->socket() >= 0) { -- JavaThread* thread = JavaThread::current(); -- ThreadBlockInVM tbivm(thread); -- -- // write operation result -- char msg[32]; -- sprintf(msg, "%d\n", res); -- int rc = write_fully(this->socket(), msg, strlen(msg)); -- -- // write any result data -- if (rc == 0) { -- write_fully(this->socket(), (char*) st->base(), st->size()); -- ::shutdown(this->socket(), 2); -- } -- -- // close socket and we're done -- ::close(this->socket()); -- } -- delete this; --} -- -- --// AttachListener functions -- --AttachOperation* AttachListener::dequeue() { -- JavaThread* thread = JavaThread::current(); -- ThreadBlockInVM tbivm(thread); -- -- AttachOperation* op = SolarisAttachListener::dequeue(); -- -- return op; --} -- -- --// Performs initialization at vm startup --// For Solaris we remove any stale .java_pid file which could cause --// an attaching process to think we are ready to receive a door_call --// before we are properly initialized -- --void AttachListener::vm_start() { -- char fn[PATH_MAX+1]; -- struct stat64 st; -- int ret; -- -- int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d", -- os::get_temp_directory(), os::current_process_id()); -- assert(n < sizeof(fn), "java_pid file name buffer overflow"); -- -- RESTARTABLE(::stat64(fn, &st), ret); -- if (ret == 0) { -- ret = ::unlink(fn); -- if (ret == -1) { -- log_debug(attach)("Failed to remove stale attach pid file at %s", fn); -- } -- } --} -- --int AttachListener::pd_init() { -- JavaThread* thread = JavaThread::current(); -- ThreadBlockInVM tbivm(thread); -- -- int ret_code = SolarisAttachListener::init(); -- -- return ret_code; --} -- --// Attach Listener is started lazily except in the case when --// +ReduseSignalUsage is used --bool AttachListener::init_at_startup() { -- if (ReduceSignalUsage) { -- return true; -- } else { -- return false; -- } --} -- --bool AttachListener::check_socket_file() { -- int ret; -- struct stat64 st; -- ret = stat64(SolarisAttachListener::door_path(), &st); -- if (ret == -1) { // need to restart attach listener. -- log_debug(attach)("Door file %s does not exist - Restart Attach Listener", -- SolarisAttachListener::door_path()); -- -- listener_cleanup(); -- -- // wait to terminate current attach listener instance... -- while (AttachListener::transit_state(AL_INITIALIZING, -- AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) { -- os::naked_yield(); -- } -- return is_init_trigger(); -- } -- return false; --} -- --// If the file .attach_pid exists in the working directory --// or /tmp then this is the trigger to start the attach mechanism --bool AttachListener::is_init_trigger() { -- if (init_at_startup() || is_initialized()) { -- return false; // initialized at startup or already initialized -- } -- char fn[PATH_MAX + 1]; -- int ret; -- struct stat64 st; -- sprintf(fn, ".attach_pid%d", os::current_process_id()); -- RESTARTABLE(::stat64(fn, &st), ret); -- if (ret == -1) { -- log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); -- snprintf(fn, sizeof(fn), "%s/.attach_pid%d", -- os::get_temp_directory(), os::current_process_id()); -- RESTARTABLE(::stat64(fn, &st), ret); -- if (ret == -1) { -- log_debug(attach)("Failed to find attach file: %s", fn); -- } -- } -- if (ret == 0) { -- // simple check to avoid starting the attach mechanism when -- // a bogus non-root user creates the file -- if (os::Posix::matches_effective_uid_or_root(st.st_uid)) { -- init(); -- log_trace(attach)("Attach triggered by %s", fn); -- return true; -- } else { -- log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid()); -- } -- } -- return false; --} -- --// if VM aborts then detach/cleanup --void AttachListener::abort() { -- listener_cleanup(); --} -- --void AttachListener::pd_data_dump() { -- os::signal_notify(SIGQUIT); --} -- --static jint enable_dprobes(AttachOperation* op, outputStream* out) { -- const char* probe = op->arg(0); -- if (probe == NULL || probe[0] == '\0') { -- out->print_cr("No probe specified"); -- return JNI_ERR; -- } else { -- char *end; -- long val = strtol(probe, &end, 10); -- if (end == probe || val < 0 || val > INT_MAX) { -- out->print_cr("invalid probe type"); -- return JNI_ERR; -- } else { -- int probe_typess = (int) val; -- DTrace::enable_dprobes(probe_typess); -- return JNI_OK; -- } -- } --} -- --// platform specific operations table --static AttachOperationFunctionInfo funcs[] = { -- { "enabledprobes", enable_dprobes }, -- { NULL, NULL } --}; -- --AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* name) { -- int i; -- for (i = 0; funcs[i].name != NULL; i++) { -- if (strcmp(funcs[i].name, name) == 0) { -- return &funcs[i]; -- } -- } -- return NULL; --} -- --// Solaris specific global flag set. --jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { -- const char* name = op->arg(0); -- assert(name != NULL, "flag name should not be null"); -- bool flag = true; -- const char* arg1; -- if ((arg1 = op->arg(1)) != NULL) { -- char *end; -- flag = (strtol(arg1, &end, 10) != 0); -- if (arg1 == end) { -- out->print_cr("flag value has to be an integer"); -- return JNI_ERR; -- } -- } -- -- if (strcmp(name, "DTraceMonitorProbes") == 0) { -- DTrace::set_monitor_dprobes(flag); -- return JNI_OK; -- } -- -- out->print_cr("flag '%s' cannot be changed", name); -- return JNI_ERR; --} -- --void AttachListener::pd_detachall() { -- DTrace::detach_all_clients(); --} ---- old/src/hotspot/os/solaris/c1_globals_solaris.hpp 2020-05-20 18:09:28.228984152 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,36 +0,0 @@ --/* -- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP --#define OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP -- --#include "utilities/globalDefinitions.hpp" --#include "utilities/macros.hpp" -- --// --// Sets the default values for operating system dependent flags used by the --// client compiler. (see c1_globals.hpp) --// -- --#endif // OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP ---- old/src/hotspot/os/solaris/c2_globals_solaris.hpp 2020-05-20 18:09:28.972998437 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,36 +0,0 @@ --/* -- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP --#define OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP -- --#include "utilities/globalDefinitions.hpp" --#include "utilities/macros.hpp" -- --// --// Sets the default values for operating system dependent flags used by the --// server compiler. (see c2_globals.hpp) --// -- --#endif // OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP ---- old/src/hotspot/os/solaris/decoder_solaris.cpp 2020-05-20 18:09:29.669011799 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,32 +0,0 @@ --/* -- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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 "utilities/decoder_elf.hpp" -- --#include -- --bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { -- return !cplus_demangle(symbol, buf, (size_t)buflen); --} -- ---- old/src/hotspot/os/solaris/dtrace/jhelper.d 2020-05-20 18:09:30.445026698 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,540 +0,0 @@ --/* -- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. 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. -- * -- */ -- --/* This file is auto-generated */ --#include "JvmOffsetsIndex.h" -- --#define DEBUG -- --#ifdef DEBUG --#define MARK_LINE this->line = __LINE__ --#else --#define MARK_LINE --#endif -- --#ifdef _LP64 --#define STACK_BIAS 0x7ff --#define pointer uint64_t --#else --#define STACK_BIAS 0 --#define pointer uint32_t --#endif -- --extern pointer __JvmOffsets; -- --/* GrowableArray* */ --extern pointer __1cJCodeCacheG_heaps_; -- --extern pointer __1cIUniverseO_collectedHeap_; -- --extern pointer __1cHnmethodG__vtbl_; --extern pointer __1cGMethodG__vtbl_; --extern pointer __1cKBufferBlobG__vtbl_; -- --#define copyin_ptr(ADDR) *(pointer*) copyin((pointer) (ADDR), sizeof(pointer)) --#define copyin_uchar(ADDR) *(uchar_t*) copyin((pointer) (ADDR), sizeof(uchar_t)) --#define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t)) --#define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t)) --#define copyin_int32(ADDR) *(int32_t*) copyin((pointer) (ADDR), sizeof(int32_t)) --#define copyin_uint8(ADDR) *(uint8_t*) copyin((pointer) (ADDR), sizeof(uint8_t)) -- --#define copyin_offset(JVM_CONST) JVM_CONST = \ -- copyin_int32(JvmOffsetsPtr + IDX_##JVM_CONST * sizeof(int32_t)) -- --int init_done; -- --dtrace:helper:ustack: --{ -- MARK_LINE; -- this->done = 0; -- /* -- * TBD: -- * Here we initialize init_done, otherwise jhelper does not work. -- * Therefore, copyin_offset() statements work multiple times now. -- * There is a hope we could avoid it in the future, and so, -- * this initialization can be removed. -- */ -- init_done = 0; -- this->error = (char *) NULL; -- this->result = (char *) NULL; -- this->isMethod = 0; -- this->codecache = 0; -- this->klass = (pointer) NULL; -- this->vtbl = (pointer) NULL; -- this->suffix = '\0'; --} -- --dtrace:helper:ustack: --{ -- MARK_LINE; -- /* Initialization of JvmOffsets constants */ -- JvmOffsetsPtr = (pointer) &``__JvmOffsets; --} -- --dtrace:helper:ustack: --/!init_done && !this->done/ --{ -- MARK_LINE; -- -- copyin_offset(POINTER_SIZE); -- copyin_offset(COMPILER); -- copyin_offset(OFFSET_CollectedHeap_reserved); -- copyin_offset(OFFSET_MemRegion_start); -- copyin_offset(OFFSET_MemRegion_word_size); -- copyin_offset(SIZE_HeapWord); -- -- copyin_offset(OFFSET_interpreter_frame_method); -- copyin_offset(OFFSET_Klass_name); -- copyin_offset(OFFSET_ConstantPool_pool_holder); -- -- copyin_offset(OFFSET_HeapBlockHeader_used); -- copyin_offset(OFFSET_oopDesc_metadata); -- -- copyin_offset(OFFSET_Symbol_length); -- copyin_offset(OFFSET_Symbol_body); -- -- copyin_offset(OFFSET_Method_constMethod); -- copyin_offset(OFFSET_ConstMethod_constants); -- copyin_offset(OFFSET_ConstMethod_name_index); -- copyin_offset(OFFSET_ConstMethod_signature_index); -- -- copyin_offset(OFFSET_CodeHeap_memory); -- copyin_offset(OFFSET_CodeHeap_segmap); -- copyin_offset(OFFSET_CodeHeap_log2_segment_size); -- -- copyin_offset(OFFSET_GrowableArray_CodeHeap_data); -- copyin_offset(OFFSET_GrowableArray_CodeHeap_len); -- -- copyin_offset(OFFSET_VirtualSpace_low); -- copyin_offset(OFFSET_VirtualSpace_high); -- -- copyin_offset(OFFSET_CodeBlob_name); -- -- copyin_offset(OFFSET_nmethod_method); -- copyin_offset(SIZE_HeapBlockHeader); -- copyin_offset(SIZE_oopDesc); -- copyin_offset(SIZE_ConstantPool); -- -- copyin_offset(OFFSET_NarrowPtrStruct_base); -- copyin_offset(OFFSET_NarrowPtrStruct_shift); -- -- /* -- * The PC to translate is in arg0. -- */ -- this->pc = arg0; -- --#if defined(__i386) || defined(__amd64) -- this->methodPtr = copyin_ptr(arg1 + OFFSET_interpreter_frame_method); --#else --#error "Don't know architecture" --#endif -- -- /* Read address of GrowableArray */ -- // this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_); -- this->code_heaps_address = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cJCodeCacheG_heaps_ ) , sizeof ( uint64_t ) ); -- -- /* Read address of _data array field in GrowableArray */ -- this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data); -- this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len); -- -- this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_; -- -- /* -- * Get Java heap bounds -- */ -- // this->Universe_collectedHeap = copyin_ptr(&``__1cIUniverseO_collectedHeap_); -- this->Universe_collectedHeap = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cIUniverseO_collectedHeap_ ) , sizeof ( uint64_t ) ); -- -- this->heap_start = copyin_ptr(this->Universe_collectedHeap + -- OFFSET_CollectedHeap_reserved + -- OFFSET_MemRegion_start); -- this->heap_size = SIZE_HeapWord * -- copyin_ptr(this->Universe_collectedHeap + -- OFFSET_CollectedHeap_reserved + -- OFFSET_MemRegion_word_size -- ); -- this->heap_end = this->heap_start + this->heap_size; --} -- --/* -- * IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in -- * the code cache. If more code heaps are added the following probes have to -- * be extended. This is done by simply adding a probe to get the heap bounds -- * and another probe to set the code heap address of the newly created heap. -- */ -- --/* -- * ----- BEGIN: Get bounds of code heaps ----- -- */ --dtrace:helper:ustack: --/init_done < 1 && this->number_of_heaps >= 1 && !this->done/ --{ -- MARK_LINE; -- /* CodeHeap 1 */ -- init_done = 1; -- this->code_heap1_address = copyin_ptr(this->code_heaps_array_address); -- this->code_heap1_low = copyin_ptr(this->code_heap1_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); -- this->code_heap1_high = copyin_ptr(this->code_heap1_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); --} -- --dtrace:helper:ustack: --/init_done < 2 && this->number_of_heaps >= 2 && !this->done/ --{ -- MARK_LINE; -- /* CodeHeap 2 */ -- init_done = 2; -- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; -- this->code_heap2_address = copyin_ptr(this->code_heaps_array_address); -- this->code_heap2_low = copyin_ptr(this->code_heap2_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); -- this->code_heap2_high = copyin_ptr(this->code_heap2_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); --} -- --dtrace:helper:ustack: --/init_done < 3 && this->number_of_heaps >= 3 && !this->done/ --{ -- /* CodeHeap 3 */ -- init_done = 3; -- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; -- this->code_heap3_address = copyin_ptr(this->code_heaps_array_address); -- this->code_heap3_low = copyin_ptr(this->code_heap3_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); -- this->code_heap3_high = copyin_ptr(this->code_heap3_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); --} -- --dtrace:helper:ustack: --/init_done < 4 && this->number_of_heaps >= 4 && !this->done/ --{ -- /* CodeHeap 4 */ -- init_done = 4; -- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; -- this->code_heap4_address = copyin_ptr(this->code_heaps_array_address); -- this->code_heap4_low = copyin_ptr(this->code_heap4_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); -- this->code_heap4_high = copyin_ptr(this->code_heap4_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); --} -- --dtrace:helper:ustack: --/init_done < 5 && this->number_of_heaps >= 5 && !this->done/ --{ -- /* CodeHeap 5 */ -- init_done = 5; -- this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; -- this->code_heap5_address = copyin_ptr(this->code_heaps_array_address); -- this->code_heap5_low = copyin_ptr(this->code_heap5_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); -- this->code_heap5_high = copyin_ptr(this->code_heap5_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); --} --/* -- * ----- END: Get bounds of code heaps ----- -- */ -- --/* -- * ----- BEGIN: Get address of the code heap pc points to ----- -- */ --dtrace:helper:ustack: --/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/ --{ -- MARK_LINE; -- this->codecache = 1; -- this->code_heap_address = this->code_heap1_address; --} -- --dtrace:helper:ustack: --/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/ --{ -- MARK_LINE; -- this->codecache = 1; -- this->code_heap_address = this->code_heap2_address; --} -- --dtrace:helper:ustack: --/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/ --{ -- MARK_LINE; -- this->codecache = 1; -- this->code_heap_address = this->code_heap3_address; --} -- --dtrace:helper:ustack: --/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/ --{ -- MARK_LINE; -- this->codecache = 1; -- this->code_heap_address = this->code_heap4_address; --} -- --dtrace:helper:ustack: --/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/ --{ -- MARK_LINE; -- this->codecache = 1; -- this->code_heap_address = this->code_heap5_address; --} --/* -- * ----- END: Get address of the code heap pc points to ----- -- */ -- --dtrace:helper:ustack: --/!this->done && this->codecache/ --{ -- MARK_LINE; -- /* -- * Get code heap configuration -- */ -- this->code_heap_low = copyin_ptr(this->code_heap_address + -- OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); -- this->code_heap_segmap_low = copyin_ptr(this->code_heap_address + -- OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low); -- this->code_heap_log2_segment_size = copyin_uint32( -- this->code_heap_address + OFFSET_CodeHeap_log2_segment_size); -- -- /* -- * Find start -- */ -- this->segment = (this->pc - this->code_heap_low) >> -- this->code_heap_log2_segment_size; -- this->block = this->code_heap_segmap_low; -- this->tag = copyin_uchar(this->block + this->segment); --} -- --dtrace:helper:ustack: --/!this->done && this->codecache && this->tag > 0/ --{ -- MARK_LINE; -- this->tag = copyin_uchar(this->block + this->segment); -- this->segment = this->segment - this->tag; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache && this->tag > 0/ --{ -- MARK_LINE; -- this->tag = copyin_uchar(this->block + this->segment); -- this->segment = this->segment - this->tag; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache && this->tag > 0/ --{ -- MARK_LINE; -- this->tag = copyin_uchar(this->block + this->segment); -- this->segment = this->segment - this->tag; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache && this->tag > 0/ --{ -- MARK_LINE; -- this->tag = copyin_uchar(this->block + this->segment); -- this->segment = this->segment - this->tag; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache && this->tag > 0/ --{ -- MARK_LINE; -- this->tag = copyin_uchar(this->block + this->segment); -- this->segment = this->segment - this->tag; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache && this->tag > 0/ --{ -- MARK_LINE; -- this->error = ""; -- this->done = 1; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache/ --{ -- MARK_LINE; -- this->block = this->code_heap_low + -- (this->segment << this->code_heap_log2_segment_size); -- this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used); --} -- --dtrace:helper:ustack: --/!this->done && this->codecache && !this->used/ --{ -- MARK_LINE; -- this->error = ""; -- this->done = 1; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache/ --{ -- MARK_LINE; -- this->start = this->block + SIZE_HeapBlockHeader; -- this->vtbl = copyin_ptr(this->start); -- -- this->nmethod_vtbl = (pointer) &``__1cHnmethodG__vtbl_; -- this->BufferBlob_vtbl = (pointer) &``__1cKBufferBlobG__vtbl_; --} -- --dtrace:helper:ustack: --/!this->done && this->vtbl == this->nmethod_vtbl/ --{ -- MARK_LINE; -- this->methodPtr = copyin_ptr(this->start + OFFSET_nmethod_method); -- this->suffix = '*'; -- this->isMethod = 1; --} -- --dtrace:helper:ustack: --/!this->done && this->vtbl == this->BufferBlob_vtbl/ --{ -- MARK_LINE; -- this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name); --} -- -- --dtrace:helper:ustack: --/!this->done && this->vtbl == this->BufferBlob_vtbl && this->methodPtr != 0/ --{ -- MARK_LINE; -- this->klass = copyin_ptr(this->methodPtr); -- this->isMethod = this->klass == this->Method_vtbl; -- this->done = !this->isMethod; --} -- --dtrace:helper:ustack: --/!this->done && !this->isMethod/ --{ -- MARK_LINE; -- this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name); -- this->result = this->name != 0 ? copyinstr(this->name) : ""; -- this->done = 1; --} -- --dtrace:helper:ustack: --/!this->done && this->isMethod/ --{ -- MARK_LINE; -- this->constMethod = copyin_ptr(this->methodPtr + -- OFFSET_Method_constMethod); -- -- this->nameIndex = copyin_uint16(this->constMethod + -- OFFSET_ConstMethod_name_index); -- -- this->signatureIndex = copyin_uint16(this->constMethod + -- OFFSET_ConstMethod_signature_index); -- -- this->constantPool = copyin_ptr(this->constMethod + -- OFFSET_ConstMethod_constants); -- -- this->nameSymbol = copyin_ptr(this->constantPool + -- this->nameIndex * sizeof (pointer) + SIZE_ConstantPool); -- /* The symbol is a CPSlot and has lower bit set to indicate metadata */ -- this->nameSymbol &= (~1); /* remove metadata lsb */ -- -- this->nameSymbolLength = copyin_uint16(this->nameSymbol + -- OFFSET_Symbol_length); -- -- this->signatureSymbol = copyin_ptr(this->constantPool + -- this->signatureIndex * sizeof (pointer) + SIZE_ConstantPool); -- this->signatureSymbol &= (~1); /* remove metadata lsb */ -- -- this->signatureSymbolLength = copyin_uint16(this->signatureSymbol + -- OFFSET_Symbol_length); -- -- this->klassPtr = copyin_ptr(this->constantPool + -- OFFSET_ConstantPool_pool_holder); -- -- this->klassSymbol = copyin_ptr(this->klassPtr + -- OFFSET_Klass_name); -- -- this->klassSymbolLength = copyin_uint16(this->klassSymbol + -- OFFSET_Symbol_length); -- -- /* -- * Enough for three strings, plus the '.', plus the trailing '\0'. -- */ -- this->result = (char *) alloca(this->klassSymbolLength + -- this->nameSymbolLength + -- this->signatureSymbolLength + 2 + 1); -- -- copyinto(this->klassSymbol + OFFSET_Symbol_body, -- this->klassSymbolLength, this->result); -- -- /* -- * Add the '.' between the class and the name. -- */ -- this->result[this->klassSymbolLength] = '.'; -- -- copyinto(this->nameSymbol + OFFSET_Symbol_body, -- this->nameSymbolLength, -- this->result + this->klassSymbolLength + 1); -- -- copyinto(this->signatureSymbol + OFFSET_Symbol_body, -- this->signatureSymbolLength, -- this->result + this->klassSymbolLength + -- this->nameSymbolLength + 1); -- -- /* -- * Now we need to add a trailing '\0' and possibly a tag character. -- */ -- this->result[this->klassSymbolLength + 1 + -- this->nameSymbolLength + -- this->signatureSymbolLength] = this->suffix; -- this->result[this->klassSymbolLength + 2 + -- this->nameSymbolLength + -- this->signatureSymbolLength] = '\0'; -- -- this->done = 1; --} -- --dtrace:helper:ustack: --/this->done && this->error == (char *) NULL/ --{ -- this->result; --} -- --dtrace:helper:ustack: --/this->done && this->error != (char *) NULL/ --{ -- this->error; --} -- --dtrace:helper:ustack: --/!this->done && this->codecache/ --{ -- this->done = 1; -- "error"; --} -- -- --dtrace:helper:ustack: --/!this->done/ --{ -- NULL; --} ---- old/src/hotspot/os/solaris/globals_solaris.hpp 2020-05-20 18:09:31.185040905 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,49 +0,0 @@ --/* -- * Copyright (c) 2005, 2020, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_SOLARIS_GLOBALS_SOLARIS_HPP --#define OS_SOLARIS_GLOBALS_SOLARIS_HPP -- --// --// Defines Solaris specific flags. They are not available on other platforms. --// --#define RUNTIME_OS_FLAGS(develop, \ -- develop_pd, \ -- product, \ -- product_pd, \ -- notproduct, \ -- range, \ -- constraint) -- --// --// Defines Solaris-specific default values. The flags are available on all --// platforms, but they may have different default values on other platforms. --// --define_pd_global(size_t, PreTouchParallelChunkSize, 1 * G); --define_pd_global(bool, UseLargePages, true); --define_pd_global(bool, UseLargePagesIndividualAllocation, false); --define_pd_global(bool, UseOSErrorReporting, false); --define_pd_global(bool, UseThreadPriorities, false); -- --#endif // OS_SOLARIS_GLOBALS_SOLARIS_HPP ---- old/src/hotspot/os/solaris/osThread_solaris.cpp 2020-05-20 18:09:31.813052962 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,47 +0,0 @@ --/* -- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. 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. -- * -- */ -- --// no precompiled headers --#include "runtime/handles.inline.hpp" --#include "runtime/mutexLocker.hpp" --#include "runtime/os.hpp" --#include "runtime/osThread.hpp" --#include "runtime/safepoint.hpp" --#include "runtime/vmThread.hpp" -- --#include -- -- // *************************************************************** -- // Platform dependent initialization and cleanup -- // *************************************************************** -- --void OSThread::pd_initialize() { -- _thread_id = 0; -- sigemptyset(&_caller_sigmask); -- -- _vm_created_thread = false; --} -- --void OSThread::pd_destroy() { --} ---- old/src/hotspot/os/solaris/osThread_solaris.hpp 2020-05-20 18:09:32.557067247 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,93 +0,0 @@ --/* -- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_SOLARIS_OSTHREAD_SOLARIS_HPP --#define OS_SOLARIS_OSTHREAD_SOLARIS_HPP -- --// This is embedded via include into the class OSThread -- public: -- typedef thread_t thread_id_t; -- -- private: -- uint _lwp_id; // lwp ID, only used with bound threads -- int _native_priority; // Saved native priority when starting -- // a bound thread -- sigset_t _caller_sigmask; // Caller's signal mask -- bool _vm_created_thread; // true if the VM created this thread, -- // false if primary thread or attached thread -- public: -- uint lwp_id() const { return _lwp_id; } -- int native_priority() const { return _native_priority; } -- -- // Set and get state of _vm_created_thread flag -- void set_vm_created() { _vm_created_thread = true; } -- bool is_vm_created() { return _vm_created_thread; } -- -- // Methods to save/restore caller's signal mask -- sigset_t caller_sigmask() const { return _caller_sigmask; } -- void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } -- --#ifndef PRODUCT -- // Used for debugging, return a unique integer for each thread. -- int thread_identifier() const { return _thread_id; } --#endif --#ifdef ASSERT -- // On solaris reposition can fail in two ways: -- // 1: a mismatched pc, because signal is delivered too late, target thread -- // is resumed. -- // 2: on a timeout where signal is lost, target thread is resumed. -- bool valid_reposition_failure() { -- // only 1 and 2 can happen and we can handle both of them -- return true; -- } --#endif -- void set_lwp_id(uint id) { _lwp_id = id; } -- void set_native_priority(int prio) { _native_priority = prio; } -- -- public: -- pthread_t pthread_id() const { -- // Here: same as OSThread::thread_id() -- return _thread_id; -- } -- SuspendResume sr; -- -- private: -- void* _siginfo; -- ucontext_t* _ucontext; -- -- public: -- void set_siginfo(void* ptr) { _siginfo = ptr; } -- ucontext_t* ucontext() const { return _ucontext; } -- void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; } -- -- // *************************************************************** -- // Platform dependent initialization and cleanup -- // *************************************************************** -- --private: -- -- void pd_initialize(); -- void pd_destroy(); -- --#endif // OS_SOLARIS_OSTHREAD_SOLARIS_HPP ---- old/src/hotspot/os/solaris/os_perf_solaris.cpp 2020-05-20 18:09:33.261080763 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,808 +0,0 @@ --/* -- * Copyright (c) 2012, 2019, Oracle and/or its affiliates. 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 "jvm.h" --#include "memory/allocation.inline.hpp" --#include "runtime/os.hpp" --#include "runtime/os_perf.hpp" --#include "runtime/vm_version.hpp" --#include "os_solaris.inline.hpp" --#include "utilities/globalDefinitions.hpp" --#include "utilities/macros.hpp" -- --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include --#include -- --static const double NANOS_PER_SEC = 1000000000.0; -- --struct CPUPerfTicks { -- kstat_t* kstat; -- uint64_t last_idle; -- uint64_t last_total; -- double last_ratio; --}; -- --struct CPUPerfCounters { -- int nProcs; -- CPUPerfTicks* jvmTicks; -- kstat_ctl_t* kstat_ctrl; --}; -- --static int get_info(const char* path, void* info, size_t s, off_t o) { -- assert(path != NULL, "path is NULL!"); -- assert(info != NULL, "info is NULL!"); -- -- int fd = -1; -- -- if ((fd = os::open(path, O_RDONLY, 0)) < 0) { -- return OS_ERR; -- } -- if (pread(fd, info, s, o) != s) { -- close(fd); -- return OS_ERR; -- } -- close(fd); -- return OS_OK; --} -- --static int get_psinfo2(void* info, size_t s, off_t o) { -- return get_info("/proc/self/psinfo", info, s, o); --} -- --static int get_psinfo(psinfo_t* info) { -- return get_psinfo2(info, sizeof(*info), 0); --} -- --static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) { -- assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!"); -- assert(load != NULL, "load pointer is NULL!"); -- assert(cpu_stat != NULL, "cpu_stat pointer is NULL!"); -- -- if (load->kstat == NULL) { -- // no handle. -- return OS_ERR; -- } -- if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) { -- // disable handle for this CPU -- load->kstat = NULL; -- return OS_ERR; -- } -- return OS_OK; --} -- --static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) { -- assert(counters != NULL, "counters pointer is NULL!"); -- -- cpu_stat_t cpu_stat = {0}; -- -- if (which_logical_cpu >= counters->nProcs) { -- return .0; -- } -- -- CPUPerfTicks load = counters->jvmTicks[which_logical_cpu]; -- if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) { -- return .0; -- } -- -- uint_t* usage = cpu_stat.cpu_sysinfo.cpu; -- if (usage == NULL) { -- return .0; -- } -- -- uint64_t c_idle = usage[CPU_IDLE]; -- uint64_t c_total = 0; -- -- for (int i = 0; i < CPU_STATES; i++) { -- c_total += usage[i]; -- } -- -- // Calculate diff against previous snapshot -- uint64_t d_idle = c_idle - load.last_idle; -- uint64_t d_total = c_total - load.last_total; -- -- /** update if weve moved */ -- if (d_total > 0) { -- // Save current values for next time around -- load.last_idle = c_idle; -- load.last_total = c_total; -- load.last_ratio = (double) (d_total - d_idle) / d_total; -- } -- -- return load.last_ratio; --} -- --static int get_boot_time(uint64_t* time) { -- assert(time != NULL, "time pointer is NULL!"); -- setutxent(); -- for(;;) { -- struct utmpx* u; -- if ((u = getutxent()) == NULL) { -- break; -- } -- if (u->ut_type == BOOT_TIME) { -- *time = u->ut_xtime; -- endutxent(); -- return OS_OK; -- } -- } -- endutxent(); -- return OS_ERR; --} -- --static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) { -- assert(switches != NULL, "switches pointer is NULL!"); -- assert(counters != NULL, "counter pointer is NULL!"); -- *switches = 0; -- uint64_t s = 0; -- -- // Collect data from all CPUs -- for (int i = 0; i < counters->nProcs; i++) { -- cpu_stat_t cpu_stat = {0}; -- CPUPerfTicks load = counters->jvmTicks[i]; -- -- if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) { -- s += cpu_stat.cpu_sysinfo.pswitch; -- } else { -- //fail fast... -- return OS_ERR; -- } -- } -- *switches = s; -- return OS_OK; --} -- --static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) { -- assert(counters != NULL, "counters is NULL!"); -- assert(rate != NULL, "rate pointer is NULL!"); -- static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; -- static uint64_t lastTime = 0; -- static uint64_t lastSwitches = 0; -- static double lastRate = 0.0; -- -- uint64_t lt = 0; -- int res = 0; -- -- if (lastTime == 0) { -- uint64_t tmp; -- if (get_boot_time(&tmp) < 0) { -- return OS_ERR; -- } -- lt = tmp * 1000; -- } -- -- res = OS_OK; -- -- pthread_mutex_lock(&contextSwitchLock); -- { -- -- uint64_t sw = 0; -- clock_t t, d; -- -- if (lastTime == 0) { -- lastTime = lt; -- } -- -- t = clock(); -- d = t - lastTime; -- -- if (d == 0) { -- *rate = lastRate; -- } else if (get_noof_context_switches(counters, &sw)== OS_OK) { -- *rate = ((double)(sw - lastSwitches) / d) * 1000; -- lastRate = *rate; -- lastSwitches = sw; -- lastTime = t; -- } else { -- *rate = 0.0; -- res = OS_ERR; -- } -- if (*rate < 0.0) { -- *rate = 0.0; -- lastRate = 0.0; -- } -- } -- pthread_mutex_unlock(&contextSwitchLock); -- return res; -- } -- -- -- --class CPUPerformanceInterface::CPUPerformance : public CHeapObj { -- friend class CPUPerformanceInterface; -- private: -- CPUPerfCounters _counters; -- int cpu_load(int which_logical_cpu, double* cpu_load); -- int context_switch_rate(double* rate); -- int cpu_load_total_process(double* cpu_load); -- int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); -- -- CPUPerformance(); -- ~CPUPerformance(); -- bool initialize(); --}; -- --CPUPerformanceInterface::CPUPerformance::CPUPerformance() { -- _counters.nProcs = 0; -- _counters.jvmTicks = NULL; -- _counters.kstat_ctrl = NULL; --} -- --bool CPUPerformanceInterface::CPUPerformance::initialize() { -- // initialize kstat control structure, -- _counters.kstat_ctrl = kstat_open(); -- assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!"); -- -- if (NULL == _counters.kstat_ctrl) { -- return false; -- } -- -- // Get number of CPU(s) -- if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) { -- // ignore error? -- _counters.nProcs = 1; -- } -- -- assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!"); -- if (_counters.nProcs == 0) { -- return false; -- } -- -- // Data structure(s) for saving CPU load (one per CPU) -- size_t array_entry_count = _counters.nProcs; -- _counters.jvmTicks = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal); -- memset(_counters.jvmTicks, 0, array_entry_count * sizeof(*_counters.jvmTicks)); -- -- // Get kstat cpu_stat counters for every CPU -- // loop over kstat to find our cpu_stat(s) -- int i = 0; -- for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) { -- if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) { -- if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) { -- continue; -- } -- if (i == _counters.nProcs) { -- // more cpu_stats than reported CPUs -- break; -- } -- _counters.jvmTicks[i++].kstat = kstat; -- } -- } -- return true; --} -- --CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { -- FREE_C_HEAP_ARRAY(char, _counters.jvmTicks); -- if (_counters.kstat_ctrl != NULL) { -- kstat_close(_counters.kstat_ctrl); -- } --} -- --int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { -- assert(cpu_load != NULL, "cpu_load pointer is NULL!"); -- double t = .0; -- if (-1 == which_logical_cpu) { -- for (int i = 0; i < _counters.nProcs; i++) { -- t += get_cpu_load(i, &_counters); -- } -- // Cap total systemload to 1.0 -- t = MIN2((t / _counters.nProcs), 1.0); -- } else { -- t = MIN2(get_cpu_load(which_logical_cpu, &_counters), 1.0); -- } -- -- *cpu_load = t; -- return OS_OK; --} -- --int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { -- assert(cpu_load != NULL, "cpu_load pointer is NULL!"); -- -- psinfo_t info; -- -- // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s -- // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000. -- if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) { -- *cpu_load = 0.0; -- return OS_ERR; -- } -- *cpu_load = (double) info.pr_pctcpu / 0x8000; -- return OS_OK; --} -- --int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { -- assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited"); -- assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited"); -- assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited"); -- -- static uint64_t lastTime; -- static uint64_t lastUser, lastKernel; -- static double lastUserRes, lastKernelRes; -- -- pstatus_t pss; -- psinfo_t info; -- -- *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0; -- if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) { -- return OS_ERR; -- } -- -- if (get_psinfo(&info) != 0) { -- return OS_ERR; -- } -- -- // get the total time in user, kernel and total time -- // check ratios for 'lately' and multiply the 'recent load'. -- uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec; -- uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec; -- uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec; -- uint64_t diff = time - lastTime; -- double load = (double) info.pr_pctcpu / 0x8000; -- -- if (diff > 0) { -- lastUserRes = (load * (user - lastUser)) / diff; -- lastKernelRes = (load * (kernel - lastKernel)) / diff; -- -- // BUG9182835 - patch for clamping these values to sane ones. -- lastUserRes = MIN2(1, lastUserRes); -- lastUserRes = MAX2(0, lastUserRes); -- lastKernelRes = MIN2(1, lastKernelRes); -- lastKernelRes = MAX2(0, lastKernelRes); -- } -- -- double t = .0; -- cpu_load(-1, &t); -- // clamp at user+system and 1.0 -- if (lastUserRes + lastKernelRes > t) { -- t = MIN2(lastUserRes + lastKernelRes, 1.0); -- } -- -- *pjvmUserLoad = lastUserRes; -- *pjvmKernelLoad = lastKernelRes; -- *psystemTotalLoad = t; -- -- lastTime = time; -- lastUser = user; -- lastKernel = kernel; -- -- return OS_OK; --} -- --int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { -- return perf_context_switch_rate(&_counters, rate); --} -- --CPUPerformanceInterface::CPUPerformanceInterface() { -- _impl = NULL; --} -- --bool CPUPerformanceInterface::initialize() { -- _impl = new CPUPerformanceInterface::CPUPerformance(); -- return _impl->initialize(); --} -- --CPUPerformanceInterface::~CPUPerformanceInterface(void) { -- if (_impl != NULL) { -- delete _impl; -- } --} -- --int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { -- return _impl->cpu_load(which_logical_cpu, cpu_load); --} -- --int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { -- return _impl->cpu_load_total_process(cpu_load); --} -- --int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const { -- return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); --} -- --int CPUPerformanceInterface::context_switch_rate(double* rate) const { -- return _impl->context_switch_rate(rate); --} -- --class SystemProcessInterface::SystemProcesses : public CHeapObj { -- friend class SystemProcessInterface; -- private: -- class ProcessIterator : public CHeapObj { -- friend class SystemProcessInterface::SystemProcesses; -- private: -- DIR* _dir; -- struct dirent* _entry; -- bool _valid; -- -- ProcessIterator(); -- ~ProcessIterator(); -- bool initialize(); -- -- bool is_valid() const { return _valid; } -- bool is_valid_entry(struct dirent* const entry) const; -- bool is_dir(const char* const name) const; -- char* allocate_string(const char* const str) const; -- int current(SystemProcess* const process_info); -- int next_process(); -- }; -- -- ProcessIterator* _iterator; -- SystemProcesses(); -- bool initialize(); -- ~SystemProcesses(); -- -- //information about system processes -- int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; --}; -- --bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const { -- struct stat64 mystat; -- int ret_val = 0; -- -- ret_val = ::stat64(name, &mystat); -- -- if (ret_val < 0) { -- return false; -- } -- ret_val = S_ISDIR(mystat.st_mode); -- return ret_val > 0; --} -- --// if it has a numeric name, is a directory and has a 'psinfo' file in it --bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const { -- // ignore the "." and ".." directories -- if ((strcmp(entry->d_name, ".") == 0) || -- (strcmp(entry->d_name, "..") == 0)) { -- return false; -- } -- -- char buffer[PATH_MAX] = {0}; -- uint64_t size = 0; -- bool result = false; -- FILE *fp = NULL; -- -- if (atoi(entry->d_name) != 0) { -- jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name); -- -- if (is_dir(buffer)) { -- memset(buffer, 0, PATH_MAX); -- jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name); -- if ((fp = fopen(buffer, "r")) != NULL) { -- int nread = 0; -- psinfo_t psinfo_data; -- if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) { -- // only considering system process owned by root -- if (psinfo_data.pr_uid == 0) { -- result = true; -- } -- } -- } -- } -- } -- -- if (fp != NULL) { -- fclose(fp); -- } -- -- return result; --} -- --char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { -- if (str != NULL) { -- return os::strdup_check_oom(str, mtInternal); -- } -- return NULL; --} -- --int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { -- if (!is_valid()) { -- return OS_ERR; -- } -- -- char psinfo_path[PATH_MAX] = {0}; -- jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name); -- -- FILE *fp = NULL; -- if ((fp = fopen(psinfo_path, "r")) == NULL) { -- return OS_ERR; -- } -- -- int nread = 0; -- psinfo_t psinfo_data; -- if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) { -- fclose(fp); -- return OS_ERR; -- } -- -- char *exe_path = NULL; -- if ((psinfo_data.pr_fname != NULL) && -- (psinfo_data.pr_psargs != NULL)) { -- char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname); -- if (path_substring != NULL) { -- int len = path_substring - psinfo_data.pr_psargs; -- exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal); -- jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs); -- exe_path[len] = '\0'; -- } -- } -- -- process_info->set_pid(atoi(_entry->d_name)); -- process_info->set_name(allocate_string(psinfo_data.pr_fname)); -- process_info->set_path(allocate_string(exe_path)); -- process_info->set_command_line(allocate_string(psinfo_data.pr_psargs)); -- -- if (exe_path != NULL) { -- FREE_C_HEAP_ARRAY(char, exe_path); -- } -- -- if (fp != NULL) { -- fclose(fp); -- } -- -- return OS_OK; --} -- --int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { -- if (!is_valid()) { -- return OS_ERR; -- } -- -- do { -- _entry = os::readdir(_dir); -- if (_entry == NULL) { -- // Error or reached end. Could use errno to distinguish those cases. -- _valid = false; -- return OS_ERR; -- } -- } while(!is_valid_entry(_entry)); -- -- _valid = true; -- return OS_OK; --} -- --SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { -- _dir = NULL; -- _entry = NULL; -- _valid = false; --} -- --bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { -- _dir = os::opendir("/proc"); -- _entry = NULL; -- _valid = true; -- next_process(); -- -- return true; --} -- --SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { -- if (_dir != NULL) { -- os::closedir(_dir); -- } --} -- --SystemProcessInterface::SystemProcesses::SystemProcesses() { -- _iterator = NULL; --} -- --bool SystemProcessInterface::SystemProcesses::initialize() { -- _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); -- return _iterator->initialize(); --} -- --SystemProcessInterface::SystemProcesses::~SystemProcesses() { -- if (_iterator != NULL) { -- delete _iterator; -- } --} -- --int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const { -- assert(system_processes != NULL, "system_processes pointer is NULL!"); -- assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!"); -- assert(_iterator != NULL, "iterator is NULL!"); -- -- // initialize pointers -- *no_of_sys_processes = 0; -- *system_processes = NULL; -- -- while (_iterator->is_valid()) { -- SystemProcess* tmp = new SystemProcess(); -- _iterator->current(tmp); -- -- //if already existing head -- if (*system_processes != NULL) { -- //move "first to second" -- tmp->set_next(*system_processes); -- } -- // new head -- *system_processes = tmp; -- // increment -- (*no_of_sys_processes)++; -- // step forward -- _iterator->next_process(); -- } -- return OS_OK; --} -- --int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const { -- return _impl->system_processes(system_procs, no_of_sys_processes); --} -- --SystemProcessInterface::SystemProcessInterface() { -- _impl = NULL; --} -- --bool SystemProcessInterface::initialize() { -- _impl = new SystemProcessInterface::SystemProcesses(); -- return _impl->initialize(); -- --} -- --SystemProcessInterface::~SystemProcessInterface() { -- if (_impl != NULL) { -- delete _impl; -- } --} -- --CPUInformationInterface::CPUInformationInterface() { -- _cpu_info = NULL; --} -- --bool CPUInformationInterface::initialize() { -- _cpu_info = new CPUInformation(); -- VM_Version::initialize_cpu_information(); -- _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads()); -- _cpu_info->set_number_of_cores(VM_Version::number_of_cores()); -- _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets()); -- _cpu_info->set_cpu_name(VM_Version::cpu_name()); -- _cpu_info->set_cpu_description(VM_Version::cpu_description()); -- return true; --} -- --CPUInformationInterface::~CPUInformationInterface() { -- if (_cpu_info != NULL) { -- if (_cpu_info->cpu_name() != NULL) { -- const char* cpu_name = _cpu_info->cpu_name(); -- FREE_C_HEAP_ARRAY(char, cpu_name); -- _cpu_info->set_cpu_name(NULL); -- } -- if (_cpu_info->cpu_description() != NULL) { -- const char* cpu_desc = _cpu_info->cpu_description(); -- FREE_C_HEAP_ARRAY(char, cpu_desc); -- _cpu_info->set_cpu_description(NULL); -- } -- delete _cpu_info; -- } --} -- --int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { -- if (_cpu_info == NULL) { -- return OS_ERR; -- } -- -- cpu_info = *_cpu_info; // shallow copy assignment -- return OS_OK; --} -- --class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { -- friend class NetworkPerformanceInterface; -- private: -- NetworkPerformance(); -- NONCOPYABLE(NetworkPerformance); -- bool initialize(); -- ~NetworkPerformance(); -- int network_utilization(NetworkInterface** network_interfaces) const; --}; -- --NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() { -- --} -- --bool NetworkPerformanceInterface::NetworkPerformance::initialize() { -- return true; --} -- --NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { -- --} -- --int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const --{ -- kstat_ctl_t* ctl = kstat_open(); -- if (ctl == NULL) { -- return OS_ERR; -- } -- -- NetworkInterface* ret = NULL; -- for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) { -- if (strcmp(k->ks_class, "net") != 0) { -- continue; -- } -- if (strcmp(k->ks_module, "link") != 0) { -- continue; -- } -- -- if (kstat_read(ctl, k, NULL) == -1) { -- return OS_ERR; -- } -- -- uint64_t bytes_in = UINT64_MAX; -- uint64_t bytes_out = UINT64_MAX; -- for (unsigned int i = 0; i < k->ks_ndata; ++i) { -- kstat_named_t* data = &reinterpret_cast(k->ks_data)[i]; -- if (strcmp(data->name, "rbytes64") == 0) { -- bytes_in = data->value.ui64; -- } -- else if (strcmp(data->name, "obytes64") == 0) { -- bytes_out = data->value.ui64; -- } -- } -- -- if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) { -- NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret); -- ret = cur; -- } -- } -- -- kstat_close(ctl); -- *network_interfaces = ret; -- -- return OS_OK; --} -- --NetworkPerformanceInterface::NetworkPerformanceInterface() { -- _impl = NULL; --} -- --NetworkPerformanceInterface::~NetworkPerformanceInterface() { -- if (_impl != NULL) { -- delete _impl; -- } --} -- --bool NetworkPerformanceInterface::initialize() { -- _impl = new NetworkPerformanceInterface::NetworkPerformance(); -- return _impl->initialize(); --} -- --int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const { -- return _impl->network_utilization(network_interfaces); --} ---- old/src/hotspot/os/solaris/os_solaris.cpp 2020-05-20 18:09:34.749109332 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,3073 +0,0 @@ --/* -- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. 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. -- * -- */ -- --// no precompiled headers --#include "jvm.h" --#include "classfile/classLoader.hpp" --#include "classfile/systemDictionary.hpp" --#include "classfile/vmSymbols.hpp" --#include "code/icBuffer.hpp" --#include "code/vtableStubs.hpp" --#include "compiler/compileBroker.hpp" --#include "compiler/disassembler.hpp" --#include "interpreter/interpreter.hpp" --#include "jvmtifiles/jvmti.h" --#include "logging/log.hpp" --#include "logging/logStream.hpp" --#include "memory/allocation.inline.hpp" --#include "memory/universe.hpp" --#include "oops/oop.inline.hpp" --#include "os_solaris.inline.hpp" --#include "prims/jniFastGetField.hpp" --#include "prims/jvm_misc.hpp" --#include "runtime/arguments.hpp" --#include "runtime/atomic.hpp" --#include "runtime/globals.hpp" --#include "runtime/globals_extension.hpp" --#include "runtime/interfaceSupport.inline.hpp" --#include "runtime/java.hpp" --#include "runtime/javaCalls.hpp" --#include "runtime/javaThread.hpp" --#include "runtime/mutexLocker.hpp" --#include "runtime/objectMonitor.hpp" --#include "runtime/osInfo.hpp" --#include "runtime/orderAccess.hpp" --#include "runtime/osThread.hpp" --#include "runtime/park.hpp" --#include "runtime/perfMemory.hpp" --#include "runtime/sharedRuntime.hpp" --#include "runtime/statSampler.hpp" --#include "runtime/stubRoutines.hpp" --#include "runtime/threadCritical.hpp" --#include "runtime/threads.hpp" --#include "runtime/timer.hpp" --#include "runtime/vm_version.hpp" --#include "semaphore_posix.hpp" --#include "services/attachListener.hpp" --#include "services/memTracker.hpp" --#include "services/runtimeService.hpp" --#include "signals_posix.hpp" --#include "utilities/align.hpp" --#include "utilities/decoder.hpp" --#include "utilities/defaultStream.hpp" --#include "utilities/events.hpp" --#include "utilities/growableArray.hpp" --#include "utilities/macros.hpp" --#include "utilities/vmError.hpp" -- --// put OS-includes here --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include // for elf Sym structure used by dladdr1 --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include -- --# include -- --#define MAX_PATH (2 * K) -- --// for timer info max values which include all bits --#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) -- --// Here are some liblgrp types from sys/lgrp_user.h to be able to --// compile on older systems without this header file. -- --#ifndef MADV_ACCESS_LWP -- #define MADV_ACCESS_LWP 7 /* next LWP to access heavily */ --#endif --#ifndef MADV_ACCESS_MANY -- #define MADV_ACCESS_MANY 8 /* many processes to access heavily */ --#endif -- --#ifndef LGRP_RSRC_CPU -- #define LGRP_RSRC_CPU 0 /* CPU resources */ --#endif --#ifndef LGRP_RSRC_MEM -- #define LGRP_RSRC_MEM 1 /* memory resources */ --#endif -- --// guarded in sys/mman.h --extern "C" { --extern int getpagesizes(size_t[], int); --} -- --// Values for ThreadPriorityPolicy == 1 --int prio_policy1[CriticalPriority+1] = { -- -99999, 0, 16, 32, 48, 64, -- 80, 96, 112, 124, 127, 127 }; -- --// System parameters used internally --static clock_t clock_tics_per_sec = 100; -- --// For diagnostics to print a message once. see run_periodic_checks --static bool check_addr0_done = false; -- --address os::Solaris::handler_start; // start pc of thr_sighndlrinfo --address os::Solaris::handler_end; // end pc of thr_sighndlrinfo -- --address os::Solaris::_main_stack_base = NULL; // 4352906 workaround -- --os::Solaris::pthread_setname_np_func_t os::Solaris::_pthread_setname_np = NULL; -- --// "default" initializers for missing libc APIs --extern "C" { -- int memcntl(void *, size_t, int, void *, int, int); -- int meminfo(const uint64_t *, int, const uint_t *, int, uint64_t *, uint_t *); --} -- --static inline size_t adjust_stack_size(address base, size_t size) { -- if ((ssize_t)size < 0) { -- // 4759953: Compensate for ridiculous stack size. -- size = max_intx; -- } -- if (size > (size_t)base) { -- // 4812466: Make sure size doesn't allow the stack to wrap the address space. -- size = (size_t)base; -- } -- return size; --} -- --static inline stack_t get_stack_info() { -- stack_t st; -- int retval = thr_stksegment(&st); -- st.ss_size = adjust_stack_size((address)st.ss_sp, st.ss_size); -- assert(retval == 0, "incorrect return value from thr_stksegment"); -- assert((address)&st < (address)st.ss_sp, "Invalid stack base returned"); -- assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned"); -- return st; --} -- --bool os::is_primordial_thread(void) { -- int r = thr_main(); -- guarantee(r == 0 || r == 1, "CR6501650 or CR6493689"); -- return r == 1; --} -- --address os::current_stack_base() { -- bool _is_primordial_thread = is_primordial_thread(); -- -- // Workaround 4352906, avoid calls to thr_stksegment by -- // thr_main after the first one (it looks like we trash -- // some data, causing the value for ss_sp to be incorrect). -- if (!_is_primordial_thread || os::Solaris::_main_stack_base == NULL) { -- stack_t st = get_stack_info(); -- if (_is_primordial_thread) { -- // cache initial value of stack base -- os::Solaris::_main_stack_base = (address)st.ss_sp; -- } -- return (address)st.ss_sp; -- } else { -- guarantee(os::Solaris::_main_stack_base != NULL, "Attempt to use null cached stack base"); -- return os::Solaris::_main_stack_base; -- } --} -- --size_t os::current_stack_size() { -- size_t size; -- -- if (!is_primordial_thread()) { -- size = get_stack_info().ss_size; -- } else { -- struct rlimit limits; -- getrlimit(RLIMIT_STACK, &limits); -- size = adjust_stack_size(os::Solaris::_main_stack_base, (size_t)limits.rlim_cur); -- } -- // base may not be page aligned -- address base = current_stack_base(); -- address bottom = align_up(base - size, os::vm_page_size());; -- return (size_t)(base - bottom); --} -- --jint os::Solaris::_os_thread_limit = 0; --volatile jint os::Solaris::_os_thread_count = 0; -- --julong os::available_memory() { -- return Solaris::available_memory(); --} -- --julong os::free_memory() { -- return Solaris::available_memory(); --} -- --julong os::Solaris::available_memory() { -- return (julong)sysconf(_SC_AVPHYS_PAGES) * os::vm_page_size(); --} -- --julong os::Solaris::_physical_memory = 0; -- --julong os::physical_memory() { -- return Solaris::physical_memory(); --} -- --static hrtime_t first_hrtime = 0; --static const hrtime_t hrtime_hz = 1000*1000*1000; --static volatile hrtime_t max_hrtime = 0; -- -- --void os::Solaris::initialize_system_info() { -- set_processor_count(sysconf(_SC_NPROCESSORS_CONF)); -- _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * -- (julong)sysconf(_SC_PAGESIZE); --} -- --uint os::processor_id() { -- const processorid_t id = ::getcpuid(); -- assert(id >= 0 && id < _processor_count, "Invalid processor id"); -- return (uint)id; --} -- --int os::active_processor_count() { -- // User has overridden the number of active processors -- if (ActiveProcessorCount > 0) { -- log_trace(os)("active_processor_count: " -- "active processor count set by user : %d", -- ActiveProcessorCount); -- return ActiveProcessorCount; -- } -- -- int online_cpus = sysconf(_SC_NPROCESSORS_ONLN); -- pid_t pid = getpid(); -- psetid_t pset = PS_NONE; -- // Are we running in a processor set or is there any processor set around? -- if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) { -- uint_t pset_cpus; -- // Query the number of cpus available to us. -- if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) { -- assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check"); -- return pset_cpus; -- } -- } -- // Otherwise return number of online cpus -- return online_cpus; --} -- --void os::set_native_thread_name(const char *name) { -- if (Solaris::_pthread_setname_np != NULL) { -- // Only the first 31 bytes of 'name' are processed by pthread_setname_np -- // but we explicitly copy into a size-limited buffer to avoid any -- // possible overflow. -- char buf[32]; -- snprintf(buf, sizeof(buf), "%s", name); -- buf[sizeof(buf) - 1] = '\0'; -- Solaris::_pthread_setname_np(pthread_self(), buf); -- } --} -- --void os::init_system_properties_values() { -- // The next steps are taken in the product version: -- // -- // Obtain the JAVA_HOME value from the location of libjvm.so. -- // This library should be located at: -- // /jre/lib//{client|server}/libjvm.so. -- // -- // If "/jre/lib/" appears at the right place in the path, then we -- // assume libjvm.so is installed in a JDK and we use this path. -- // -- // Otherwise exit with message: "Could not create the Java virtual machine." -- // -- // The following extra steps are taken in the debugging version: -- // -- // If "/jre/lib/" does NOT appear at the right place in the path -- // instead of exit check for $JAVA_HOME environment variable. -- // -- // If it is defined and we are able to locate $JAVA_HOME/jre/lib/, -- // then we append a fake suffix "hotspot/libjvm.so" to this path so -- // it looks like libjvm.so is installed there -- // /jre/lib//hotspot/libjvm.so. -- // -- // Otherwise exit. -- // -- // Important note: if the location of libjvm.so changes this -- // code needs to be changed accordingly. -- --// Base path of extensions installed on the system. --#define SYS_EXT_DIR "/usr/jdk/packages" --#define EXTENSIONS_DIR "/lib/ext" -- -- // Buffer that fits several sprintfs. -- // Note that the space for the colon and the trailing null are provided -- // by the nulls included by the sizeof operator. -- const size_t bufsize = -- MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. -- sizeof(SYS_EXT_DIR) + sizeof("/lib/"), // invariant ld_library_path -- (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir -- char *buf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); -- -- // sysclasspath, java_home, dll_dir -- { -- char *pslash; -- os::jvm_path(buf, bufsize); -- -- // Found the full path to libjvm.so. -- // Now cut the path to /jre if we can. -- *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. -- pslash = strrchr(buf, '/'); -- if (pslash != NULL) { -- *pslash = '\0'; // Get rid of /{client|server|hotspot}. -- } -- Arguments::set_dll_dir(buf); -- -- if (pslash != NULL) { -- pslash = strrchr(buf, '/'); -- if (pslash != NULL) { -- *pslash = '\0'; // Get rid of /lib. -- } -- } -- Arguments::set_java_home(buf); -- if (!set_boot_path('/', ':')) { -- vm_exit_during_initialization("Failed setting boot class path.", NULL); -- } -- } -- -- // Where to look for native libraries. -- { -- // Use dlinfo() to determine the correct java.library.path. -- // -- // If we're launched by the Java launcher, and the user -- // does not set java.library.path explicitly on the commandline, -- // the Java launcher sets LD_LIBRARY_PATH for us and unsets -- // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case -- // dlinfo returns LD_LIBRARY_PATH + crle settings (including -- // /usr/lib), which is exactly what we want. -- // -- // If the user does set java.library.path, it completely -- // overwrites this setting, and always has. -- // -- // If we're not launched by the Java launcher, we may -- // get here with any/all of the LD_LIBRARY_PATH[_32|64] -- // settings. Again, dlinfo does exactly what we want. -- -- Dl_serinfo info_sz, *info = &info_sz; -- Dl_serpath *path; -- char *library_path; -- char *common_path = buf; -- -- // Determine search path count and required buffer size. -- if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) { -- FREE_C_HEAP_ARRAY(char, buf); -- vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror()); -- } -- -- // Allocate new buffer and initialize. -- info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal); -- info->dls_size = info_sz.dls_size; -- info->dls_cnt = info_sz.dls_cnt; -- -- // Obtain search path information. -- if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) { -- FREE_C_HEAP_ARRAY(char, buf); -- FREE_C_HEAP_ARRAY(char, info); -- vm_exit_during_initialization("dlinfo SERINFO request", dlerror()); -- } -- -- path = &info->dls_serpath[0]; -- -- // Note: Due to a legacy implementation, most of the library path -- // is set in the launcher. This was to accommodate linking restrictions -- // on legacy Solaris implementations (which are no longer supported). -- // Eventually, all the library path setting will be done here. -- // -- // However, to prevent the proliferation of improperly built native -- // libraries, the new path component /usr/jdk/packages is added here. -- -- // Construct the invariant part of ld_library_path. -- sprintf(common_path, SYS_EXT_DIR "/lib"); -- -- // Struct size is more than sufficient for the path components obtained -- // through the dlinfo() call, so only add additional space for the path -- // components explicitly added here. -- size_t library_path_size = info->dls_size + strlen(common_path); -- library_path = NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal); -- library_path[0] = '\0'; -- -- // Construct the desired Java library path from the linker's library -- // search path. -- // -- // For compatibility, it is optimal that we insert the additional path -- // components specific to the Java VM after those components specified -- // in LD_LIBRARY_PATH (if any) but before those added by the ld.so -- // infrastructure. -- if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it. -- strcpy(library_path, common_path); -- } else { -- int inserted = 0; -- uint_t i; -- for (i = 0; i < info->dls_cnt; i++, path++) { -- uint_t flags = path->dls_flags & LA_SER_MASK; -- if (((flags & LA_SER_LIBPATH) == 0) && !inserted) { -- strcat(library_path, common_path); -- strcat(library_path, os::path_separator()); -- inserted = 1; -- } -- strcat(library_path, path->dls_name); -- strcat(library_path, os::path_separator()); -- } -- // Eliminate trailing path separator. -- library_path[strlen(library_path)-1] = '\0'; -- } -- -- // happens before argument parsing - can't use a trace flag -- // tty->print_raw("init_system_properties_values: native lib path: "); -- // tty->print_raw_cr(library_path); -- -- // Callee copies into its own buffer. -- Arguments::set_library_path(library_path); -- -- FREE_C_HEAP_ARRAY(char, library_path); -- FREE_C_HEAP_ARRAY(char, info); -- } -- -- // Extensions directories. -- sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); -- Arguments::set_ext_dirs(buf); -- -- FREE_C_HEAP_ARRAY(char, buf); -- --#undef SYS_EXT_DIR --#undef EXTENSIONS_DIR --} -- --static thread_t main_thread; -- --// Thread start routine for all newly created threads --extern "C" void* thread_native_entry(void* thread_addr) { -- -- Thread* thread = (Thread*)thread_addr; -- -- thread->record_stack_base_and_size(); -- -- // Try to randomize the cache line index of hot stack frames. -- // This helps when threads of the same stack traces evict each other's -- // cache lines. The threads can be either from the same JVM instance, or -- // from different JVM instances. The benefit is especially true for -- // processors with hyperthreading technology. -- static int counter = 0; -- int pid = os::current_process_id(); -- alloca(((pid ^ counter++) & 7) * 128); -- -- int prio; -- -- thread->initialize_thread_current(); -- -- OSThread* osthr = thread->osthread(); -- -- osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound -- -- log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", -- os::current_thread_id()); -- -- if (UseNUMA) { -- int lgrp_id = os::numa_get_group_id(); -- if (lgrp_id != -1) { -- thread->set_lgrp_id(lgrp_id); -- } -- } -- -- // Our priority was set when we were created, and stored in the -- // osthread, but couldn't be passed through to our LWP until now. -- // So read back the priority and set it again. -- -- if (osthr->thread_id() != -1) { -- if (UseThreadPriorities) { -- int prio = osthr->native_priority(); -- os::set_native_priority(thread, prio); -- } -- } -- -- assert(osthr->get_state() == RUNNABLE, "invalid os thread state"); -- -- // initialize signal mask for this thread -- PosixSignals::hotspot_sigmask(thread); -- -- os::Solaris::init_thread_fpu_state(); -- -- thread->call_run(); -- -- // Note: at this point the thread object may already have deleted itself. -- // Do not dereference it from here on out. -- -- // One less thread is executing -- // When the VMThread gets here, the main thread may have already exited -- // which frees the CodeHeap containing the Atomic::dec code -- if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) { -- Atomic::dec(&os::Solaris::_os_thread_count); -- } -- -- log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); -- -- thr_exit(NULL); -- ShouldNotReachHere(); -- -- return NULL; --} -- --static OSThread* create_os_thread(Thread* thread, thread_t thread_id) { -- // Allocate the OSThread object -- OSThread* osthread = new OSThread(); -- if (osthread == NULL) return NULL; -- -- // Store info on the Solaris thread into the OSThread -- osthread->set_thread_id(thread_id); -- osthread->set_lwp_id(_lwp_self()); -- -- if (UseNUMA) { -- int lgrp_id = os::numa_get_group_id(); -- if (lgrp_id != -1) { -- thread->set_lgrp_id(lgrp_id); -- } -- } -- -- // Initial thread state is INITIALIZED, not SUSPENDED -- osthread->set_state(INITIALIZED); -- -- return osthread; --} -- --bool os::create_attached_thread(JavaThread* thread) { --#ifdef ASSERT -- thread->verify_not_published(); --#endif -- OSThread* osthread = create_os_thread(thread, thr_self()); -- if (osthread == NULL) { -- return false; -- } -- -- // Initial thread state is RUNNABLE -- osthread->set_state(RUNNABLE); -- thread->set_osthread(osthread); -- -- if (os::is_primordial_thread()) { -- os::Solaris::correct_stack_boundaries_for_primordial_thread(thread); -- } -- -- // initialize signal mask for this thread -- // and save the caller's signal mask -- PosixSignals::hotspot_sigmask(thread); -- -- log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", -- os::current_thread_id()); -- -- return true; --} -- --bool os::create_main_thread(JavaThread* thread) { --#ifdef ASSERT -- thread->verify_not_published(); --#endif -- if (_starting_thread == NULL) { -- _starting_thread = create_os_thread(thread, main_thread); -- if (_starting_thread == NULL) { -- return false; -- } -- } -- -- // The primodial thread is runnable from the start -- _starting_thread->set_state(RUNNABLE); -- -- thread->set_osthread(_starting_thread); -- -- // initialize signal mask for this thread -- // and save the caller's signal mask -- PosixSignals::hotspot_sigmask(thread); -- -- return true; --} -- --// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() --static char* describe_thr_create_attributes(char* buf, size_t buflen, -- size_t stacksize, long flags) { -- stringStream ss(buf, buflen); -- ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); -- ss.print("flags: "); -- #define PRINT_FLAG(f) if (flags & f) ss.print( #f " "); -- #define ALL(X) \ -- X(THR_SUSPENDED) \ -- X(THR_DETACHED) \ -- X(THR_BOUND) \ -- X(THR_NEW_LWP) \ -- X(THR_DAEMON) -- ALL(PRINT_FLAG) -- #undef ALL -- #undef PRINT_FLAG -- return buf; --} -- --// return default stack size for thr_type --size_t os::Posix::default_stack_size(os::ThreadType thr_type) { -- // default stack size when not specified by caller is 1M (2M for LP64) -- size_t s = (BytesPerWord >> 2) * K * K; -- return s; --} -- --bool os::create_thread(Thread* thread, ThreadType thr_type, -- size_t req_stack_size) { -- // Allocate the OSThread object -- OSThread* osthread = new OSThread(); -- if (osthread == NULL) { -- return false; -- } -- -- // calculate stack size if it's not specified by caller -- size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size); -- -- // Initial state is ALLOCATED but not INITIALIZED -- osthread->set_state(ALLOCATED); -- -- if (os::Solaris::_os_thread_count > os::Solaris::_os_thread_limit) { -- // We got lots of threads. Check if we still have some address space left. -- // Need to be at least 5Mb of unreserved address space. We do check by -- // trying to reserve some. -- const size_t VirtualMemoryBangSize = 20*K*K; -- char* mem = os::reserve_memory(VirtualMemoryBangSize); -- if (mem == NULL) { -- delete osthread; -- return false; -- } else { -- // Release the memory again -- os::release_memory(mem, VirtualMemoryBangSize); -- } -- } -- -- // Setup osthread because the child thread may need it. -- thread->set_osthread(osthread); -- -- // Create the Solaris thread -- thread_t tid = 0; -- long flags = THR_DETACHED | THR_SUSPENDED; -- int status; -- -- // Mark that we don't have an lwp or thread id yet. -- // In case we attempt to set the priority before the thread starts. -- osthread->set_lwp_id(-1); -- osthread->set_thread_id(-1); -- -- status = thr_create(NULL, stack_size, thread_native_entry, thread, flags, &tid); -- -- char buf[64]; -- if (status == 0) { -- log_info(os, thread)("Thread \"%s\" started (tid: " UINTX_FORMAT ", attributes: %s). ", -- thread->name(), (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); -- } else { -- log_warning(os, thread)("Failed to start thread \"%s\" - thr_create failed (%s) for attributes: %s.", -- thread->name(), os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); -- // Log some OS information which might explain why creating the thread failed. -- log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); -- LogStream st(Log(os, thread)::info()); -- os::Posix::print_rlimit_info(&st); -- os::print_memory_info(&st); -- } -- -- if (status != 0) { -- thread->set_osthread(NULL); -- // Need to clean up stuff we've allocated so far -- delete osthread; -- return false; -- } -- -- Atomic::inc(&os::Solaris::_os_thread_count); -- -- // Store info on the Solaris thread into the OSThread -- osthread->set_thread_id(tid); -- -- // Remember that we created this thread so we can set priority on it -- osthread->set_vm_created(); -- -- // Most thread types will set an explicit priority before starting the thread, -- // but for those that don't we need a valid value to read back in thread_native_entry. -- osthread->set_native_priority(NormPriority); -- -- // Initial thread state is INITIALIZED, not SUSPENDED -- osthread->set_state(INITIALIZED); -- -- // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain -- return true; --} -- --// CR 7190089: on Solaris, primordial thread's stack needs adjusting. --// Without the adjustment, stack size is incorrect if stack is set to unlimited (ulimit -s unlimited). --void os::Solaris::correct_stack_boundaries_for_primordial_thread(Thread* thr) { -- assert(is_primordial_thread(), "Call only for primordial thread"); -- -- JavaThread* jt = (JavaThread *)thr; -- assert(jt != NULL, "Sanity check"); -- size_t stack_size; -- address base = jt->stack_base(); -- if (Arguments::created_by_java_launcher()) { -- // Use 2MB to allow for Solaris 7 64 bit mode. -- stack_size = JavaThread::stack_size_at_create() == 0 -- ? 2048*K : JavaThread::stack_size_at_create(); -- -- // There are rare cases when we may have already used more than -- // the basic stack size allotment before this method is invoked. -- // Attempt to allow for a normally sized java_stack. -- size_t current_stack_offset = (size_t)(base - (address)&stack_size); -- stack_size += ReservedSpace::page_align_size_down(current_stack_offset); -- } else { -- // 6269555: If we were not created by a Java launcher, i.e. if we are -- // running embedded in a native application, treat the primordial thread -- // as much like a native attached thread as possible. This means using -- // the current stack size from thr_stksegment(), unless it is too large -- // to reliably setup guard pages. A reasonable max size is 8MB. -- size_t current_size = os::current_stack_size(); -- // This should never happen, but just in case.... -- if (current_size == 0) current_size = 2 * K * K; -- stack_size = current_size > (8 * K * K) ? (8 * K * K) : current_size; -- } -- address bottom = align_up(base - stack_size, os::vm_page_size());; -- stack_size = (size_t)(base - bottom); -- -- assert(stack_size > 0, "Stack size calculation problem"); -- -- if (stack_size > jt->stack_size()) { --#ifndef PRODUCT -- struct rlimit limits; -- getrlimit(RLIMIT_STACK, &limits); -- size_t size = adjust_stack_size(base, (size_t)limits.rlim_cur); -- assert(size >= jt->stack_size(), "Stack size problem in main thread"); --#endif -- tty->print_cr("Stack size of " SIZE_FORMAT " Kb exceeds current limit of " SIZE_FORMAT " Kb.\n" -- "(Stack sizes are rounded up to a multiple of the system page size.)\n" -- "See limit(1) to increase the stack size limit.", -- stack_size / K, jt->stack_size() / K); -- vm_exit(1); -- } -- assert(jt->stack_size() >= stack_size, -- "Attempt to map more stack than was allocated"); -- jt->set_stack_size(stack_size); -- --} -- -- -- --// Free Solaris resources related to the OSThread --void os::free_thread(OSThread* osthread) { -- assert(osthread != NULL, "os::free_thread but osthread not set"); -- -- // We are told to free resources of the argument thread, -- // but we can only really operate on the current thread. -- assert(Thread::current()->osthread() == osthread, -- "os::free_thread but not current thread"); -- -- // Restore caller's signal mask -- sigset_t sigmask = osthread->caller_sigmask(); -- pthread_sigmask(SIG_SETMASK, &sigmask, NULL); -- -- delete osthread; --} -- --void os::pd_start_thread(Thread* thread) { -- int status = thr_continue(thread->osthread()->thread_id()); -- assert_status(status == 0, status, "thr_continue failed"); --} -- -- --intx os::current_thread_id() { -- return (intx)thr_self(); --} -- --static pid_t _initial_pid = 0; -- --int os::current_process_id() { -- return (int)(_initial_pid ? _initial_pid : getpid()); --} -- --// gethrtime() should be monotonic according to the documentation, --// but some virtualized platforms are known to break this guarantee. --// getTimeNanos() must be guaranteed not to move backwards, so we --// are forced to add a check here. --inline hrtime_t getTimeNanos() { -- const hrtime_t now = gethrtime(); -- const hrtime_t prev = max_hrtime; -- if (now <= prev) { -- return prev; // same or retrograde time; -- } -- const hrtime_t obsv = Atomic::cmpxchg(&max_hrtime, prev, now); -- assert(obsv >= prev, "invariant"); // Monotonicity -- // If the CAS succeeded then we're done and return "now". -- // If the CAS failed and the observed value "obsv" is >= now then -- // we should return "obsv". If the CAS failed and now > obsv > prv then -- // some other thread raced this thread and installed a new value, in which case -- // we could either (a) retry the entire operation, (b) retry trying to install now -- // or (c) just return obsv. We use (c). No loop is required although in some cases -- // we might discard a higher "now" value in deference to a slightly lower but freshly -- // installed obsv value. That's entirely benign -- it admits no new orderings compared -- // to (a) or (b) -- and greatly reduces coherence traffic. -- // We might also condition (c) on the magnitude of the delta between obsv and now. -- // Avoiding excessive CAS operations to hot RW locations is critical. -- // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate -- return (prev == obsv) ? now : obsv; --} -- --double os::elapsedVTime() { -- return (double)gethrvtime() / (double)hrtime_hz; --} -- --// DLL functions -- --// This must be hard coded because it's the system's temporary --// directory not the java application's temp directory, ala java.io.tmpdir. --const char* os::get_temp_directory() { return "/tmp"; } -- --// check if addr is inside libjvm.so --bool os::address_is_in_vm(address addr) { -- static address libjvm_base_addr; -- Dl_info dlinfo; -- -- if (libjvm_base_addr == NULL) { -- if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) { -- libjvm_base_addr = (address)dlinfo.dli_fbase; -- } -- assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm"); -- } -- -- if (dladdr((void *)addr, &dlinfo) != 0) { -- if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true; -- } -- -- return false; --} -- --void os::prepare_native_symbols() { --} -- --typedef int (*dladdr1_func_type)(void *, Dl_info *, void **, int); --static dladdr1_func_type dladdr1_func = NULL; -- --bool os::dll_address_to_function_name(address addr, char *buf, -- int buflen, int * offset, -- bool demangle) { -- // buf is not optional, but offset is optional -- assert(buf != NULL, "sanity check"); -- -- Dl_info dlinfo; -- -- // dladdr1_func was initialized in os::init() -- if (dladdr1_func != NULL) { -- // yes, we have dladdr1 -- -- // Support for dladdr1 is checked at runtime; it may be -- // available even if the vm is built on a machine that does -- // not have dladdr1 support. Make sure there is a value for -- // RTLD_DL_SYMENT. --#ifndef RTLD_DL_SYMENT -- #define RTLD_DL_SYMENT 1 --#endif --#ifdef _LP64 -- Elf64_Sym * info; --#else -- Elf32_Sym * info; --#endif -- if (dladdr1_func((void *)addr, &dlinfo, (void **)&info, -- RTLD_DL_SYMENT) != 0) { -- // see if we have a matching symbol that covers our address -- if (dlinfo.dli_saddr != NULL && -- (char *)dlinfo.dli_saddr + info->st_size > (char *)addr) { -- if (dlinfo.dli_sname != NULL) { -- if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) { -- jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); -- } -- if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; -- return true; -- } -- } -- // no matching symbol so try for just file info -- if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) { -- if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), -- buf, buflen, offset, dlinfo.dli_fname, demangle)) { -- return true; -- } -- } -- } -- buf[0] = '\0'; -- if (offset != NULL) *offset = -1; -- return false; -- } -- -- // no, only dladdr is available -- if (dladdr((void *)addr, &dlinfo) != 0) { -- // see if we have a matching symbol -- if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) { -- if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) { -- jio_snprintf(buf, buflen, dlinfo.dli_sname); -- } -- if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; -- return true; -- } -- // no matching symbol so try for just file info -- if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) { -- if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), -- buf, buflen, offset, dlinfo.dli_fname, demangle)) { -- return true; -- } -- } -- } -- buf[0] = '\0'; -- if (offset != NULL) *offset = -1; -- return false; --} -- --bool os::dll_address_to_library_name(address addr, char* buf, -- int buflen, int* offset) { -- // buf is not optional, but offset is optional -- assert(buf != NULL, "sanity check"); -- -- Dl_info dlinfo; -- -- if (dladdr((void*)addr, &dlinfo) != 0) { -- if (dlinfo.dli_fname != NULL) { -- jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname); -- } -- if (dlinfo.dli_fbase != NULL && offset != NULL) { -- *offset = addr - (address)dlinfo.dli_fbase; -- } -- return true; -- } -- -- buf[0] = '\0'; -- if (offset) *offset = -1; -- return false; --} -- --int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { -- Dl_info dli; -- // Sanity check? -- if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 || -- dli.dli_fname == NULL) { -- return 1; -- } -- -- void * handle = dlopen(dli.dli_fname, RTLD_LAZY); -- if (handle == NULL) { -- return 1; -- } -- -- Link_map *map; -- dlinfo(handle, RTLD_DI_LINKMAP, &map); -- if (map == NULL) { -- dlclose(handle); -- return 1; -- } -- -- while (map->l_prev != NULL) { -- map = map->l_prev; -- } -- -- while (map != NULL) { -- // Iterate through all map entries and call callback with fields of interest -- if(callback(map->l_name, (address)map->l_addr, (address)0, param)) { -- dlclose(handle); -- return 1; -- } -- map = map->l_next; -- } -- -- dlclose(handle); -- return 0; --} -- --int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { -- outputStream * out = (outputStream *) param; -- out->print_cr(INTPTR_FORMAT " \t%s", (intptr_t)base_address, name); -- return 0; --} -- --void os::print_dll_info(outputStream * st) { -- st->print_cr("Dynamic libraries:"); st->flush(); -- if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) { -- st->print_cr("Error: Cannot print dynamic libraries."); -- } --} -- --static void change_endianness(Elf32_Half& val) { -- unsigned char *ptr = (unsigned char *)&val; -- unsigned char swp = ptr[0]; -- ptr[0] = ptr[1]; -- ptr[1] = swp; --} -- --// Loads .dll/.so and --// in case of error it checks if .dll/.so was built for the --// same architecture as Hotspot is running on -- --void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { -- log_info(os)("attempting shared library load of %s", filename); -- -- void * result= ::dlopen(filename, RTLD_LAZY); -- if (result != NULL) { -- // Successful loading -- Events::log(NULL, "Loaded shared library %s", filename); -- log_info(os)("shared library load of %s was successful", filename); -- return result; -- } -- -- Elf32_Ehdr elf_head; -- const char* error_report = ::dlerror(); -- if (error_report == NULL) { -- error_report = "dlerror returned no error description"; -- } -- if (ebuf != NULL && ebuflen > 0) { -- ::strncpy(ebuf, error_report, ebuflen-1); -- ebuf[ebuflen-1]='\0'; -- } -- -- Events::log(NULL, "Loading shared library %s failed, %s", filename, error_report); -- log_info(os)("shared library load of %s failed, %s", filename, error_report); -- -- int diag_msg_max_length=ebuflen-strlen(ebuf); -- char* diag_msg_buf=ebuf+strlen(ebuf); -- -- if (diag_msg_max_length==0) { -- // No more space in ebuf for additional diagnostics message -- return NULL; -- } -- -- -- int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK); -- -- if (file_descriptor < 0) { -- // Can't open library, report dlerror() message -- return NULL; -- } -- -- bool failed_to_read_elf_head= -- (sizeof(elf_head)!= -- (::read(file_descriptor, &elf_head,sizeof(elf_head)))); -- -- ::close(file_descriptor); -- if (failed_to_read_elf_head) { -- // file i/o error - report dlerror() msg -- return NULL; -- } -- -- if (elf_head.e_ident[EI_DATA] != LITTLE_ENDIAN_ONLY(ELFDATA2LSB) BIG_ENDIAN_ONLY(ELFDATA2MSB)) { -- // handle invalid/out of range endianness values -- if (elf_head.e_ident[EI_DATA] == 0 || elf_head.e_ident[EI_DATA] > 2) { -- return NULL; -- } -- change_endianness(elf_head.e_machine); -- } -- -- typedef struct { -- Elf32_Half code; // Actual value as defined in elf.h -- Elf32_Half compat_class; // Compatibility of archs at VM's sense -- unsigned char elf_class; // 32 or 64 bit -- unsigned char endianess; // MSB or LSB -- char* name; // String representation -- } arch_t; -- -- static const arch_t arch_array[]={ -- {EM_386, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, -- {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, -- {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"}, -- {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"}, -- {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, -- {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, -- {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, -- {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, -- {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, -- {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, -- // we only support 64 bit z architecture -- {EM_S390, EM_S390, ELFCLASS64, ELFDATA2MSB, (char*)"IBM System/390"}, -- {EM_AARCH64, EM_AARCH64, ELFCLASS64, ELFDATA2LSB, (char*)"AARCH64"} -- }; -- --#if (defined IA32) -- static Elf32_Half running_arch_code=EM_386; --#elif (defined AMD64) -- static Elf32_Half running_arch_code=EM_X86_64; --#elif (defined IA64) -- static Elf32_Half running_arch_code=EM_IA_64; --#elif (defined __sparc) && (defined _LP64) -- static Elf32_Half running_arch_code=EM_SPARCV9; --#elif (defined __sparc) && (!defined _LP64) -- static Elf32_Half running_arch_code=EM_SPARC; --#elif (defined __powerpc64__) -- static Elf32_Half running_arch_code=EM_PPC64; --#elif (defined __powerpc__) -- static Elf32_Half running_arch_code=EM_PPC; --#elif (defined ARM) -- static Elf32_Half running_arch_code=EM_ARM; --#else -- #error Method os::dll_load requires that one of following is defined:\ -- IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM --#endif -- -- // Identify compatibility class for VM's architecture and library's architecture -- // Obtain string descriptions for architectures -- -- arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL}; -- int running_arch_index=-1; -- -- for (unsigned int i=0; i < ARRAY_SIZE(arch_array); i++) { -- if (running_arch_code == arch_array[i].code) { -- running_arch_index = i; -- } -- if (lib_arch.code == arch_array[i].code) { -- lib_arch.compat_class = arch_array[i].compat_class; -- lib_arch.name = arch_array[i].name; -- } -- } -- -- assert(running_arch_index != -1, -- "Didn't find running architecture code (running_arch_code) in arch_array"); -- if (running_arch_index == -1) { -- // Even though running architecture detection failed -- // we may still continue with reporting dlerror() message -- return NULL; -- } -- -- if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) { -- if (lib_arch.name != NULL) { -- ::snprintf(diag_msg_buf, diag_msg_max_length-1, -- " (Possible cause: can't load %s .so on a %s platform)", -- lib_arch.name, arch_array[running_arch_index].name); -- } else { -- ::snprintf(diag_msg_buf, diag_msg_max_length-1, -- " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)", -- lib_arch.code, arch_array[running_arch_index].name); -- } -- return NULL; -- } -- -- if (lib_arch.endianess != arch_array[running_arch_index].endianess) { -- ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)"); -- return NULL; -- } -- -- // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit -- if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) { -- ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)"); -- return NULL; -- } -- -- if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) { -- ::snprintf(diag_msg_buf, diag_msg_max_length-1, -- " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)", -- (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32); -- return NULL; -- } -- -- return NULL; --} -- --static inline time_t get_mtime(const char* filename) { -- struct stat st; -- int ret = os::stat(filename, &st); -- assert(ret == 0, "failed to stat() file '%s': %s", filename, os::strerror(errno)); -- return st.st_mtime; --} -- --int os::compare_file_modified_times(const char* file1, const char* file2) { -- time_t t1 = get_mtime(file1); -- time_t t2 = get_mtime(file2); -- return t1 - t2; --} -- --static bool _print_ascii_file(const char* filename, outputStream* st) { -- int fd = ::open(filename, O_RDONLY); -- if (fd == -1) { -- return false; -- } -- -- char buf[32]; -- int bytes; -- while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) { -- st->print_raw(buf, bytes); -- } -- -- ::close(fd); -- -- return true; --} -- --void os::print_os_info_brief(outputStream* st) { -- os::Solaris::print_distro_info(st); -- -- os::Posix::print_uname_info(st); -- -- os::Solaris::print_libversion_info(st); --} -- --void os::print_os_info(outputStream* st) { -- st->print("OS:"); -- -- os::Solaris::print_distro_info(st); -- -- os::Posix::print_uname_info(st); -- -- os::Posix::print_uptime_info(st); -- -- os::Solaris::print_libversion_info(st); -- -- os::Posix::print_rlimit_info(st); -- -- os::Posix::print_load_average(st); --} -- --void os::Solaris::print_distro_info(outputStream* st) { -- if (!_print_ascii_file("/etc/release", st)) { -- st->print("Solaris"); -- } -- st->cr(); --} -- --void os::get_summary_os_info(char* buf, size_t buflen) { -- strncpy(buf, "Solaris", buflen); // default to plain solaris -- FILE* fp = fopen("/etc/release", "r"); -- if (fp != NULL) { -- char tmp[256]; -- // Only get the first line and chop out everything but the os name. -- if (fgets(tmp, sizeof(tmp), fp)) { -- char* ptr = tmp; -- // skip past whitespace characters -- while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++; -- if (*ptr != '\0') { -- char* nl = strchr(ptr, '\n'); -- if (nl != NULL) *nl = '\0'; -- strncpy(buf, ptr, buflen); -- } -- } -- fclose(fp); -- } --} -- --void os::Solaris::print_libversion_info(outputStream* st) { -- st->print(" (T2 libthread)"); -- st->cr(); --} -- --static bool check_addr0(outputStream* st) { -- jboolean status = false; -- const int read_chunk = 200; -- int ret = 0; -- int nmap = 0; -- int fd = ::open("/proc/self/map",O_RDONLY); -- if (fd >= 0) { -- prmap_t *p = NULL; -- char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t)); -- if (NULL == mbuff) { -- ::close(fd); -- return status; -- } -- while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) { -- //check if read() has not read partial data -- if( 0 != ret % sizeof(prmap_t)){ -- break; -- } -- nmap = ret / sizeof(prmap_t); -- p = (prmap_t *)mbuff; -- for(int i = 0; i < nmap; i++){ -- if (p->pr_vaddr == 0x0) { -- st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024); -- st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname); -- st->print("Access: "); -- st->print("%s",(p->pr_mflags & MA_READ) ? "r" : "-"); -- st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-"); -- st->print("%s",(p->pr_mflags & MA_EXEC) ? "x" : "-"); -- st->cr(); -- status = true; -- } -- p++; -- } -- } -- free(mbuff); -- ::close(fd); -- } -- return status; --} -- --void os::get_summary_cpu_info(char* buf, size_t buflen) { -- // Get MHz with system call. We don't seem to already have this. -- processor_info_t stats; -- processorid_t id = getcpuid(); -- int clock = 0; -- if (processor_info(id, &stats) != -1) { -- clock = stats.pi_clock; // pi_processor_type isn't more informative than below -- } -- snprintf(buf, buflen, "64 bit %d MHz", clock); --} -- --void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { -- // Nothing to do for now. --} -- --void os::print_memory_info(outputStream* st) { -- st->print("Memory:"); -- st->print(" %dk page", os::vm_page_size()>>10); -- st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10); -- st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10); -- st->cr(); -- (void) check_addr0(st); --} -- --static int Maxsignum = 0; -- --static char saved_jvm_path[MAXPATHLEN] = { 0 }; -- --// Find the full path to the current module, libjvm.so --void os::jvm_path(char *buf, jint buflen) { -- // Error checking. -- if (buflen < MAXPATHLEN) { -- assert(false, "must use a large-enough buffer"); -- buf[0] = '\0'; -- return; -- } -- // Lazy resolve the path to current module. -- if (saved_jvm_path[0] != 0) { -- strcpy(buf, saved_jvm_path); -- return; -- } -- -- Dl_info dlinfo; -- int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo); -- assert(ret != 0, "cannot locate libjvm"); -- if (ret != 0 && dlinfo.dli_fname != NULL) { -- if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { -- return; -- } -- } else { -- buf[0] = '\0'; -- return; -- } -- -- if (Arguments::sun_java_launcher_is_altjvm()) { -- // Support for the java launcher's '-XXaltjvm=' option. Typical -- // value for buf is "/jre/lib///libjvm.so". -- // If "/jre/lib/" appears at the right place in the string, then -- // assume we are installed in a JDK and we're done. Otherwise, check -- // for a JAVA_HOME environment variable and fix up the path so it -- // looks like libjvm.so is installed there (append a fake suffix -- // hotspot/libjvm.so). -- const char *p = buf + strlen(buf) - 1; -- for (int count = 0; p > buf && count < 5; ++count) { -- for (--p; p > buf && *p != '/'; --p) -- /* empty */ ; -- } -- -- if (strncmp(p, "/jre/lib/", 9) != 0) { -- // Look for JAVA_HOME in the environment. -- char* java_home_var = ::getenv("JAVA_HOME"); -- if (java_home_var != NULL && java_home_var[0] != 0) { -- char* jrelib_p; -- int len; -- -- // Check the current module name "libjvm.so". -- p = strrchr(buf, '/'); -- assert(strstr(p, "/libjvm") == p, "invalid library name"); -- -- if (os::Posix::realpath(java_home_var, buf, buflen) == NULL) { -- return; -- } -- // determine if this is a legacy image or modules image -- // modules image doesn't have "jre" subdirectory -- len = strlen(buf); -- assert(len < buflen, "Ran out of buffer space"); -- jrelib_p = buf + len; -- snprintf(jrelib_p, buflen-len, "/jre/lib"); -- if (0 != access(buf, F_OK)) { -- snprintf(jrelib_p, buflen-len, "/lib"); -- } -- -- if (0 == access(buf, F_OK)) { -- // Use current module name "libjvm.so" -- len = strlen(buf); -- snprintf(buf + len, buflen-len, "/hotspot/libjvm.so"); -- } else { -- // Go back to path of .so -- if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { -- return; -- } -- } -- } -- } -- } -- -- strncpy(saved_jvm_path, buf, MAXPATHLEN); -- saved_jvm_path[MAXPATHLEN - 1] = '\0'; --} -- --//////////////////////////////////////////////////////////////////////////////// --// Virtual Memory -- --static bool recoverable_mmap_error(int err) { -- // See if the error is one we can let the caller handle. This -- // list of errno values comes from the Solaris mmap(2) man page. -- switch (err) { -- case EBADF: -- case EINVAL: -- case ENOTSUP: -- // let the caller deal with these errors -- return true; -- -- default: -- // Any remaining errors on this OS can cause our reserved mapping -- // to be lost. That can cause confusion where different data -- // structures think they have the same memory mapped. The worst -- // scenario is if both the VM and a library think they have the -- // same memory mapped. -- return false; -- } --} -- --static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec, -- int err) { -- warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT -- ", %d) failed; error='%s' (errno=%d)", p2i(addr), bytes, exec, -- os::strerror(err), err); --} -- --static void warn_fail_commit_memory(char* addr, size_t bytes, -- size_t alignment_hint, bool exec, -- int err) { -- warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT -- ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr), -- bytes, alignment_hint, exec, os::strerror(err), err); --} -- --int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) { -- int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; -- size_t size = bytes; -- char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot); -- if (res != NULL) { -- if (UseNUMAInterleaving) { -- numa_make_global(addr, bytes); -- } -- return 0; -- } -- -- int err = errno; // save errno from mmap() call in mmap_chunk() -- -- if (!recoverable_mmap_error(err)) { -- warn_fail_commit_memory(addr, bytes, exec, err); -- vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "committing reserved memory."); -- } -- -- return err; --} -- --bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { -- return Solaris::commit_memory_impl(addr, bytes, exec) == 0; --} -- --void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec, -- const char* mesg) { -- assert(mesg != NULL, "mesg must be specified"); -- int err = os::Solaris::commit_memory_impl(addr, bytes, exec); -- if (err != 0) { -- // the caller wants all commit errors to exit with the specified mesg: -- warn_fail_commit_memory(addr, bytes, exec, err); -- vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); -- } --} -- --size_t os::Solaris::page_size_for_alignment(size_t alignment) { -- assert(is_aligned(alignment, (size_t) os::vm_page_size()), -- SIZE_FORMAT " is not aligned to " SIZE_FORMAT, -- alignment, (size_t) os::vm_page_size()); -- -- int page_sizes_max = 9; -- size_t _illumos_page_sizes[page_sizes_max]; -- int n = getpagesizes(_illumos_page_sizes, page_sizes_max); -- for (int i = 0; _illumos_page_sizes[i] != 0; i++) { -- if (is_aligned(alignment, _illumos_page_sizes[i])) { -- return _illumos_page_sizes[i]; -- } -- } -- -- return (size_t) os::vm_page_size(); --} -- --int os::Solaris::commit_memory_impl(char* addr, size_t bytes, -- size_t alignment_hint, bool exec) { -- int err = Solaris::commit_memory_impl(addr, bytes, exec); -- if (err == 0 && UseLargePages && alignment_hint > 0) { -- assert(is_aligned(bytes, alignment_hint), -- SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint); -- -- // The syscall memcntl requires an exact page size (see man memcntl for details). -- size_t page_size = page_size_for_alignment(alignment_hint); -- if (page_size > (size_t) os::vm_page_size()) { -- (void)Solaris::setup_large_pages(addr, bytes, page_size); -- } -- } -- return err; --} -- --bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint, -- bool exec) { -- return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0; --} -- --void os::pd_commit_memory_or_exit(char* addr, size_t bytes, -- size_t alignment_hint, bool exec, -- const char* mesg) { -- assert(mesg != NULL, "mesg must be specified"); -- int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec); -- if (err != 0) { -- // the caller wants all commit errors to exit with the specified mesg: -- warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err); -- vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); -- } --} -- --// Uncommit the pages in a specified region. --void os::pd_free_memory(char* addr, size_t bytes, size_t alignment_hint) { -- if (posix_madvise(addr, bytes, MADV_FREE) < 0) { -- debug_only(warning("MADV_FREE failed.")); -- return; -- } --} -- --bool os::pd_create_stack_guard_pages(char* addr, size_t size) { -- return os::commit_memory(addr, size, !ExecMem); --} -- --bool os::remove_stack_guard_pages(char* addr, size_t size) { -- return os::uncommit_memory(addr, size); --} -- --// Change the page size in a given range. --void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { -- assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned."); -- assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned."); -- if (UseLargePages) { -- size_t page_size = Solaris::page_size_for_alignment(alignment_hint); -- if (page_size > (size_t) os::vm_page_size()) { -- Solaris::setup_large_pages(addr, bytes, page_size); -- } -- } --} -- --// Tell the OS to make the range local to the first-touching LWP --void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { -- assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned."); -- if (posix_madvise(addr, bytes, MADV_ACCESS_LWP) < 0) { -- debug_only(warning("MADV_ACCESS_LWP failed.")); -- } --} -- --// Tell the OS that this range would be accessed from different LWPs. --void os::numa_make_global(char *addr, size_t bytes) { -- assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned."); -- if (posix_madvise(addr, bytes, MADV_ACCESS_MANY) < 0) { -- debug_only(warning("MADV_ACCESS_MANY failed.")); -- } --} -- --// Get the number of the locality groups. --size_t os::numa_get_groups_num() { -- size_t n = Solaris::lgrp_nlgrps(Solaris::lgrp_cookie()); -- return n != -1 ? n : 1; --} -- --// Get a list of leaf locality groups. A leaf lgroup is group that --// doesn't have any children. Typical leaf group is a CPU or a CPU/memory --// board. An LWP is assigned to one of these groups upon creation. --size_t os::numa_get_leaf_groups(int *ids, size_t size) { -- if ((ids[0] = Solaris::lgrp_root(Solaris::lgrp_cookie())) == -1) { -- ids[0] = 0; -- return 1; -- } -- int result_size = 0, top = 1, bottom = 0, cur = 0; -- for (unsigned int k = 0; k < size; k++) { -- int r = Solaris::lgrp_children(Solaris::lgrp_cookie(), ids[cur], -- (Solaris::lgrp_id_t*)&ids[top], size - top); -- if (r == -1) { -- ids[0] = 0; -- return 1; -- } -- if (!r) { -- // That's a leaf node. -- assert(bottom <= cur, "Sanity check"); -- // Check if the node has memory -- if (Solaris::lgrp_resources(Solaris::lgrp_cookie(), ids[cur], -- NULL, 0, LGRP_RSRC_MEM) > 0) { -- ids[bottom++] = ids[cur]; -- } -- } -- top += r; -- cur++; -- } -- if (bottom == 0) { -- // Handle a situation, when the OS reports no memory available. -- // Assume UMA architecture. -- ids[0] = 0; -- return 1; -- } -- return bottom; --} -- --// Detect the topology change. Typically happens during CPU plugging-unplugging. --bool os::numa_topology_changed() { -- int is_stale = Solaris::lgrp_cookie_stale(Solaris::lgrp_cookie()); -- if (is_stale != -1 && is_stale) { -- Solaris::lgrp_fini(Solaris::lgrp_cookie()); -- Solaris::lgrp_cookie_t c = Solaris::lgrp_init(Solaris::LGRP_VIEW_CALLER); -- assert(c != 0, "Failure to initialize LGRP API"); -- Solaris::set_lgrp_cookie(c); -- return true; -- } -- return false; --} -- --// Get the group id of the current LWP. --int os::numa_get_group_id() { -- int lgrp_id = Solaris::lgrp_home(P_LWPID, P_MYID); -- if (lgrp_id == -1) { -- return 0; -- } -- const int size = os::numa_get_groups_num(); -- int *ids = (int*)alloca(size * sizeof(int)); -- -- // Get the ids of all lgroups with memory; r is the count. -- int r = Solaris::lgrp_resources(Solaris::lgrp_cookie(), lgrp_id, -- (Solaris::lgrp_id_t*)ids, size, LGRP_RSRC_MEM); -- if (r <= 0) { -- return 0; -- } -- return ids[os::random() % r]; --} -- --int os::numa_get_group_id_for_address(const void* address) { -- return 0; --} -- --bool os::numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count) { -- return false; --} -- --// Scan the pages from start to end until a page different than --// the one described in the info parameter is encountered. --char *os::scan_pages(char *start, char* end, page_info* page_expected, -- page_info* page_found) { -- const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; -- const size_t types = sizeof(info_types) / sizeof(info_types[0]); -- uint64_t addrs[MAX_MEMINFO_CNT], outdata[types * MAX_MEMINFO_CNT + 1]; -- uint_t validity[MAX_MEMINFO_CNT]; -- -- size_t page_size = MAX2((size_t)os::vm_page_size(), page_expected->size); -- uint64_t p = (uint64_t)start; -- while (p < (uint64_t)end) { -- addrs[0] = p; -- size_t addrs_count = 1; -- while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) { -- addrs[addrs_count] = addrs[addrs_count - 1] + page_size; -- addrs_count++; -- } -- -- if (meminfo(addrs, addrs_count, info_types, types, outdata, validity) < 0) { -- return NULL; -- } -- -- size_t i = 0; -- for (; i < addrs_count; i++) { -- if ((validity[i] & 1) != 0) { -- if ((validity[i] & 4) != 0) { -- if (outdata[types * i + 1] != page_expected->size) { -- break; -- } -- } else if (page_expected->size != 0) { -- break; -- } -- -- if ((validity[i] & 2) != 0 && page_expected->lgrp_id > 0) { -- if (outdata[types * i] != page_expected->lgrp_id) { -- break; -- } -- } -- } else { -- return NULL; -- } -- } -- -- if (i < addrs_count) { -- if ((validity[i] & 2) != 0) { -- page_found->lgrp_id = outdata[types * i]; -- } else { -- page_found->lgrp_id = -1; -- } -- if ((validity[i] & 4) != 0) { -- page_found->size = outdata[types * i + 1]; -- } else { -- page_found->size = 0; -- } -- return (char*)addrs[i]; -- } -- -- p = addrs[addrs_count - 1] + page_size; -- } -- return end; --} -- --bool os::pd_uncommit_memory(char* addr, size_t bytes, bool exec) { -- size_t size = bytes; -- // Map uncommitted pages PROT_NONE so we fail early if we touch an -- // uncommitted page. Otherwise, the read/write might succeed if we -- // have enough swap space to back the physical page. -- return -- NULL != Solaris::mmap_chunk(addr, size, -- MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE, -- PROT_NONE); --} -- --char* os::Solaris::mmap_chunk(char *addr, size_t size, int flags, int prot) { -- char *b = (char *)mmap(addr, size, prot, flags, os::Solaris::_dev_zero_fd, 0); -- -- if (b == MAP_FAILED) { -- return NULL; -- } -- return b; --} -- --char* os::Solaris::anon_mmap(char* requested_addr, size_t bytes) { -- char* addr = requested_addr; -- int flags = MAP_PRIVATE | MAP_NORESERVE; -- -- // Map uncommitted pages PROT_NONE so we fail early if we touch an -- // uncommitted page. Otherwise, the read/write might succeed if we -- // have enough swap space to back the physical page. -- return mmap_chunk(addr, bytes, flags, PROT_NONE); --} -- --char* os::pd_reserve_memory(size_t bytes, bool exec) { -- char* addr = Solaris::anon_mmap(NULL, bytes); -- -- return addr; --} -- --char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) { -- assert(file_desc >= 0, "file_desc is not valid"); -- char* result = pd_attempt_reserve_memory_at(requested_addr, bytes, !ExecMem); -- if (result != NULL) { -- if (replace_existing_mapping_with_file_mapping(result, bytes, file_desc) == NULL) { -- vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory")); -- } -- } -- return result; --} -- --// Reserve memory at an arbitrary address, only if that area is --// available (and not reserved for something else). -- --char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool exec) { -- // Assert only that the size is a multiple of the page size, since -- // that's all that mmap requires, and since that's all we really know -- // about at this low abstraction level. If we need higher alignment, -- // we can either pass an alignment to this method or verify alignment -- // in one of the methods further up the call chain. See bug 5044738. -- assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block"); -- -- // Since snv_84, Solaris attempts to honor the address hint - see 5003415. -- char* addr = Solaris::anon_mmap(requested_addr, bytes); -- -- volatile int err = errno; -- if (addr == requested_addr) { -- return addr; -- } -- -- if (addr != NULL) { -- pd_unmap_memory(addr, bytes); -- } -- -- return NULL; --} -- --bool os::pd_release_memory(char* addr, size_t bytes) { -- size_t size = bytes; -- return munmap(addr, size) == 0; --} -- --static bool solaris_mprotect(char* addr, size_t bytes, int prot) { -- assert(addr == (char*)align_down((uintptr_t)addr, os::vm_page_size()), -- "addr must be page aligned"); -- Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+bytes), prot); -- int retVal = mprotect(addr, bytes, prot); -- return retVal == 0; --} -- --// Protect memory (Used to pass readonly pages through --// JNI GetArrayElements with empty arrays.) --// Also, used for serialization page and for compressed oops null pointer --// checking. --bool os::protect_memory(char* addr, size_t bytes, ProtType prot, -- bool is_committed) { -- unsigned int p = 0; -- switch (prot) { -- case MEM_PROT_NONE: p = PROT_NONE; break; -- case MEM_PROT_READ: p = PROT_READ; break; -- case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break; -- case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break; -- default: -- ShouldNotReachHere(); -- } -- // is_committed is unused. -- return solaris_mprotect(addr, bytes, p); --} -- --// guard_memory and unguard_memory only happens within stack guard pages. --// Since ISM pertains only to the heap, guard and unguard memory should not --/// happen with an ISM region. --bool os::guard_memory(char* addr, size_t bytes) { -- return solaris_mprotect(addr, bytes, PROT_NONE); --} -- --bool os::unguard_memory(char* addr, size_t bytes) { -- return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE); --} -- --// Large page support --static size_t _large_page_size = 0; -- --bool os::Solaris::mpss_sanity_check(bool warn, size_t* page_size) { -- // Find the page sizes supported by the system -- int page_sizes_max = 9; -- size_t _illumos_page_sizes[page_sizes_max]; -- int n = getpagesizes(_illumos_page_sizes, page_sizes_max); -- assert(n > 0, "illumos bug?"); -- -- if (n == 1) return false; // Only one page size available. -- -- // Skip sizes larger than 4M (or LargePageSizeInBytes if it was set) -- const size_t size_limit = -- FLAG_IS_DEFAULT(LargePageSizeInBytes) ? 4 * M : LargePageSizeInBytes; -- int beg; -- for (beg = 0; beg < n; ++beg) { -- if (_illumos_page_sizes[beg] <= size_limit) { -- _page_sizes.add(_illumos_page_sizes[beg]); -- if (_illumos_page_sizes[beg] > *page_size) { -- *page_size = _illumos_page_sizes[beg]; -- } -- } -- } -- // make sure we add the default -- _page_sizes.add(os::vm_page_size()); -- return true; --} -- --void os::large_page_init() { -- if (UseLargePages) { -- // print a warning if any large page related flag is specified on command line -- bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) || -- !FLAG_IS_DEFAULT(LargePageSizeInBytes); -- -- UseLargePages = Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size); -- } --} -- --bool os::Solaris::is_valid_page_size(size_t bytes) { -- return _page_sizes.contains(bytes); --} -- --bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { -- assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align); -- assert(is_aligned((void*) start, align), -- PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align); -- assert(is_aligned(bytes, align), -- SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align); -- -- // Signal to OS that we want large pages for addresses -- // from addr, addr + bytes -- struct memcntl_mha mpss_struct; -- mpss_struct.mha_cmd = MHA_MAPSIZE_VA; -- mpss_struct.mha_pagesize = align; -- mpss_struct.mha_flags = 0; -- // Upon successful completion, memcntl() returns 0 -- if (memcntl(start, bytes, MC_HAT_ADVISE, (caddr_t) &mpss_struct, 0, 0)) { -- debug_only(warning("Attempt to use MPSS failed.")); -- return false; -- } -- return true; --} -- --char* os::pd_reserve_memory_special(size_t size, size_t alignment, size_t page_size, char* addr, bool exec) { -- fatal("os::reserve_memory_special should not be called on Solaris."); -- return NULL; --} -- --bool os::pd_release_memory_special(char* base, size_t bytes) { -- fatal("os::release_memory_special should not be called on Solaris."); -- return false; --} -- --size_t os::large_page_size() { -- return _large_page_size; --} -- --// MPSS allows application to commit large page memory on demand; with ISM --// the entire memory region must be allocated as shared memory. --bool os::can_commit_large_page_memory() { -- return true; --} -- --bool os::can_execute_large_page_memory() { -- return true; --} -- --// Interface for setting lwp priorities. We are using T2 libthread, --// which forces the use of bound threads, so all of our threads will --// be assigned to real lwp's. Using the thr_setprio function is --// meaningless in this mode so we must adjust the real lwp's priority. --// The routines below implement the getting and setting of lwp priorities. --// --// Note: There are three priority scales used on Solaris. Java priorities --// which range from 1 to 10, libthread "thr_setprio" scale which range --// from 0 to 127, and the current scheduling class of the process we --// are running in. This is typically from -60 to +60. --// The setting of the lwp priorities is done after a call to thr_setprio --// so Java priorities are mapped to libthread priorities and we map from --// the latter to lwp priorities. We don't keep priorities stored in --// Java priorities since some of our worker threads want to set priorities --// higher than all Java threads. --// --// For related information: --// (1) man -s 2 priocntl --// (2) man -s 4 priocntl --// (3) man dispadmin --// = librt.so --// = libthread/common/rtsched.c - thrp_setlwpprio(). --// = ps -cL ... to validate priority. --// = sched_get_priority_min and _max --// pthread_create --// sched_setparam --// pthread_setschedparam --// --// Assumptions: --// + We assume that all threads in the process belong to the same --// scheduling class. IE. an homogenous process. --// + Must be root or in IA group to change change "interactive" attribute. --// Priocntl() will fail silently. The only indication of failure is when --// we read-back the value and notice that it hasn't changed. --// + Interactive threads enter the runq at the head, non-interactive at the tail. --// + For RT, change timeslice as well. Invariant: --// constant "priority integral" --// Konst == TimeSlice * (60-Priority) --// Given a priority, compute appropriate timeslice. --// + Higher numerical values have higher priority. -- --// sched class attributes --typedef struct { -- int schedPolicy; // classID -- int maxPrio; -- int minPrio; --} SchedInfo; -- -- --static SchedInfo tsLimits, iaLimits, rtLimits, fxLimits; -- --#ifdef ASSERT --static int ReadBackValidate = 1; --#endif --static int myClass = 0; --static int myMin = 0; --static int myMax = 0; --static int myCur = 0; --static bool priocntl_enable = false; -- --static const int criticalPrio = FXCriticalPriority; --static int java_MaxPriority_to_os_priority = 0; // Saved mapping -- -- --// lwp_priocntl_init --// --// Try to determine the priority scale for our process. --// --// Return errno or 0 if OK. --// --static int lwp_priocntl_init() { -- int rslt; -- pcinfo_t ClassInfo; -- pcparms_t ParmInfo; -- int i; -- -- if (!UseThreadPriorities) return 0; -- -- // If ThreadPriorityPolicy is 1, switch tables -- if (ThreadPriorityPolicy == 1) { -- for (i = 0; i < CriticalPriority+1; i++) -- os::java_to_os_priority[i] = prio_policy1[i]; -- } -- if (UseCriticalJavaThreadPriority) { -- // MaxPriority always maps to the FX scheduling class and criticalPrio. -- // See set_native_priority() and set_lwp_class_and_priority(). -- // Save original MaxPriority mapping in case attempt to -- // use critical priority fails. -- java_MaxPriority_to_os_priority = os::java_to_os_priority[MaxPriority]; -- // Set negative to distinguish from other priorities -- os::java_to_os_priority[MaxPriority] = -criticalPrio; -- } -- -- // Get IDs for a set of well-known scheduling classes. -- // TODO-FIXME: GETCLINFO returns the current # of classes in the -- // the system. We should have a loop that iterates over the -- // classID values, which are known to be "small" integers. -- -- strcpy(ClassInfo.pc_clname, "TS"); -- ClassInfo.pc_cid = -1; -- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); -- if (rslt < 0) return errno; -- assert(ClassInfo.pc_cid != -1, "cid for TS class is -1"); -- tsLimits.schedPolicy = ClassInfo.pc_cid; -- tsLimits.maxPrio = ((tsinfo_t*)ClassInfo.pc_clinfo)->ts_maxupri; -- tsLimits.minPrio = -tsLimits.maxPrio; -- -- strcpy(ClassInfo.pc_clname, "IA"); -- ClassInfo.pc_cid = -1; -- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); -- if (rslt < 0) return errno; -- assert(ClassInfo.pc_cid != -1, "cid for IA class is -1"); -- iaLimits.schedPolicy = ClassInfo.pc_cid; -- iaLimits.maxPrio = ((iainfo_t*)ClassInfo.pc_clinfo)->ia_maxupri; -- iaLimits.minPrio = -iaLimits.maxPrio; -- -- strcpy(ClassInfo.pc_clname, "RT"); -- ClassInfo.pc_cid = -1; -- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); -- if (rslt < 0) return errno; -- assert(ClassInfo.pc_cid != -1, "cid for RT class is -1"); -- rtLimits.schedPolicy = ClassInfo.pc_cid; -- rtLimits.maxPrio = ((rtinfo_t*)ClassInfo.pc_clinfo)->rt_maxpri; -- rtLimits.minPrio = 0; -- -- strcpy(ClassInfo.pc_clname, "FX"); -- ClassInfo.pc_cid = -1; -- rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); -- if (rslt < 0) return errno; -- assert(ClassInfo.pc_cid != -1, "cid for FX class is -1"); -- fxLimits.schedPolicy = ClassInfo.pc_cid; -- fxLimits.maxPrio = ((fxinfo_t*)ClassInfo.pc_clinfo)->fx_maxupri; -- fxLimits.minPrio = 0; -- -- // Query our "current" scheduling class. -- // This will normally be IA, TS or, rarely, FX or RT. -- memset(&ParmInfo, 0, sizeof(ParmInfo)); -- ParmInfo.pc_cid = PC_CLNULL; -- rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo); -- if (rslt < 0) return errno; -- myClass = ParmInfo.pc_cid; -- -- // We now know our scheduling classId, get specific information -- // about the class. -- ClassInfo.pc_cid = myClass; -- ClassInfo.pc_clname[0] = 0; -- rslt = priocntl((idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo); -- if (rslt < 0) return errno; -- -- memset(&ParmInfo, 0, sizeof(pcparms_t)); -- ParmInfo.pc_cid = PC_CLNULL; -- rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo); -- if (rslt < 0) return errno; -- -- if (ParmInfo.pc_cid == rtLimits.schedPolicy) { -- myMin = rtLimits.minPrio; -- myMax = rtLimits.maxPrio; -- } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) { -- iaparms_t *iaInfo = (iaparms_t*)ParmInfo.pc_clparms; -- myMin = iaLimits.minPrio; -- myMax = iaLimits.maxPrio; -- myMax = MIN2(myMax, (int)iaInfo->ia_uprilim); // clamp - restrict -- } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) { -- tsparms_t *tsInfo = (tsparms_t*)ParmInfo.pc_clparms; -- myMin = tsLimits.minPrio; -- myMax = tsLimits.maxPrio; -- myMax = MIN2(myMax, (int)tsInfo->ts_uprilim); // clamp - restrict -- } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) { -- fxparms_t *fxInfo = (fxparms_t*)ParmInfo.pc_clparms; -- myMin = fxLimits.minPrio; -- myMax = fxLimits.maxPrio; -- myMax = MIN2(myMax, (int)fxInfo->fx_uprilim); // clamp - restrict -- } else { -- return EINVAL; // no clue, punt -- } -- -- priocntl_enable = true; // Enable changing priorities -- return 0; --} -- --#define IAPRI(x) ((iaparms_t *)((x).pc_clparms)) --#define RTPRI(x) ((rtparms_t *)((x).pc_clparms)) --#define TSPRI(x) ((tsparms_t *)((x).pc_clparms)) --#define FXPRI(x) ((fxparms_t *)((x).pc_clparms)) -- -- --// scale_to_lwp_priority --// --// Convert from the libthread "thr_setprio" scale to our current --// lwp scheduling class scale. --// --static int scale_to_lwp_priority(int rMin, int rMax, int x) { -- int v; -- -- if (x == 127) return rMax; // avoid round-down -- v = (((x*(rMax-rMin)))/128)+rMin; -- return v; --} -- -- --// set_lwp_class_and_priority --int set_lwp_class_and_priority(int ThreadID, int lwpid, -- int newPrio, int new_class, bool scale) { -- int rslt; -- int Actual, Expected, prv; -- pcparms_t ParmInfo; // for GET-SET --#ifdef ASSERT -- pcparms_t ReadBack; // for readback --#endif -- -- // Set priority via PC_GETPARMS, update, PC_SETPARMS -- // Query current values. -- // TODO: accelerate this by eliminating the PC_GETPARMS call. -- // Cache "pcparms_t" in global ParmCache. -- // TODO: elide set-to-same-value -- -- // If something went wrong on init, don't change priorities. -- if (!priocntl_enable) { -- return EINVAL; -- } -- -- // If lwp hasn't started yet, just return -- // the _start routine will call us again. -- if (lwpid <= 0) { -- return 0; -- } -- -- memset(&ParmInfo, 0, sizeof(pcparms_t)); -- ParmInfo.pc_cid = PC_CLNULL; -- rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo); -- if (rslt < 0) return errno; -- -- int cur_class = ParmInfo.pc_cid; -- ParmInfo.pc_cid = (id_t)new_class; -- -- if (new_class == rtLimits.schedPolicy) { -- rtparms_t *rtInfo = (rtparms_t*)ParmInfo.pc_clparms; -- rtInfo->rt_pri = scale ? scale_to_lwp_priority(rtLimits.minPrio, -- rtLimits.maxPrio, newPrio) -- : newPrio; -- rtInfo->rt_tqsecs = RT_NOCHANGE; -- rtInfo->rt_tqnsecs = RT_NOCHANGE; -- } else if (new_class == iaLimits.schedPolicy) { -- iaparms_t* iaInfo = (iaparms_t*)ParmInfo.pc_clparms; -- int maxClamped = MIN2(iaLimits.maxPrio, -- cur_class == new_class -- ? (int)iaInfo->ia_uprilim : iaLimits.maxPrio); -- iaInfo->ia_upri = scale ? scale_to_lwp_priority(iaLimits.minPrio, -- maxClamped, newPrio) -- : newPrio; -- iaInfo->ia_uprilim = cur_class == new_class -- ? IA_NOCHANGE : (pri_t)iaLimits.maxPrio; -- iaInfo->ia_mode = IA_NOCHANGE; -- } else if (new_class == tsLimits.schedPolicy) { -- tsparms_t* tsInfo = (tsparms_t*)ParmInfo.pc_clparms; -- int maxClamped = MIN2(tsLimits.maxPrio, -- cur_class == new_class -- ? (int)tsInfo->ts_uprilim : tsLimits.maxPrio); -- tsInfo->ts_upri = scale ? scale_to_lwp_priority(tsLimits.minPrio, -- maxClamped, newPrio) -- : newPrio; -- tsInfo->ts_uprilim = cur_class == new_class -- ? TS_NOCHANGE : (pri_t)tsLimits.maxPrio; -- } else if (new_class == fxLimits.schedPolicy) { -- fxparms_t* fxInfo = (fxparms_t*)ParmInfo.pc_clparms; -- int maxClamped = MIN2(fxLimits.maxPrio, -- cur_class == new_class -- ? (int)fxInfo->fx_uprilim : fxLimits.maxPrio); -- fxInfo->fx_upri = scale ? scale_to_lwp_priority(fxLimits.minPrio, -- maxClamped, newPrio) -- : newPrio; -- fxInfo->fx_uprilim = cur_class == new_class -- ? FX_NOCHANGE : (pri_t)fxLimits.maxPrio; -- fxInfo->fx_tqsecs = FX_NOCHANGE; -- fxInfo->fx_tqnsecs = FX_NOCHANGE; -- } else { -- return EINVAL; // no clue, punt -- } -- -- rslt = priocntl(P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo); -- if (rslt < 0) return errno; -- --#ifdef ASSERT -- // Sanity check: read back what we just attempted to set. -- // In theory it could have changed in the interim ... -- // -- // The priocntl system call is tricky. -- // Sometimes it'll validate the priority value argument and -- // return EINVAL if unhappy. At other times it fails silently. -- // Readbacks are prudent. -- -- if (!ReadBackValidate) return 0; -- -- memset(&ReadBack, 0, sizeof(pcparms_t)); -- ReadBack.pc_cid = PC_CLNULL; -- rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack); -- assert(rslt >= 0, "priocntl failed"); -- Actual = Expected = 0xBAD; -- assert(ParmInfo.pc_cid == ReadBack.pc_cid, "cid's don't match"); -- if (ParmInfo.pc_cid == rtLimits.schedPolicy) { -- Actual = RTPRI(ReadBack)->rt_pri; -- Expected = RTPRI(ParmInfo)->rt_pri; -- } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) { -- Actual = IAPRI(ReadBack)->ia_upri; -- Expected = IAPRI(ParmInfo)->ia_upri; -- } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) { -- Actual = TSPRI(ReadBack)->ts_upri; -- Expected = TSPRI(ParmInfo)->ts_upri; -- } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) { -- Actual = FXPRI(ReadBack)->fx_upri; -- Expected = FXPRI(ParmInfo)->fx_upri; -- } --#endif -- -- return 0; --} -- --// Solaris only gives access to 128 real priorities at a time, --// so we expand Java's ten to fill this range. This would be better --// if we dynamically adjusted relative priorities. --// --// The ThreadPriorityPolicy option allows us to select 2 different --// priority scales. --// --// ThreadPriorityPolicy=0 --// Since the Solaris' default priority is MaximumPriority, we do not --// set a priority lower than Max unless a priority lower than --// NormPriority is requested. --// --// ThreadPriorityPolicy=1 --// This mode causes the priority table to get filled with --// linear values. NormPriority get's mapped to 50% of the --// Maximum priority an so on. This will cause VM threads --// to get unfair treatment against other Solaris processes --// which do not explicitly alter their thread priorities. -- --int os::java_to_os_priority[CriticalPriority + 1] = { -- -99999, // 0 Entry should never be used -- -- 0, // 1 MinPriority -- 32, // 2 -- 64, // 3 -- -- 96, // 4 -- 127, // 5 NormPriority -- 127, // 6 -- -- 127, // 7 -- 127, // 8 -- 127, // 9 NearMaxPriority -- -- 127, // 10 MaxPriority -- -- -criticalPrio // 11 CriticalPriority --}; -- --OSReturn os::set_native_priority(Thread* thread, int newpri) { -- OSThread* osthread = thread->osthread(); -- -- // Save requested priority in case the thread hasn't been started -- osthread->set_native_priority(newpri); -- -- // Check for critical priority request -- bool fxcritical = false; -- if (newpri == -criticalPrio) { -- fxcritical = true; -- newpri = criticalPrio; -- } -- -- assert(newpri >= MinimumPriority && newpri <= MaximumPriority, "bad priority mapping"); -- if (!UseThreadPriorities) return OS_OK; -- -- int status = 0; -- -- if (!fxcritical) { -- // Use thr_setprio only if we have a priority that thr_setprio understands -- status = thr_setprio(thread->osthread()->thread_id(), newpri); -- } -- -- int lwp_status = -- set_lwp_class_and_priority(osthread->thread_id(), -- osthread->lwp_id(), -- newpri, -- fxcritical ? fxLimits.schedPolicy : myClass, -- !fxcritical); -- if (lwp_status != 0 && fxcritical) { -- // Try again, this time without changing the scheduling class -- newpri = java_MaxPriority_to_os_priority; -- lwp_status = set_lwp_class_and_priority(osthread->thread_id(), -- osthread->lwp_id(), -- newpri, myClass, false); -- } -- status |= lwp_status; -- return (status == 0) ? OS_OK : OS_ERR; --} -- -- --OSReturn os::get_native_priority(const Thread* const thread, -- int *priority_ptr) { -- int p; -- if (!UseThreadPriorities) { -- *priority_ptr = NormalPriority; -- return OS_OK; -- } -- int status = thr_getprio(thread->osthread()->thread_id(), &p); -- if (status != 0) { -- return OS_ERR; -- } -- *priority_ptr = p; -- return OS_OK; --} -- --//////////////////////////////////////////////////////////////////////////////// -- --// This does not do anything on Solaris. This is basically a hook for being --// able to use structured exception handling (thread-local exception filters) on, e.g., Win32. --void os::os_exception_wrapper(java_call_t f, JavaValue* value, -- const methodHandle& method, JavaCallArguments* args, -- JavaThread* thread) { -- f(value, method, args, thread); --} -- --void report_error(const char* file_name, int line_no, const char* title, -- const char* format, ...); -- --// (Static) wrappers for the liblgrp API --os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home; --os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init; --os::Solaris::lgrp_fini_func_t os::Solaris::_lgrp_fini; --os::Solaris::lgrp_root_func_t os::Solaris::_lgrp_root; --os::Solaris::lgrp_children_func_t os::Solaris::_lgrp_children; --os::Solaris::lgrp_resources_func_t os::Solaris::_lgrp_resources; --os::Solaris::lgrp_nlgrps_func_t os::Solaris::_lgrp_nlgrps; --os::Solaris::lgrp_cookie_stale_func_t os::Solaris::_lgrp_cookie_stale; --os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0; -- --static address resolve_symbol_lazy(const char* name) { -- address addr = (address) dlsym(RTLD_DEFAULT, name); -- if (addr == NULL) { -- // RTLD_DEFAULT was not defined on some early versions of 2.5.1 -- addr = (address) dlsym(RTLD_NEXT, name); -- } -- return addr; --} -- --static address resolve_symbol(const char* name) { -- address addr = resolve_symbol_lazy(name); -- if (addr == NULL) { -- fatal("resolve_symbol failed (%s)", dlerror()); -- } -- return addr; --} -- --void os::Solaris::libthread_init() { -- address func = (address)dlsym(RTLD_DEFAULT, "_thr_suspend_allmutators"); -- -- lwp_priocntl_init(); -- -- // RTLD_DEFAULT was not defined on some early versions of 5.5.1 -- if (func == NULL) { -- func = (address) dlsym(RTLD_NEXT, "_thr_suspend_allmutators"); -- // Guarantee that this VM is running on an new enough OS (5.6 or -- // later) that it will have a new enough libthread.so. -- guarantee(func != NULL, "libthread.so is too old."); -- } -- -- int size; -- void (*handler_info_func)(address *, int *); -- handler_info_func = CAST_TO_FN_PTR(void (*)(address *, int *), resolve_symbol("thr_sighndlrinfo")); -- handler_info_func(&handler_start, &size); -- handler_end = handler_start + size; --} -- -- --bool os::Solaris::_synchronization_initialized; -- --void os::Solaris::synchronization_init() { -- _synchronization_initialized = true; --} -- --bool os::Solaris::liblgrp_init() { -- void *handle = dlopen("liblgrp.so.1", RTLD_LAZY); -- if (handle != NULL) { -- os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home"))); -- os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init"))); -- os::Solaris::set_lgrp_fini(CAST_TO_FN_PTR(lgrp_fini_func_t, dlsym(handle, "lgrp_fini"))); -- os::Solaris::set_lgrp_root(CAST_TO_FN_PTR(lgrp_root_func_t, dlsym(handle, "lgrp_root"))); -- os::Solaris::set_lgrp_children(CAST_TO_FN_PTR(lgrp_children_func_t, dlsym(handle, "lgrp_children"))); -- os::Solaris::set_lgrp_resources(CAST_TO_FN_PTR(lgrp_resources_func_t, dlsym(handle, "lgrp_resources"))); -- os::Solaris::set_lgrp_nlgrps(CAST_TO_FN_PTR(lgrp_nlgrps_func_t, dlsym(handle, "lgrp_nlgrps"))); -- os::Solaris::set_lgrp_cookie_stale(CAST_TO_FN_PTR(lgrp_cookie_stale_func_t, -- dlsym(handle, "lgrp_cookie_stale"))); -- -- lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER); -- set_lgrp_cookie(c); -- return true; -- } -- return false; --} -- --// int pset_getloadavg(psetid_t pset, double loadavg[], int nelem); --typedef long (*pset_getloadavg_type)(psetid_t pset, double loadavg[], int nelem); --static pset_getloadavg_type pset_getloadavg_ptr = NULL; -- --void init_pset_getloadavg_ptr(void) { -- pset_getloadavg_ptr = -- (pset_getloadavg_type)dlsym(RTLD_DEFAULT, "pset_getloadavg"); -- if (pset_getloadavg_ptr == NULL) { -- log_warning(os)("pset_getloadavg function not found"); -- } --} -- --int os::Solaris::_dev_zero_fd = -1; -- --// this is called _before_ the global arguments have been parsed --void os::init(void) { -- _initial_pid = getpid(); -- -- max_hrtime = first_hrtime = gethrtime(); -- -- init_random(1234567); -- -- int page_size = sysconf(_SC_PAGESIZE); -- OSInfo::set_vm_page_size(page_size); -- OSInfo::set_vm_allocation_granularity(page_size); -- if (os::vm_page_size() <= 0) { -- fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno)); -- } -- _page_sizes.add(os::vm_page_size()); -- -- Solaris::initialize_system_info(); -- -- int fd = ::open("/dev/zero", O_RDWR); -- if (fd < 0) { -- fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno)); -- } else { -- Solaris::set_dev_zero_fd(fd); -- -- // Close on exec, child won't inherit. -- fcntl(fd, F_SETFD, FD_CLOEXEC); -- } -- -- clock_tics_per_sec = CLK_TCK; -- -- // check if dladdr1() exists; dladdr1 can provide more information than -- // dladdr for os::dll_address_to_function_name. It comes with SunOS 5.9 -- // and is available on linker patches for 5.7 and 5.8. -- // libdl.so must have been loaded, this call is just an entry lookup -- void * hdl = dlopen("libdl.so", RTLD_NOW); -- if (hdl) { -- dladdr1_func = CAST_TO_FN_PTR(dladdr1_func_type, dlsym(hdl, "dladdr1")); -- } -- -- // main_thread points to the thread that created/loaded the JVM. -- main_thread = thr_self(); -- -- // dynamic lookup of functions that may not be available in our lowest -- // supported Solaris release -- void * handle = dlopen("libc.so.1", RTLD_LAZY); -- if (handle != NULL) { -- Solaris::_pthread_setname_np = // from 11.3 -- (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np"); -- } -- -- // Shared Posix initialization -- os::Posix::init(); --} -- --// To install functions for atexit system call --extern "C" { -- static void perfMemory_exit_helper() { -- perfMemory_exit(); -- } --} -- --// this is called _after_ the global arguments have been parsed --jint os::init_2(void) { -- Solaris::libthread_init(); -- -- if (UseNUMA) { -- if (!Solaris::liblgrp_init()) { -- FLAG_SET_ERGO(UseNUMA, false); -- } else { -- size_t lgrp_limit = os::numa_get_groups_num(); -- int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit, mtInternal); -- size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit); -- FREE_C_HEAP_ARRAY(int, lgrp_ids); -- if (lgrp_num < 2) { -- // There's only one locality group, disable NUMA -- UseNUMA = false; -- } -- } -- } -- -- // When NUMA requested, not-NUMA-aware allocations default to interleaving. -- if (UseNUMA && !UseNUMAInterleaving) { -- FLAG_SET_ERGO_IF_DEFAULT(UseNUMAInterleaving, true); -- } -- -- if (PosixSignals::init() == JNI_ERR) { -- return JNI_ERR; -- } -- -- // initialize synchronization primitives -- Solaris::synchronization_init(); -- DEBUG_ONLY(os::set_mutex_init_done();) -- -- if (MaxFDLimit) { -- // set the number of file descriptors to max. print out error -- // if getrlimit/setrlimit fails but continue regardless. -- struct rlimit nbr_files; -- int status = getrlimit(RLIMIT_NOFILE, &nbr_files); -- if (status != 0) { -- log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); -- } else { -- nbr_files.rlim_cur = nbr_files.rlim_max; -- status = setrlimit(RLIMIT_NOFILE, &nbr_files); -- if (status != 0) { -- log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); -- } -- } -- } -- -- // Calculate theoretical max. size of Threads to guard gainst -- // artifical out-of-memory situations, where all available address- -- // space has been reserved by thread stacks. Default stack size is 1Mb. -- size_t pre_thread_stack_size = (JavaThread::stack_size_at_create()) ? -- JavaThread::stack_size_at_create() : (1*K*K); -- assert(pre_thread_stack_size != 0, "Must have a stack"); -- // Solaris has a maximum of 4Gb of user programs. Calculate the thread limit when -- // we should start doing Virtual Memory banging. Currently when the threads will -- // have used all but 200Mb of space. -- size_t max_address_space = ((unsigned int)4 * K * K * K) - (200 * K * K); -- Solaris::_os_thread_limit = max_address_space / pre_thread_stack_size; -- -- // at-exit methods are called in the reverse order of their registration. -- // In Solaris 7 and earlier, atexit functions are called on return from -- // main or as a result of a call to exit(3C). There can be only 32 of -- // these functions registered and atexit() does not set errno. In Solaris -- // 8 and later, there is no limit to the number of functions registered -- // and atexit() sets errno. In addition, in Solaris 8 and later, atexit -- // functions are called upon dlclose(3DL) in addition to return from main -- // and exit(3C). -- -- if (PerfAllowAtExitRegistration) { -- // only register atexit functions if PerfAllowAtExitRegistration is set. -- // atexit functions can be delayed until process exit time, which -- // can be problematic for embedded VM situations. Embedded VMs should -- // call DestroyJavaVM() to assure that VM resources are released. -- -- // note: perfMemory_exit_helper atexit function may be removed in -- // the future if the appropriate cleanup code can be added to the -- // VM_Exit VMOperation's doit method. -- if (atexit(perfMemory_exit_helper) != 0) { -- warning("os::init2 atexit(perfMemory_exit_helper) failed"); -- } -- } -- -- // Init pset_loadavg function pointer -- init_pset_getloadavg_ptr(); -- -- // Shared Posix initialization -- os::Posix::init_2(); -- -- return JNI_OK; --} -- --// This code originates from JDK's sysOpen and open64_w --// from src/solaris/hpi/src/system_md.c -- --int os::open(const char *path, int oflag, int mode) { -- if (strlen(path) > MAX_PATH - 1) { -- errno = ENAMETOOLONG; -- return -1; -- } -- int fd; -- -- fd = ::open64(path, oflag, mode); -- if (fd == -1) return -1; -- -- // If the open succeeded, the file might still be a directory -- { -- struct stat64 buf64; -- int ret = ::fstat64(fd, &buf64); -- int st_mode = buf64.st_mode; -- -- if (ret != -1) { -- if ((st_mode & S_IFMT) == S_IFDIR) { -- errno = EISDIR; -- ::close(fd); -- return -1; -- } -- } else { -- ::close(fd); -- return -1; -- } -- } -- -- // All file descriptors that are opened in the JVM and not -- // specifically destined for a subprocess should have the -- // close-on-exec flag set. If we don't set it, then careless 3rd -- // party native code might fork and exec without closing all -- // appropriate file descriptors (e.g. as we do in closeDescriptors in -- // UNIXProcess.c), and this in turn might: -- // -- // - cause end-of-file to fail to be detected on some file -- // descriptors, resulting in mysterious hangs, or -- // -- // - might cause an fopen in the subprocess to fail on a system -- // suffering from bug 1085341. -- // -- // (Yes, the default setting of the close-on-exec flag is a Unix -- // design flaw) -- // -- // See: -- // 1085341: 32-bit stdio routines should support file descriptors >255 -- // 4843136: (process) pipe file descriptor from Runtime.exec not being closed -- // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 -- // --#ifdef FD_CLOEXEC -- { -- int flags = ::fcntl(fd, F_GETFD); -- if (flags != -1) { -- ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC); -- } -- } --#endif -- -- return fd; --} -- --// create binary file, rewriting existing file if required --int os::create_binary_file(const char* path, bool rewrite_existing) { -- int oflags = O_WRONLY | O_CREAT; -- if (!rewrite_existing) { -- oflags |= O_EXCL; -- } -- return ::open64(path, oflags, S_IREAD | S_IWRITE); --} -- --// return current position of file pointer --jlong os::current_file_offset(int fd) { -- return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR); --} -- --// move file pointer to the specified offset --jlong os::seek_to_file_offset(int fd, jlong offset) { -- return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET); --} -- --// Map a block of memory. --char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, -- char *addr, size_t bytes, bool read_only, -- bool allow_exec) { -- int prot; -- int flags; -- -- if (read_only) { -- prot = PROT_READ; -- flags = MAP_SHARED; -- } else { -- prot = PROT_READ | PROT_WRITE; -- flags = MAP_PRIVATE; -- } -- -- if (allow_exec) { -- prot |= PROT_EXEC; -- } -- -- if (addr != NULL) { -- flags |= MAP_FIXED; -- } -- -- char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags, -- fd, file_offset); -- if (mapped_address == MAP_FAILED) { -- return NULL; -- } -- return mapped_address; --} -- -- --// Remap a block of memory. --char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset, -- char *addr, size_t bytes, bool read_only, -- bool allow_exec) { -- // same as map_memory() on this OS -- return os::map_memory(fd, file_name, file_offset, addr, bytes, read_only, -- allow_exec); --} -- -- --// Unmap a block of memory. --bool os::pd_unmap_memory(char* addr, size_t bytes) { -- return munmap(addr, bytes) == 0; --} -- --const intptr_t thr_time_off = (intptr_t)(&((prusage_t *)(NULL))->pr_utime); --const intptr_t thr_time_size = (intptr_t)(&((prusage_t *)(NULL))->pr_ttime) - -- (intptr_t)(&((prusage_t *)(NULL))->pr_utime); -- -- --// JVMTI & JVM monitoring and management support --// The thread_cpu_time() and current_thread_cpu_time() are only --// supported if is_thread_cpu_time_supported() returns true. --// They are not supported on Solaris T1. -- --// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) --// are used by JVM M&M and JVMTI to get user+sys or user CPU time --// of a thread. --// --// current_thread_cpu_time() and thread_cpu_time(Thread *) --// returns the fast estimate available on the platform. -- --// hrtime_t gethrvtime() return value includes --// user time but does not include system time --jlong os::current_thread_cpu_time() { -- return (jlong) gethrvtime(); --} -- --jlong os::thread_cpu_time(Thread *thread) { -- // return user level CPU time only to be consistent with -- // what current_thread_cpu_time returns. -- // thread_cpu_time_info() must be changed if this changes -- return os::thread_cpu_time(thread, false /* user time only */); --} -- --jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { -- if (user_sys_cpu_time) { -- return os::thread_cpu_time(Thread::current(), user_sys_cpu_time); -- } else { -- return os::current_thread_cpu_time(); -- } --} -- --jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { -- char proc_name[64]; -- int count; -- prusage_t prusage; -- jlong lwp_time; -- int fd; -- -- sprintf(proc_name, "/proc/%d/lwp/%d/lwpusage", -- getpid(), -- thread->osthread()->lwp_id()); -- fd = ::open(proc_name, O_RDONLY); -- if (fd == -1) return -1; -- -- do { -- count = ::pread(fd, -- (void *)&prusage.pr_utime, -- thr_time_size, -- thr_time_off); -- } while (count < 0 && errno == EINTR); -- ::close(fd); -- if (count < 0) return -1; -- -- if (user_sys_cpu_time) { -- // user + system CPU time -- lwp_time = (((jlong)prusage.pr_stime.tv_sec + -- (jlong)prusage.pr_utime.tv_sec) * (jlong)1000000000) + -- (jlong)prusage.pr_stime.tv_nsec + -- (jlong)prusage.pr_utime.tv_nsec; -- } else { -- // user level CPU time only -- lwp_time = ((jlong)prusage.pr_utime.tv_sec * (jlong)1000000000) + -- (jlong)prusage.pr_utime.tv_nsec; -- } -- -- return (lwp_time); --} -- --void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { -- info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits -- info_ptr->may_skip_backward = false; // elapsed time not wall time -- info_ptr->may_skip_forward = false; // elapsed time not wall time -- info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned --} -- --void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { -- info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits -- info_ptr->may_skip_backward = false; // elapsed time not wall time -- info_ptr->may_skip_forward = false; // elapsed time not wall time -- info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned --} -- --bool os::is_thread_cpu_time_supported() { -- return true; --} -- --// System loadavg support. Returns -1 if load average cannot be obtained. --// Return the load average for our processor set if the primitive exists --// (Solaris 9 and later). Otherwise just return system wide loadavg. --int os::loadavg(double loadavg[], int nelem) { -- if (pset_getloadavg_ptr != NULL) { -- return (*pset_getloadavg_ptr)(PS_MYID, loadavg, nelem); -- } else { -- return ::getloadavg(loadavg, nelem); -- } --} -- --//--------------------------------------------------------------------------------- -- --bool os::find(address addr, outputStream* st) { -- Dl_info dlinfo; -- memset(&dlinfo, 0, sizeof(dlinfo)); -- if (dladdr(addr, &dlinfo) != 0) { -- st->print(PTR_FORMAT ": ", p2i(addr)); -- if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) { -- st->print("%s+" PTR_FORMAT, dlinfo.dli_sname, -- p2i(addr) - p2i(dlinfo.dli_saddr)); -- } else if (dlinfo.dli_fbase != NULL) { -- st->print("", p2i(addr) - p2i(dlinfo.dli_fbase)); -- } else { -- st->print(""); -- } -- if (dlinfo.dli_fname != NULL) { -- st->print(" in %s", dlinfo.dli_fname); -- } -- if (dlinfo.dli_fbase != NULL) { -- st->print(" at " PTR_FORMAT, p2i(dlinfo.dli_fbase)); -- } -- st->cr(); -- -- if (Verbose) { -- // decode some bytes around the PC -- address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size()); -- address end = clamp_address_in_page(addr+40, addr, os::vm_page_size()); -- address lowest = (address) dlinfo.dli_sname; -- if (!lowest) lowest = (address) dlinfo.dli_fbase; -- if (begin < lowest) begin = lowest; -- Dl_info dlinfo2; -- if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr -- && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) { -- end = (address) dlinfo2.dli_saddr; -- } -- Disassembler::decode(begin, end, st); -- } -- return true; -- } -- return false; --} -- --// Following function has been added to support HotSparc's libjvm.so running --// under Solaris production JDK 1.2.2 / 1.3.0. These came from --// src/solaris/hpi/native_threads in the EVM codebase. --// --// NOTE: This is no longer needed in the 1.3.1 and 1.4 production release --// libraries and should thus be removed. We will leave it behind for a while --// until we no longer want to able to run on top of 1.3.0 Solaris production --// JDK. See 4341971. -- --#define STACK_SLACK 0x800 -- --extern "C" { -- intptr_t sysThreadAvailableStackWithSlack() { -- stack_t st; -- intptr_t retval, stack_top; -- retval = thr_stksegment(&st); -- assert(retval == 0, "incorrect return value from thr_stksegment"); -- assert((address)&st < (address)st.ss_sp, "Invalid stack base returned"); -- assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned"); -- stack_top=(intptr_t)st.ss_sp-st.ss_size; -- return ((intptr_t)&stack_top - stack_top - STACK_SLACK); -- } --} -- --// ObjectMonitor park-unpark infrastructure ... --// --// We implement Solaris and Linux PlatformEvents with the --// obvious condvar-mutex-flag triple. --// Another alternative that works quite well is pipes: --// Each PlatformEvent consists of a pipe-pair. --// The thread associated with the PlatformEvent --// calls park(), which reads from the input end of the pipe. --// Unpark() writes into the other end of the pipe. --// The write-side of the pipe must be set NDELAY. --// Unfortunately pipes consume a large # of handles. --// Native solaris lwp_park() and lwp_unpark() work nicely, too. --// Using pipes for the 1st few threads might be workable, however. --// --// park() is permitted to return spuriously. --// Callers of park() should wrap the call to park() in --// an appropriate loop. A litmus test for the correct --// usage of park is the following: if park() were modified --// to immediately return 0 your code should still work, --// albeit degenerating to a spin loop. --// --// In a sense, park()-unpark() just provides more polite spinning --// and polling with the key difference over naive spinning being --// that a parked thread needs to be explicitly unparked() in order --// to wake up and to poll the underlying condition. --// --// Assumption: --// Only one parker can exist on an event, which is why we allocate --// them per-thread. Multiple unparkers can coexist. --// --// _event transitions in park() --// -1 => -1 : illegal --// 1 => 0 : pass - return immediately --// 0 => -1 : block; then set _event to 0 before returning --// --// _event transitions in unpark() --// 0 => 1 : just return --// 1 => 1 : just return --// -1 => either 0 or 1; must signal target thread --// That is, we can safely transition _event from -1 to either --// 0 or 1. --// --// _event serves as a restricted-range semaphore. --// -1 : thread is blocked, i.e. there is a waiter --// 0 : neutral: thread is running or ready, --// could have been signaled after a wait started --// 1 : signaled - thread is running or ready --// --// Another possible encoding of _event would be with --// explicit "PARKED" == 01b and "SIGNALED" == 10b bits. --// --// TODO-FIXME: add DTRACE probes for: --// 1. Tx parks --// 2. Ty unparks Tx --// 3. Tx resumes from park -- --// JSR166 --// ------------------------------------------------------- -- --// The solaris and linux implementations of park/unpark are fairly --// conservative for now, but can be improved. They currently use a --// mutex/condvar pair, plus _counter. --// Park decrements _counter if > 0, else does a condvar wait. Unpark --// sets count to 1 and signals condvar. Only one thread ever waits --// on the condvar. Contention seen when trying to park implies that someone --// is unparking you, so don't wait. And spurious returns are fine, so there --// is no need to track notifications. -- --// Get the default path to the core file --// Returns the length of the string --int os::get_core_path(char* buffer, size_t bufferSize) { -- const char* p = get_current_directory(buffer, bufferSize); -- -- if (p == NULL) { -- assert(p != NULL, "failed to get current directory"); -- return 0; -- } -- -- jio_snprintf(buffer, bufferSize, "%s/core or core.%d", -- p, current_process_id()); -- -- return strlen(buffer); --} -- --bool os::supports_map_sync() { -- return false; --} -- --#ifndef PRODUCT --void TestReserveMemorySpecial_test() { -- // No tests available for this platform --} --#endif -- --bool os::start_debugging(char *buf, int buflen) { -- int len = (int)strlen(buf); -- char *p = &buf[len]; -- -- jio_snprintf(p, buflen-len, -- "\n\n" -- "Do you want to debug the problem?\n\n" -- "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n" -- "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n" -- "Otherwise, press RETURN to abort...", -- os::current_process_id(), os::current_thread_id()); -- -- bool yes = os::message_box("Unexpected Error", buf); -- -- if (yes) { -- // yes, user asked VM to launch debugger -- jio_snprintf(buf, sizeof(buf), "dbx - %d", os::current_process_id()); -- -- os::fork_and_exec(buf); -- yes = false; -- } -- return yes; --} -- --void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} -- --#if INCLUDE_JFR -- --void os::jfr_report_memory_info() {} -- --#endif // INCLUDE_JFR -- --bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { -- -- if (ebuf && ebuflen > 0) { -- ebuf[0] = '\0'; -- ebuf[ebuflen - 1] = '\0'; -- } -- -- bool res = (0 == ::dlclose(libhandle)); -- if (!res) { -- // error analysis when dlopen fails -- const char* error_report = ::dlerror(); -- if (error_report == nullptr) { -- error_report = "dlerror returned no error description"; -- } -- if (ebuf != nullptr && ebuflen > 0) { -- snprintf(ebuf, ebuflen - 1, "%s", error_report); -- } -- } -- -- return res; --} // end: os::pd_dll_unload() ---- old/src/hotspot/os/solaris/os_solaris.hpp 2020-05-20 18:09:35.461123002 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,198 +0,0 @@ --/* -- * Copyright (c) 1997, 2020, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_SOLARIS_OS_SOLARIS_HPP --#define OS_SOLARIS_OS_SOLARIS_HPP -- --#include "runtime/os.hpp" -- --// Solaris_OS defines the interface to Solaris operating systems -- --// see thr_setprio(3T) for the basis of these numbers --#define MinimumPriority 0 --#define NormalPriority 64 --#define MaximumPriority 127 -- --// FX/60 is critical thread class/priority on T4 --#define FXCriticalPriority 60 -- --class os::Solaris { -- friend class os; -- -- private: -- -- static bool _synchronization_initialized; -- -- typedef uintptr_t lgrp_cookie_t; -- typedef id_t lgrp_id_t; -- typedef int lgrp_rsrc_t; -- typedef enum lgrp_view { -- LGRP_VIEW_CALLER, // what's available to the caller -- LGRP_VIEW_OS // what's available to operating system -- } lgrp_view_t; -- -- typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id); -- typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view); -- typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie); -- typedef lgrp_id_t (*lgrp_root_func_t)(lgrp_cookie_t cookie); -- typedef int (*lgrp_children_func_t)(lgrp_cookie_t cookie, lgrp_id_t parent, -- lgrp_id_t *lgrp_array, uint_t lgrp_array_size); -- typedef int (*lgrp_resources_func_t)(lgrp_cookie_t cookie, lgrp_id_t lgrp, -- lgrp_id_t *lgrp_array, uint_t lgrp_array_size, -- lgrp_rsrc_t type); -- typedef int (*lgrp_nlgrps_func_t)(lgrp_cookie_t cookie); -- typedef int (*lgrp_cookie_stale_func_t)(lgrp_cookie_t cookie); -- -- static lgrp_home_func_t _lgrp_home; -- static lgrp_init_func_t _lgrp_init; -- static lgrp_fini_func_t _lgrp_fini; -- static lgrp_root_func_t _lgrp_root; -- static lgrp_children_func_t _lgrp_children; -- static lgrp_resources_func_t _lgrp_resources; -- static lgrp_nlgrps_func_t _lgrp_nlgrps; -- static lgrp_cookie_stale_func_t _lgrp_cookie_stale; -- static lgrp_cookie_t _lgrp_cookie; -- -- // Large Page Support -- static bool is_valid_page_size(size_t bytes); -- static size_t page_size_for_alignment(size_t alignment); -- static bool setup_large_pages(caddr_t start, size_t bytes, size_t align); -- -- typedef int (*pthread_setname_np_func_t)(pthread_t, const char*); -- static pthread_setname_np_func_t _pthread_setname_np; -- -- public: -- // Large Page Support--ISM. -- static bool largepage_range(char* addr, size_t size); -- -- static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo -- -- static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect); -- static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread, -- const ucontext_t* uc); -- -- static intptr_t* ucontext_get_sp(const ucontext_t* uc); -- // ucontext_get_fp() is only used by Solaris X86 (see note below) -- static intptr_t* ucontext_get_fp(const ucontext_t* uc); -- -- static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr); -- -- static void init_thread_fpu_state(void); -- -- protected: -- // Solaris-specific interface goes here -- static julong available_memory(); -- static julong free_memory(); -- static julong physical_memory() { return _physical_memory; } -- static julong _physical_memory; -- static void initialize_system_info(); -- static int _dev_zero_fd; -- static int get_dev_zero_fd() { return _dev_zero_fd; } -- static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; } -- static int commit_memory_impl(char* addr, size_t bytes, bool exec); -- static int commit_memory_impl(char* addr, size_t bytes, -- size_t alignment_hint, bool exec); -- static char* mmap_chunk(char *addr, size_t size, int flags, int prot); -- static char* anon_mmap(char* requested_addr, size_t bytes); -- static bool mpss_sanity_check(bool warn, size_t * page_size); -- -- // Workaround for 4352906. thr_stksegment sometimes returns -- // a bad value for the primordial thread's stack base when -- // it is called more than one time. -- // Workaround is to cache the initial value to avoid further -- // calls to thr_stksegment. -- // It appears that someone (Hotspot?) is trashing the user's -- // proc_t structure (note that this is a system struct). -- static address _main_stack_base; -- -- static void print_distro_info(outputStream* st); -- static void print_libversion_info(outputStream* st); -- -- public: -- static void libthread_init(); -- static void synchronization_init(); -- static bool liblgrp_init(); -- -- // alignment with os_posix means we use pthreads -- static int mutex_lock(pthread_mutex_t *mx) { return pthread_mutex_lock(mx); } -- static int mutex_trylock(pthread_mutex_t *mx) { return pthread_mutex_trylock(mx); } -- static int mutex_unlock(pthread_mutex_t *mx) { return pthread_mutex_unlock(mx); } -- static int mutex_init(pthread_mutex_t *mx) { return pthread_mutex_init(mx, NULL); } -- static int mutex_destroy(pthread_mutex_t *mx) { return pthread_mutex_destroy(mx); } -- -- static int cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mx, timestruc_t *abst) { return pthread_cond_timedwait(cv, mx, abst); } -- static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mx) { return pthread_cond_wait(cv, mx); } -- static int cond_signal(pthread_cond_t *cv) { return pthread_cond_signal(cv); } -- static int cond_broadcast(pthread_cond_t *cv) { return pthread_cond_broadcast(cv); } -- static int cond_init(pthread_cond_t *cv) { return pthread_cond_init(cv, NULL); } -- static int cond_destroy(pthread_cond_t *cv) { return pthread_cond_destroy(cv); } -- -- static bool synchronization_initialized() { return _synchronization_initialized; } -- -- static void set_lgrp_home(lgrp_home_func_t func) { _lgrp_home = func; } -- static void set_lgrp_init(lgrp_init_func_t func) { _lgrp_init = func; } -- static void set_lgrp_fini(lgrp_fini_func_t func) { _lgrp_fini = func; } -- static void set_lgrp_root(lgrp_root_func_t func) { _lgrp_root = func; } -- static void set_lgrp_children(lgrp_children_func_t func) { _lgrp_children = func; } -- static void set_lgrp_resources(lgrp_resources_func_t func) { _lgrp_resources = func; } -- static void set_lgrp_nlgrps(lgrp_nlgrps_func_t func) { _lgrp_nlgrps = func; } -- static void set_lgrp_cookie_stale(lgrp_cookie_stale_func_t func) { _lgrp_cookie_stale = func; } -- static void set_lgrp_cookie(lgrp_cookie_t cookie) { _lgrp_cookie = cookie; } -- -- static id_t lgrp_home(idtype_t type, id_t id) { return _lgrp_home != NULL ? _lgrp_home(type, id) : -1; } -- static lgrp_cookie_t lgrp_init(lgrp_view_t view) { return _lgrp_init != NULL ? _lgrp_init(view) : 0; } -- static int lgrp_fini(lgrp_cookie_t cookie) { return _lgrp_fini != NULL ? _lgrp_fini(cookie) : -1; } -- static lgrp_id_t lgrp_root(lgrp_cookie_t cookie) { return _lgrp_root != NULL ? _lgrp_root(cookie) : -1; } -- static int lgrp_children(lgrp_cookie_t cookie, lgrp_id_t parent, -- lgrp_id_t *lgrp_array, uint_t lgrp_array_size) { -- return _lgrp_children != NULL ? _lgrp_children(cookie, parent, lgrp_array, lgrp_array_size) : -1; -- } -- static int lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp, -- lgrp_id_t *lgrp_array, uint_t lgrp_array_size, -- lgrp_rsrc_t type) { -- return _lgrp_resources != NULL ? _lgrp_resources(cookie, lgrp, lgrp_array, lgrp_array_size, type) : -1; -- } -- -- static int lgrp_nlgrps(lgrp_cookie_t cookie) { return _lgrp_nlgrps != NULL ? _lgrp_nlgrps(cookie) : -1; } -- static int lgrp_cookie_stale(lgrp_cookie_t cookie) { -- return _lgrp_cookie_stale != NULL ? _lgrp_cookie_stale(cookie) : -1; -- } -- static lgrp_cookie_t lgrp_cookie() { return _lgrp_cookie; } -- -- static sigset_t* unblocked_signals(); -- static sigset_t* vm_signals(); -- -- // %%% Following should be promoted to os.hpp: -- // Trace number of created threads -- static jint _os_thread_limit; -- static volatile jint _os_thread_count; -- -- static void correct_stack_boundaries_for_primordial_thread(Thread* thr); -- -- // Stack repair handling -- -- // none present -- --}; --#endif // OS_SOLARIS_OS_SOLARIS_HPP ---- old/src/hotspot/os/solaris/os_solaris.inline.hpp 2020-05-20 18:09:36.197137133 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,72 +0,0 @@ --/* -- * Copyright (c) 1997, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_SOLARIS_OS_SOLARIS_INLINE_HPP --#define OS_SOLARIS_OS_SOLARIS_INLINE_HPP -- --#include "os_solaris.hpp" -- --#include "runtime/os.hpp" --#include "os_posix.inline.hpp" -- --// System includes --#include --#include --#include --#include --#include --#include --#include --#include -- --inline bool os::zero_page_read_protected() { -- return true; --} -- --inline bool os::uses_stack_guard_pages() { -- return true; --} -- --inline bool os::must_commit_stack_guard_pages() { -- assert(uses_stack_guard_pages(), "sanity check"); -- int r = thr_main() ; -- guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ; -- return r; --} -- -- --// Bang the shadow pages if they need to be touched to be mapped. --inline void os::map_stack_shadow_pages(address sp) { --} -- --// Trim-native support, stubbed out for now, may be enabled later --inline bool os::can_trim_native_heap() { return false; } --inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } -- --////////////////////////////////////////////////////////////////////////////// --//////////////////////////////////////////////////////////////////////////////// -- --inline bool os::numa_has_group_homing() { return true; } -- --#endif // OS_SOLARIS_OS_SOLARIS_INLINE_HPP ---- old/src/hotspot/os/solaris/vmStructs_solaris.hpp 2020-05-20 18:09:38.337178219 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,44 +0,0 @@ --/* -- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP --#define OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP -- --// These are the OS-specific fields, types and integer --// constants required by the Serviceability Agent. This file is --// referenced by vmStructs.cpp. -- --#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ -- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) -- --#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ -- declare_unsigned_integer_type(OSThread::thread_id_t) -- --#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -- --#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -- --#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) -- --#endif // OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP ---- old/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp 2020-05-20 18:09:56.181520810 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,37 +0,0 @@ --/* -- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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 "asm/macroAssembler.inline.hpp" --#include "runtime/os.hpp" -- --void MacroAssembler::int3() { -- push(rax); -- push(rdx); -- push(rcx); -- call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint))); -- pop(rcx); -- pop(rdx); -- pop(rax); --} ---- old/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp 2020-05-20 18:09:56.917534941 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,182 +0,0 @@ --/* -- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP -- --inline int32_t _Atomic_add(int32_t add_value, volatile int32_t* dest) { -- int32_t rv = add_value; -- __asm__ volatile ("lock xaddl %0,(%2)" -- : "=r" (rv) -- : "0" (rv), "r" (dest) -- : "cc", "memory"); -- return rv + add_value; --} --inline int64_t _Atomic_add_long(int64_t add_value, volatile int64_t* dest) { -- int64_t rv = add_value; -- __asm__ volatile ("lock xaddq %0,(%2)" -- : "=r" (rv) -- : "0" (rv), "r" (dest) -- : "cc", "memory"); -- return rv + add_value; --} --inline int32_t _Atomic_xchg(int32_t exchange_value, volatile int32_t* dest) { -- __asm__ __volatile__ ("xchgl (%2),%0" -- : "=r" (exchange_value) -- : "0" (exchange_value), "r" (dest) -- : "memory"); -- return exchange_value; --} --inline int64_t _Atomic_xchg_long(int64_t exchange_value, volatile int64_t* dest) { -- __asm__ __volatile__ ("xchgq (%2),%0" -- : "=r" (exchange_value) -- : "0" (exchange_value), "r" (dest) -- : "memory"); -- return exchange_value; --} --inline int8_t _Atomic_cmpxchg_byte(int8_t exchange_value, volatile int8_t* dest, int8_t compare_value) { -- __asm__ volatile ("lock cmpxchgb %1,(%3)" -- : "=a" (exchange_value) -- : "q" (exchange_value), "a" (compare_value), "r" (dest) -- : "cc", "memory"); -- return exchange_value; --} --inline int32_t _Atomic_cmpxchg(int32_t exchange_value, volatile int32_t* dest, int32_t compare_value) { -- __asm__ volatile ("lock cmpxchgl %1,(%3)" -- : "=a" (exchange_value) -- : "q" (exchange_value), "a" (compare_value), "r" (dest) -- : "cc", "memory"); -- return exchange_value; --} --inline int64_t _Atomic_cmpxchg_long(int64_t exchange_value, volatile int64_t* dest, int64_t compare_value) { -- __asm__ volatile ("lock cmpxchgq %1,(%3)" -- : "=a" (exchange_value) -- : "q" (exchange_value), "a" (compare_value), "r" (dest) -- : "cc", "memory"); -- return exchange_value; --} -- --template --struct Atomic::PlatformAdd { -- template -- D add_then_fetch(D volatile* dest, I add_value, atomic_memory_order order) const; -- -- template -- D fetch_then_add(D volatile* dest, I add_value, atomic_memory_order order) const { -- return add_then_fetch(dest, add_value, order) - add_value; -- } --}; -- --// Not using add_using_helper; see comment for cmpxchg. --template<> --template --inline D Atomic::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_value, -- atomic_memory_order order) const { -- STATIC_ASSERT(4 == sizeof(I)); -- STATIC_ASSERT(4 == sizeof(D)); -- return PrimitiveConversions::cast( -- _Atomic_add(PrimitiveConversions::cast(add_value), -- reinterpret_cast(dest))); --} -- --// Not using add_using_helper; see comment for cmpxchg. --template<> --template --inline D Atomic::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_value, -- atomic_memory_order order) const { -- STATIC_ASSERT(8 == sizeof(I)); -- STATIC_ASSERT(8 == sizeof(D)); -- return PrimitiveConversions::cast( -- _Atomic_add_long(PrimitiveConversions::cast(add_value), -- reinterpret_cast(dest))); --} -- --template<> --template --inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, -- T exchange_value, -- atomic_memory_order order) const { -- STATIC_ASSERT(4 == sizeof(T)); -- return PrimitiveConversions::cast( -- _Atomic_xchg(PrimitiveConversions::cast(exchange_value), -- reinterpret_cast(dest))); --} -- --template<> --template --inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest, -- T exchange_value, -- atomic_memory_order order) const { -- STATIC_ASSERT(8 == sizeof(T)); -- return PrimitiveConversions::cast( -- _Atomic_xchg_long(PrimitiveConversions::cast(exchange_value), -- reinterpret_cast(dest))); --} -- --// Not using cmpxchg_using_helper here, because some configurations of --// Solaris compiler don't deal well with passing a "defined in .il" --// function as an argument. We *should* switch to using gcc-style --// inline assembly, but attempting to do so with Studio 12.4 ran into --// segfaults. -- --template<> --template --inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest, -- T compare_value, -- T exchange_value, -- atomic_memory_order order) const { -- STATIC_ASSERT(1 == sizeof(T)); -- return PrimitiveConversions::cast( -- _Atomic_cmpxchg_byte(PrimitiveConversions::cast(exchange_value), -- reinterpret_cast(dest), -- PrimitiveConversions::cast(compare_value))); --} -- --template<> --template --inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest, -- T compare_value, -- T exchange_value, -- atomic_memory_order order) const { -- STATIC_ASSERT(4 == sizeof(T)); -- return PrimitiveConversions::cast( -- _Atomic_cmpxchg(PrimitiveConversions::cast(exchange_value), -- reinterpret_cast(dest), -- PrimitiveConversions::cast(compare_value))); --} -- --template<> --template --inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, -- T compare_value, -- T exchange_value, -- atomic_memory_order order) const { -- STATIC_ASSERT(8 == sizeof(T)); -- return PrimitiveConversions::cast( -- _Atomic_cmpxchg_long(PrimitiveConversions::cast(exchange_value), -- reinterpret_cast(dest), -- PrimitiveConversions::cast(compare_value))); --} -- --#endif // OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp 2020-05-20 18:09:57.609548227 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,60 +0,0 @@ --/* -- * Copyright (c) 1998, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP -- --extern "C" { -- inline u2 _raw_swap_u2(u2 x) { -- unsigned short int __dest; -- __asm__ ("rorw $8, %w0": "=r" (__dest): "0" (x): "cc"); -- return __dest; -- } -- inline u4 _raw_swap_u4(u4 x) { -- unsigned int __dest; -- __asm__ ("bswap %0" : "=r" (__dest) : "0" (x)); -- return __dest; -- } -- inline u8 _raw_swap_u8(u8 x) { -- unsigned long __dest; -- __asm__ ("bswap %q0" : "=r" (__dest) : "0" (x)); -- return __dest; -- } --} -- --// Efficient swapping of data bytes from Java byte --// ordering to native byte ordering and vice versa. --inline u2 Bytes::swap_u2(u2 x) { -- return _raw_swap_u2(x); --} -- --inline u4 Bytes::swap_u4(u4 x) { -- return _raw_swap_u4(x); --} -- --inline u8 Bytes::swap_u8(u8 x) { -- return _raw_swap_u8(x); --} -- --#endif // OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp 2020-05-20 18:09:58.313561743 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,30 +0,0 @@ --/* -- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP -- --// now in central copy_x86.hpp -- --#endif // OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp 2020-05-20 18:09:59.705588468 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,40 +0,0 @@ --/* -- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP -- --// Sets the default values for platform dependent flags used by the runtime system. --// (see globals.hpp) -- --define_pd_global(bool, DontYieldALot, true); // Determined in the design center --define_pd_global(intx, CompilerThreadStackSize, 1024); --define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default --define_pd_global(intx, VMThreadStackSize, 1024); --define_pd_global(size_t, JVMInvokeMethodSlack, 8*K); -- --// Used on 64 bit platforms for UseCompressedOops base address --define_pd_global(size_t, HeapBaseMinAddress, 2*G); -- --#endif // OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp 2020-05-20 18:10:00.453602829 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,58 +0,0 @@ --/* -- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP -- --// Included in orderAccess.hpp header file. -- --// Compiler version last used for testing: solaris studio 12u3 --// Please update this information when this file changes -- --// Implementation of class OrderAccess. -- --// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions --inline void compiler_barrier() { -- __asm__ volatile ("" : : : "memory"); --} -- --inline void OrderAccess::loadload() { compiler_barrier(); } --inline void OrderAccess::storestore() { compiler_barrier(); } --inline void OrderAccess::loadstore() { compiler_barrier(); } --inline void OrderAccess::storeload() { fence(); } -- --inline void OrderAccess::acquire() { compiler_barrier(); } --inline void OrderAccess::release() { compiler_barrier(); } -- --inline void OrderAccess::fence() { -- __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); -- compiler_barrier(); --} -- --inline void OrderAccess::cross_modify_fence_impl() { -- int idx = 0; -- __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory"); --} -- --#endif // OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp 2020-05-20 18:10:01.145616115 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,662 +0,0 @@ --/* -- * Copyright (c) 1999, 2020, Oracle and/or its affiliates. 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. -- * -- */ -- --// no precompiled headers --#include "jvm.h" --#include "asm/macroAssembler.hpp" --#include "classfile/classLoader.hpp" --#include "classfile/systemDictionary.hpp" --#include "classfile/vmSymbols.hpp" --#include "code/codeCache.hpp" --#include "code/icBuffer.hpp" --#include "code/vtableStubs.hpp" --#include "interpreter/interpreter.hpp" --#include "logging/log.hpp" --#include "memory/allocation.inline.hpp" --#include "os_solaris.hpp" --#include "os_posix.hpp" --#include "prims/jniFastGetField.hpp" --#include "prims/jvm_misc.hpp" --#include "runtime/arguments.hpp" --#include "runtime/frame.inline.hpp" --#include "runtime/interfaceSupport.inline.hpp" --#include "runtime/java.hpp" --#include "runtime/javaCalls.hpp" --#include "runtime/mutexLocker.hpp" --#include "runtime/osThread.hpp" --#include "runtime/safepointMechanism.hpp" --#include "runtime/sharedRuntime.hpp" --#include "runtime/stubRoutines.hpp" --#include "runtime/thread.inline.hpp" --#include "runtime/timer.hpp" --#include "signals_posix.hpp" --#include "utilities/align.hpp" --#include "utilities/events.hpp" --#include "utilities/vmError.hpp" -- --// put OS-includes here --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include --# include -- -- --#define MAX_PATH (2 * K) -- --// Minimum usable stack sizes required to get to user code. Space for --// HotSpot guard pages is added later. --#ifdef _LP64 --// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler --// threads requires a large stack with the Solaris Studio C++ compiler version 5.13 --// and product VM builds (debug builds require significantly less stack space). --size_t os::_compiler_thread_min_stack_allowed = 325 * K; --size_t os::_java_thread_min_stack_allowed = 48 * K; --size_t os::_vm_internal_thread_min_stack_allowed = 224 * K; --#else --size_t os::_compiler_thread_min_stack_allowed = 32 * K; --size_t os::_java_thread_min_stack_allowed = 32 * K; --size_t os::_vm_internal_thread_min_stack_allowed = 64 * K; --#endif // _LP64 -- --#ifdef AMD64 --#define REG_SP REG_RSP --#define REG_PC REG_RIP --#define REG_FP REG_RBP --#else --#define REG_SP UESP --#define REG_PC EIP --#define REG_FP EBP --// 4900493 counter to prevent runaway LDTR refresh attempt -- --static volatile int ldtr_refresh = 0; --// the libthread instruction that faults because of the stale LDTR -- --static const unsigned char movlfs[] = { 0x8e, 0xe0 // movl %eax,%fs -- }; --#endif // AMD64 -- --char* os::non_memory_address_word() { -- // Must never look like an address returned by reserve_memory, -- // even in its subfields (as defined by the CPU immediate fields, -- // if the CPU splits constants across multiple instructions). -- return (char*) -1; --} -- --// --// Validate a ucontext retrieved from walking a uc_link of a ucontext. --// There are issues with libthread giving out uc_links for different threads --// on the same uc_link chain and bad or circular links. --// --bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) { -- if (valid >= suspect || -- valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags || -- valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp || -- valid->uc_stack.ss_size != suspect->uc_stack.ss_size) { -- DEBUG_ONLY(tty->print_cr("valid_ucontext: failed test 1");) -- return false; -- } -- -- if (thread->is_Java_thread()) { -- if (!thread->is_in_full_stack_checked((address)suspect)) { -- DEBUG_ONLY(tty->print_cr("valid_ucontext: uc_link not in thread stack");) -- return false; -- } -- if (!thread->is_in_full_stack_checked((address) suspect->uc_mcontext.gregs[REG_SP])) { -- DEBUG_ONLY(tty->print_cr("valid_ucontext: stackpointer not in thread stack");) -- return false; -- } -- } -- return true; --} -- --// We will only follow one level of uc_link since there are libthread --// issues with ucontext linking and it is better to be safe and just --// let caller retry later. --const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, -- const ucontext_t *uc) { -- -- const ucontext_t *retuc = NULL; -- -- if (uc != NULL) { -- if (uc->uc_link == NULL) { -- // cannot validate without uc_link so accept current ucontext -- retuc = uc; -- } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { -- // first ucontext is valid so try the next one -- uc = uc->uc_link; -- if (uc->uc_link == NULL) { -- // cannot validate without uc_link so accept current ucontext -- retuc = uc; -- } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { -- // the ucontext one level down is also valid so return it -- retuc = uc; -- } -- } -- } -- return retuc; --} -- --void os::Posix::ucontext_set_pc(ucontext_t* uc, address pc) { -- uc->uc_mcontext.gregs [REG_PC] = (greg_t) pc; --} -- --// Assumes ucontext is valid --intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) { -- return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; --} -- --// Assumes ucontext is valid --intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) { -- return (intptr_t*)uc->uc_mcontext.gregs[REG_FP]; --} -- --address os::Posix::ucontext_get_pc(const ucontext_t *uc) { -- return (address) uc->uc_mcontext.gregs[REG_PC]; --} -- --address os::fetch_frame_from_context(const void* ucVoid, -- intptr_t** ret_sp, intptr_t** ret_fp) { -- -- address epc; -- const ucontext_t *uc = (const ucontext_t*)ucVoid; -- -- if (uc != NULL) { -- epc = os::Posix::ucontext_get_pc(uc); -- if (ret_sp) *ret_sp = os::Solaris::ucontext_get_sp(uc); -- if (ret_fp) *ret_fp = os::Solaris::ucontext_get_fp(uc); -- } else { -- epc = NULL; -- if (ret_sp) *ret_sp = (intptr_t *)NULL; -- if (ret_fp) *ret_fp = (intptr_t *)NULL; -- } -- -- return epc; --} -- --frame os::fetch_frame_from_context(const void* ucVoid) { -- intptr_t* sp; -- intptr_t* fp; -- address epc = fetch_frame_from_context(ucVoid, &sp, &fp); -- return frame(sp, fp, epc); --} -- --bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) { -- address pc = (address) os::Solaris::ucontext_get_pc(uc); -- if (Interpreter::contains(pc)) { -- // interpreter performs stack banging after the fixed frame header has -- // been generated while the compilers perform it before. To maintain -- // semantic consistency between interpreted and compiled frames, the -- // method returns the Java sender of the current frame. -- *fr = os::fetch_frame_from_context(uc); -- if (!fr->is_first_java_frame()) { -- // get_frame_at_stack_banging_point() is only called when we -- // have well defined stacks so java_sender() calls do not need -- // to assert safe_for_sender() first. -- *fr = fr->java_sender(); -- } -- } else { -- // more complex code with compiled code -- assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above"); -- CodeBlob* cb = CodeCache::find_blob(pc); -- if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) { -- // Not sure where the pc points to, fallback to default -- // stack overflow handling -- return false; -- } else { -- // in compiled code, the stack banging is performed just after the return pc -- // has been pushed on the stack -- intptr_t* fp = os::Solaris::ucontext_get_fp(uc); -- intptr_t* sp = os::Solaris::ucontext_get_sp(uc); -- *fr = frame(sp + 1, fp, (address)*sp); -- if (!fr->is_java_frame()) { -- // See java_sender() comment above. -- *fr = fr->java_sender(); -- } -- } -- } -- assert(fr->is_java_frame(), "Safety check"); -- return true; --} -- --frame os::get_sender_for_C_frame(frame* fr) { -- return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); --} -- --extern "C" intptr_t *_get_current_sp() { -- register intptr_t *rsp __asm__ ("rsp"); -- return rsp; --} -- --address os::current_stack_pointer() { -- return (address)_get_current_sp(); --} -- --extern "C" intptr_t *_get_current_fp() { -- register intptr_t **rbp __asm__ ("rbp"); -- return (intptr_t*) *rbp; --} -- --frame os::current_frame() { -- intptr_t* fp = _get_current_fp(); // it's inlined so want current fp -- // fp is for os::current_frame. We want the fp for our caller. -- frame myframe((intptr_t*)os::current_stack_pointer(), -- (intptr_t*)fp, -- CAST_FROM_FN_PTR(address, os::current_frame)); -- frame caller_frame = os::get_sender_for_C_frame(&myframe); -- -- if (os::is_first_C_frame(&caller_frame)) { -- // stack is not walkable -- frame ret; // This will be a null useless frame -- return ret; -- } else { -- // return frame for our caller's caller -- return os::get_sender_for_C_frame(&caller_frame); -- } --} -- -- --bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, -- ucontext_t* uc, JavaThread* thread) { -- -- if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { -- // can't decode this kind of signal -- info = NULL; -- } else { -- assert(sig == info->si_signo, "bad siginfo"); -- } -- -- // decide if this trap can be handled by a stub -- address stub = NULL; -- -- address pc = NULL; -- -- //%note os_trap_1 -- if (info != NULL && uc != NULL && thread != NULL) { -- // factor me: getPCfromContext -- pc = (address) uc->uc_mcontext.gregs[REG_PC]; -- -- // Handle ALL stack overflow variations here -- if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { -- address addr = (address) info->si_addr; -- if (thread->in_stack_yellow_reserved_zone(addr)) { -- if (thread->thread_state() == _thread_in_Java) { -- if (thread->in_stack_reserved_zone(addr)) { -- frame fr; -- if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) { -- assert(fr.is_java_frame(), "Must be Java frame"); -- frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr); -- if (activation.sp() != NULL) { -- thread->disable_stack_reserved_zone(); -- if (activation.is_interpreted_frame()) { -- thread->set_reserved_stack_activation((address)( -- activation.fp() + frame::interpreter_frame_initial_sp_offset)); -- } else { -- thread->set_reserved_stack_activation((address)activation.unextended_sp()); -- } -- return true; -- } -- } -- } -- // Throw a stack overflow exception. Guard pages will be reenabled -- // while unwinding the stack. -- thread->disable_stack_yellow_reserved_zone(); -- stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW); -- } else { -- // Thread was in the vm or native code. Return and try to finish. -- thread->disable_stack_yellow_reserved_zone(); -- return true; -- } -- } else if (thread->in_stack_red_zone(addr)) { -- // Fatal red zone violation. Disable the guard pages and fall through -- // to handle_unexpected_exception way down below. -- thread->disable_stack_red_zone(); -- tty->print_raw_cr("An irrecoverable stack overflow has occurred."); -- } -- } -- -- if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { -- // Verify that OS save/restore AVX registers. -- stub = VM_Version::cpuinfo_cont_addr(); -- } -- -- if (thread->thread_state() == _thread_in_vm || -- thread->thread_state() == _thread_in_native) { -- if (sig == SIGBUS && info->si_code == BUS_OBJERR && thread->doing_unsafe_access()) { -- address next_pc = Assembler::locate_next_instruction(pc); -- if (UnsafeCopyMemory::contains_pc(pc)) { -- next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); -- } -- stub = SharedRuntime::handle_unsafe_access(thread, next_pc); -- } -- } -- -- if (thread->thread_state() == _thread_in_Java) { -- // Support Safepoint Polling -- if ( sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) { -- stub = SharedRuntime::get_poll_stub(pc); -- } -- else if (sig == SIGBUS && info->si_code == BUS_OBJERR) { -- // BugId 4454115: A read from a MappedByteBuffer can fault -- // here if the underlying file has been truncated. -- // Do not crash the VM in such a case. -- CodeBlob* cb = CodeCache::find_blob(pc); -- if (cb != NULL) { -- CompiledMethod* nm = cb->as_compiled_method_or_null(); -- bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc); -- if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) { -- address next_pc = Assembler::locate_next_instruction(pc); -- if (is_unsafe_arraycopy) { -- next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); -- } -- stub = SharedRuntime::handle_unsafe_access(thread, next_pc); -- } -- } -- } -- else -- if (sig == SIGFPE && info->si_code == FPE_INTDIV) { -- // integer divide by zero -- stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); -- } --#ifndef AMD64 -- else if (sig == SIGFPE && info->si_code == FPE_FLTDIV) { -- // floating-point divide by zero -- stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); -- } -- else if (sig == SIGFPE && info->si_code == FPE_FLTINV) { -- // The encoding of D2I in i486.ad can cause an exception prior -- // to the fist instruction if there was an invalid operation -- // pending. We want to dismiss that exception. From the win_32 -- // side it also seems that if it really was the fist causing -- // the exception that we do the d2i by hand with different -- // rounding. Seems kind of weird. QQQ TODO -- // Note that we take the exception at the NEXT floating point instruction. -- if (pc[0] == 0xDB) { -- assert(pc[0] == 0xDB, "not a FIST opcode"); -- assert(pc[1] == 0x14, "not a FIST opcode"); -- assert(pc[2] == 0x24, "not a FIST opcode"); -- return true; -- } else { -- assert(pc[-3] == 0xDB, "not an flt invalid opcode"); -- assert(pc[-2] == 0x14, "not an flt invalid opcode"); -- assert(pc[-1] == 0x24, "not an flt invalid opcode"); -- } -- } -- else if (sig == SIGFPE ) { -- tty->print_cr("caught SIGFPE, info 0x%x.", info->si_code); -- } --#endif // !AMD64 -- -- // QQQ It doesn't seem that we need to do this on x86 because we should be able -- // to return properly from the handler without this extra stuff on the back side. -- -- else if (sig == SIGSEGV && info->si_code > 0 && -- MacroAssembler::uses_implicit_null_check(info->si_addr)) { -- // Determination of interpreter/vtable stub/compiled code null exception -- stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); -- } -- } -- -- // jni_fast_GetField can trap at certain pc's if a GC kicks in -- // and the heap gets shrunk before the field access. -- if ((sig == SIGSEGV) || (sig == SIGBUS)) { -- address addr = JNI_FastGetField::find_slowcase_pc(pc); -- if (addr != (address)-1) { -- stub = addr; -- } -- } -- } -- -- // Execution protection violation -- // -- // Preventative code for future versions of Solaris which may -- // enable execution protection when running the 32-bit VM on AMD64. -- // -- // This should be kept as the last step in the triage. We don't -- // have a dedicated trap number for a no-execute fault, so be -- // conservative and allow other handlers the first shot. -- // -- // Note: We don't test that info->si_code == SEGV_ACCERR here. -- // this si_code is so generic that it is almost meaningless; and -- // the si_code for this condition may change in the future. -- // Furthermore, a false-positive should be harmless. -- if (UnguardOnExecutionViolation > 0 && -- (sig == SIGSEGV || sig == SIGBUS) && -- uc->uc_mcontext.gregs[TRAPNO] == T_PGFLT) { // page fault -- int page_size = os::vm_page_size(); -- address addr = (address) info->si_addr; -- address pc = (address) uc->uc_mcontext.gregs[REG_PC]; -- // Make sure the pc and the faulting address are sane. -- // -- // If an instruction spans a page boundary, and the page containing -- // the beginning of the instruction is executable but the following -- // page is not, the pc and the faulting address might be slightly -- // different - we still want to unguard the 2nd page in this case. -- // -- // 15 bytes seems to be a (very) safe value for max instruction size. -- bool pc_is_near_addr = -- (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); -- bool instr_spans_page_boundary = -- (align_down((intptr_t) pc ^ (intptr_t) addr, -- (intptr_t) page_size) > 0); -- -- if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) { -- static volatile address last_addr = -- (address) os::non_memory_address_word(); -- -- // In conservative mode, don't unguard unless the address is in the VM -- if (addr != last_addr && -- (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { -- -- // Make memory rwx and retry -- address page_start = align_down(addr, page_size); -- bool res = os::protect_memory((char*) page_start, page_size, -- os::MEM_PROT_RWX); -- -- log_debug(os)("Execution protection violation " -- "at " INTPTR_FORMAT -- ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), -- p2i(page_start), (res ? "success" : "failed"), errno); -- stub = pc; -- -- // Set last_addr so if we fault again at the same address, we don't end -- // up in an endless loop. -- // -- // There are two potential complications here. Two threads trapping at -- // the same address at the same time could cause one of the threads to -- // think it already unguarded, and abort the VM. Likely very rare. -- // -- // The other race involves two threads alternately trapping at -- // different addresses and failing to unguard the page, resulting in -- // an endless loop. This condition is probably even more unlikely than -- // the first. -- // -- // Although both cases could be avoided by using locks or thread local -- // last_addr, these solutions are unnecessary complication: this -- // handler is a best-effort safety net, not a complete solution. It is -- // disabled by default and should only be used as a workaround in case -- // we missed any no-execute-unsafe VM code. -- -- last_addr = addr; -- } -- } -- } -- -- if (stub != NULL) { -- // save all thread context in case we need to restore it -- -- if (thread != NULL) thread->set_saved_exception_pc(pc); -- // 12/02/99: On Sparc it appears that the full context is also saved -- // but as yet, no one looks at or restores that saved context -- os::Posix::ucontext_set_pc(uc, stub); -- return true; -- } -- -- return false; --} -- --void os::print_context(outputStream *st, const void *context) { -- if (context == NULL) return; -- -- const ucontext_t *uc = (const ucontext_t*)context; -- st->print_cr("Registers:"); --#ifdef AMD64 -- st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); -- st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); -- st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); -- st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); -- st->cr(); -- st->print( "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); -- st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); -- st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); -- st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); -- st->cr(); -- st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); -- st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); -- st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); -- st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); -- st->cr(); -- st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); -- st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); -- st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); -- st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); -- st->cr(); -- st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); -- st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]); --#else -- st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); -- st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); -- st->print(", ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ECX]); -- st->print(", EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDX]); -- st->cr(); -- st->print( "ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[UESP]); -- st->print(", EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBP]); -- st->print(", ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ESI]); -- st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDI]); -- st->cr(); -- st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]); -- st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]); --#endif // AMD64 -- st->cr(); -- st->cr(); --} -- --void os::print_tos_pc(outputStream *st, const void *context) { -- if (context == NULL) return; -- -- const ucontext_t* uc = (const ucontext_t*)context; -- -- intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); -- st->print_cr("Top of Stack: (sp=" INTPTR_FORMAT ")", (intptr_t)sp); -- print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t)); -- st->cr(); -- -- // Note: it may be unsafe to inspect memory near pc. For example, pc may -- // point to garbage if entry point in an nmethod is corrupted. Leave -- // this at the end, and hope for the best. -- address pc = os::Posix::ucontext_get_pc(uc); -- print_instructions(st, pc, sizeof(char)); -- st->cr(); --} -- --void os::print_register_info(outputStream *st, const void *context, int& continuation) { -- const int register_count = AMD64_ONLY(16) NOT_AMD64(8); -- int n = continuation; -- assert(n >= 0 && n <= register_count, "Invalid continuation value"); -- if (context == nullptr || n == register_count) { -- return; -- } -- -- const ucontext_t *uc = (const ucontext_t*)context; -- while (n < register_count) { -- // Update continuation with next index before printing location -- continuation = n + 1; --# define CASE_PRINT_REG(n, str, id) case n: st->print(str); print_location(st, uc->uc_mcontext.gregs[REG_##id]); -- switch (n) { --#ifdef AMD64 -- CASE_PRINT_REG( 0, "RAX=", RAX); break; -- CASE_PRINT_REG( 1, "RBX=", RBX); break; -- CASE_PRINT_REG( 2, "RCX=", RCX); break; -- CASE_PRINT_REG( 3, "RDX=", RDX); break; -- CASE_PRINT_REG( 4, "RSP=", RSP); break; -- CASE_PRINT_REG( 5, "RBP=", RBP); break; -- CASE_PRINT_REG( 6, "RSI=", RSI); break; -- CASE_PRINT_REG( 7, "RDI=", RDI); break; -- CASE_PRINT_REG( 8, "R8 =", R8); break; -- CASE_PRINT_REG( 9, "R9 =", R9); break; -- CASE_PRINT_REG(10, "R10=", R10); break; -- CASE_PRINT_REG(11, "R11=", R11); break; -- CASE_PRINT_REG(12, "R12=", R12); break; -- CASE_PRINT_REG(13, "R13=", R13); break; -- CASE_PRINT_REG(14, "R14=", R14); break; -- CASE_PRINT_REG(15, "R15=", R15); break; --#else -- CASE_PRINT_REG(0, "EAX=", EAX); break; -- CASE_PRINT_REG(1, "EBX=", EBX); break; -- CASE_PRINT_REG(2, "ECX=", ECX); break; -- CASE_PRINT_REG(3, "EDX=", EDX); break; -- CASE_PRINT_REG(4, "ESP=", ESP); break; -- CASE_PRINT_REG(5, "EBP=", EBP); break; -- CASE_PRINT_REG(6, "ESI=", ESI); break; -- CASE_PRINT_REG(7, "EDI=", EDI); break; --#endif // AMD64 -- } --# undef CASE_PRINT_REG -- ++n; -- } --} -- -- --void os::Solaris::init_thread_fpu_state(void) { -- // Nothing to do --} --void os::setup_fpu() {} -- --#ifndef PRODUCT --void os::verify_stack_alignment() { -- assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); --} --#endif -- --int os::extra_bang_size_in_bytes() { -- // JDK-8050147 requires the full cache line bang for x86. -- return VM_Version::L1_line_size(); --} ---- old/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp 2020-05-20 18:10:01.837629401 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,55 +0,0 @@ --/* -- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP -- -- // -- // NOTE: we are back in class os here, not Solaris -- // --#ifdef AMD64 -- static void setup_fpu() {} --#else -- static int32_t (*atomic_xchg_func) (int32_t, volatile int32_t*); -- static int32_t (*atomic_cmpxchg_func) (int32_t, volatile int32_t*, int32_t); -- static int64_t (*atomic_cmpxchg_long_func)(int64_t, volatile int64_t*, int64_t); -- static int32_t (*atomic_add_func) (int32_t, volatile int32_t*); -- -- static int32_t atomic_xchg_bootstrap (int32_t, volatile int32_t*); -- static int32_t atomic_cmpxchg_bootstrap (int32_t, volatile int32_t*, int32_t); -- static int64_t atomic_cmpxchg_long_bootstrap(int64_t, volatile int64_t*, int64_t); -- static int32_t atomic_add_bootstrap (int32_t, volatile int32_t*); -- -- static void setup_fpu(); --#endif // AMD64 -- -- static jlong rdtsc(); -- -- static bool is_allocatable(size_t bytes); -- -- // Used to register dynamic code cache area with the OS -- // Note: Currently only used in 64 bit Windows implementations -- static bool register_code_area(char *low, char *high) { return true; } -- --#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp 2020-05-20 18:10:02.505642227 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,39 +0,0 @@ --/* -- * Copyright (c) 2011, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP --#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP -- --#include "runtime/os.hpp" -- --// See http://www.technovelty.org/code/c/reading-rdtsc.htl for details --inline jlong os::rdtsc() { -- uint64_t res; -- uint32_t ts1, ts2; -- __asm__ __volatile__ ("rdtsc" : "=a" (ts1), "=d" (ts2)); -- res = ((uint64_t)ts1 | (uint64_t)ts2 << 32); -- return (jlong)res; --} -- --#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP ---- old/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp 2020-05-20 18:10:03.249656511 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,42 +0,0 @@ --/* -- * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP --#define OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP -- --#include "runtime/prefetch.hpp" -- --inline void Prefetch::read (const void *loc, intx interval) { --#ifdef AMD64 -- __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); --#endif // AMD64 --} -- --inline void Prefetch::write(void *loc, intx interval) { --#ifdef AMD64 -- __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); --#endif // AMD64 --} -- --#endif // OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP ---- old/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S 2020-05-20 18:10:04.733685002 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,386 +0,0 @@ --# --# Copyright (c) 2004, 2013, Oracle and/or its affiliates. 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. --# -- -- .globl fs_load -- .globl fs_thread -- -- ## NOTE WELL! The _Copy functions are called directly -- ## from server-compiler-generated code via CallLeafNoFP, -- ## which means that they *must* either not use floating -- ## point or use it in the same manner as does the server -- ## compiler. -- -- .globl _Copy_arrayof_conjoint_bytes -- .globl _Copy_conjoint_jshorts_atomic -- .globl _Copy_arrayof_conjoint_jshorts -- .globl _Copy_conjoint_jints_atomic -- .globl _Copy_arrayof_conjoint_jints -- .globl _Copy_conjoint_jlongs_atomic -- .globl _Copy_arrayof_conjoint_jlongs -- -- .section .text,"ax" -- -- # Fast thread accessors, used by threadLS_solaris_amd64.cpp -- .align 16 --fs_load: -- movq %fs:(%rdi),%rax -- ret -- -- .align 16 --fs_thread: -- movq %fs:0x0,%rax -- ret -- -- .globl SpinPause -- .align 16 --SpinPause: -- rep -- nop -- movq $1, %rax -- ret -- -- -- # Support for void Copy::arrayof_conjoint_bytes(void* from, -- # void* to, -- # size_t count) -- # rdi - from -- # rsi - to -- # rdx - count, treated as ssize_t -- # -- .align 16 --_Copy_arrayof_conjoint_bytes: -- movq %rdx,%r8 # byte count -- shrq $3,%rdx # qword count -- cmpq %rdi,%rsi -- leaq -1(%rdi,%r8,1),%rax # from + bcount*1 - 1 -- jbe acb_CopyRight -- cmpq %rax,%rsi -- jbe acb_CopyLeft --acb_CopyRight: -- leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 -- leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 -- negq %rdx -- jmp 7f -- .align 16 --1: movq 8(%rax,%rdx,8),%rsi -- movq %rsi,8(%rcx,%rdx,8) -- addq $1,%rdx -- jnz 1b --2: testq $4,%r8 # check for trailing dword -- jz 3f -- movl 8(%rax),%esi # copy trailing dword -- movl %esi,8(%rcx) -- addq $4,%rax -- addq $4,%rcx # original %rsi is trashed, so we -- # can't use it as a base register --3: testq $2,%r8 # check for trailing word -- jz 4f -- movw 8(%rax),%si # copy trailing word -- movw %si,8(%rcx) -- addq $2,%rcx --4: testq $1,%r8 # check for trailing byte -- jz 5f -- movb -1(%rdi,%r8,1),%al # copy trailing byte -- movb %al,8(%rcx) --5: ret -- .align 16 --6: movq -24(%rax,%rdx,8),%rsi -- movq %rsi,-24(%rcx,%rdx,8) -- movq -16(%rax,%rdx,8),%rsi -- movq %rsi,-16(%rcx,%rdx,8) -- movq -8(%rax,%rdx,8),%rsi -- movq %rsi,-8(%rcx,%rdx,8) -- movq (%rax,%rdx,8),%rsi -- movq %rsi,(%rcx,%rdx,8) --7: addq $4,%rdx -- jle 6b -- subq $4,%rdx -- jl 1b -- jmp 2b --acb_CopyLeft: -- testq $1,%r8 # check for trailing byte -- jz 1f -- movb -1(%rdi,%r8,1),%cl # copy trailing byte -- movb %cl,-1(%rsi,%r8,1) -- subq $1,%r8 # adjust for possible trailing word --1: testq $2,%r8 # check for trailing word -- jz 2f -- movw -2(%rdi,%r8,1),%cx # copy trailing word -- movw %cx,-2(%rsi,%r8,1) --2: testq $4,%r8 # check for trailing dword -- jz 5f -- movl (%rdi,%rdx,8),%ecx # copy trailing dword -- movl %ecx,(%rsi,%rdx,8) -- jmp 5f -- .align 16 --3: movq -8(%rdi,%rdx,8),%rcx -- movq %rcx,-8(%rsi,%rdx,8) -- subq $1,%rdx -- jnz 3b -- ret -- .align 16 --4: movq 24(%rdi,%rdx,8),%rcx -- movq %rcx,24(%rsi,%rdx,8) -- movq 16(%rdi,%rdx,8),%rcx -- movq %rcx,16(%rsi,%rdx,8) -- movq 8(%rdi,%rdx,8),%rcx -- movq %rcx,8(%rsi,%rdx,8) -- movq (%rdi,%rdx,8),%rcx -- movq %rcx,(%rsi,%rdx,8) --5: subq $4,%rdx -- jge 4b -- addq $4,%rdx -- jg 3b -- ret -- -- # Support for void Copy::arrayof_conjoint_jshorts(void* from, -- # void* to, -- # size_t count) -- # Equivalent to -- # conjoint_jshorts_atomic -- # -- # If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we -- # let the hardware handle it. The tow or four words within dwords -- # or qwords that span cache line boundaries will still be loaded -- # and stored atomically. -- # -- # rdi - from -- # rsi - to -- # rdx - count, treated as ssize_t -- # -- .align 16 --_Copy_arrayof_conjoint_jshorts: --_Copy_conjoint_jshorts_atomic: -- movq %rdx,%r8 # word count -- shrq $2,%rdx # qword count -- cmpq %rdi,%rsi -- leaq -2(%rdi,%r8,2),%rax # from + wcount*2 - 2 -- jbe acs_CopyRight -- cmpq %rax,%rsi -- jbe acs_CopyLeft --acs_CopyRight: -- leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 -- leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 -- negq %rdx -- jmp 6f --1: movq 8(%rax,%rdx,8),%rsi -- movq %rsi,8(%rcx,%rdx,8) -- addq $1,%rdx -- jnz 1b --2: testq $2,%r8 # check for trailing dword -- jz 3f -- movl 8(%rax),%esi # copy trailing dword -- movl %esi,8(%rcx) -- addq $4,%rcx # original %rsi is trashed, so we -- # can't use it as a base register --3: testq $1,%r8 # check for trailing word -- jz 4f -- movw -2(%rdi,%r8,2),%si # copy trailing word -- movw %si,8(%rcx) --4: ret -- .align 16 --5: movq -24(%rax,%rdx,8),%rsi -- movq %rsi,-24(%rcx,%rdx,8) -- movq -16(%rax,%rdx,8),%rsi -- movq %rsi,-16(%rcx,%rdx,8) -- movq -8(%rax,%rdx,8),%rsi -- movq %rsi,-8(%rcx,%rdx,8) -- movq (%rax,%rdx,8),%rsi -- movq %rsi,(%rcx,%rdx,8) --6: addq $4,%rdx -- jle 5b -- subq $4,%rdx -- jl 1b -- jmp 2b --acs_CopyLeft: -- testq $1,%r8 # check for trailing word -- jz 1f -- movw -2(%rdi,%r8,2),%cx # copy trailing word -- movw %cx,-2(%rsi,%r8,2) --1: testq $2,%r8 # check for trailing dword -- jz 4f -- movl (%rdi,%rdx,8),%ecx # copy trailing dword -- movl %ecx,(%rsi,%rdx,8) -- jmp 4f --2: movq -8(%rdi,%rdx,8),%rcx -- movq %rcx,-8(%rsi,%rdx,8) -- subq $1,%rdx -- jnz 2b -- ret -- .align 16 --3: movq 24(%rdi,%rdx,8),%rcx -- movq %rcx,24(%rsi,%rdx,8) -- movq 16(%rdi,%rdx,8),%rcx -- movq %rcx,16(%rsi,%rdx,8) -- movq 8(%rdi,%rdx,8),%rcx -- movq %rcx,8(%rsi,%rdx,8) -- movq (%rdi,%rdx,8),%rcx -- movq %rcx,(%rsi,%rdx,8) --4: subq $4,%rdx -- jge 3b -- addq $4,%rdx -- jg 2b -- ret -- -- # Support for void Copy::arrayof_conjoint_jints(jint* from, -- # jint* to, -- # size_t count) -- # Equivalent to -- # conjoint_jints_atomic -- # -- # If 'from' and/or 'to' are aligned on 4-byte boundaries, we let -- # the hardware handle it. The two dwords within qwords that span -- # cache line boundaries will still be loaded and stored atomically. -- # -- # rdi - from -- # rsi - to -- # rdx - count, treated as ssize_t -- # -- .align 16 --_Copy_arrayof_conjoint_jints: --_Copy_conjoint_jints_atomic: -- movq %rdx,%r8 # dword count -- shrq %rdx # qword count -- cmpq %rdi,%rsi -- leaq -4(%rdi,%r8,4),%rax # from + dcount*4 - 4 -- jbe aci_CopyRight -- cmpq %rax,%rsi -- jbe aci_CopyLeft --aci_CopyRight: -- leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 -- leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 -- negq %rdx -- jmp 5f -- .align 16 --1: movq 8(%rax,%rdx,8),%rsi -- movq %rsi,8(%rcx,%rdx,8) -- addq $1,%rdx -- jnz 1b --2: testq $1,%r8 # check for trailing dword -- jz 3f -- movl 8(%rax),%esi # copy trailing dword -- movl %esi,8(%rcx) --3: ret -- .align 16 --4: movq -24(%rax,%rdx,8),%rsi -- movq %rsi,-24(%rcx,%rdx,8) -- movq -16(%rax,%rdx,8),%rsi -- movq %rsi,-16(%rcx,%rdx,8) -- movq -8(%rax,%rdx,8),%rsi -- movq %rsi,-8(%rcx,%rdx,8) -- movq (%rax,%rdx,8),%rsi -- movq %rsi,(%rcx,%rdx,8) --5: addq $4,%rdx -- jle 4b -- subq $4,%rdx -- jl 1b -- jmp 2b --aci_CopyLeft: -- testq $1,%r8 # check for trailing dword -- jz 3f -- movl -4(%rdi,%r8,4),%ecx # copy trailing dword -- movl %ecx,-4(%rsi,%r8,4) -- jmp 3f --1: movq -8(%rdi,%rdx,8),%rcx -- movq %rcx,-8(%rsi,%rdx,8) -- subq $1,%rdx -- jnz 1b -- ret -- .align 16 --2: movq 24(%rdi,%rdx,8),%rcx -- movq %rcx,24(%rsi,%rdx,8) -- movq 16(%rdi,%rdx,8),%rcx -- movq %rcx,16(%rsi,%rdx,8) -- movq 8(%rdi,%rdx,8),%rcx -- movq %rcx,8(%rsi,%rdx,8) -- movq (%rdi,%rdx,8),%rcx -- movq %rcx,(%rsi,%rdx,8) --3: subq $4,%rdx -- jge 2b -- addq $4,%rdx -- jg 1b -- ret -- -- # Support for void Copy::arrayof_conjoint_jlongs(jlong* from, -- # jlong* to, -- # size_t count) -- # Equivalent to -- # conjoint_jlongs_atomic -- # arrayof_conjoint_oops -- # conjoint_oops_atomic -- # -- # rdi - from -- # rsi - to -- # rdx - count, treated as ssize_t -- # -- .align 16 --_Copy_arrayof_conjoint_jlongs: --_Copy_conjoint_jlongs_atomic: -- cmpq %rdi,%rsi -- leaq -8(%rdi,%rdx,8),%rax # from + count*8 - 8 -- jbe acl_CopyRight -- cmpq %rax,%rsi -- jbe acl_CopyLeft --acl_CopyRight: -- leaq -8(%rsi,%rdx,8),%rcx # to + count*8 - 8 -- negq %rdx -- jmp 3f --1: movq 8(%rax,%rdx,8),%rsi -- movq %rsi,8(%rcx,%rdx,8) -- addq $1,%rdx -- jnz 1b -- ret -- .align 16 --2: movq -24(%rax,%rdx,8),%rsi -- movq %rsi,-24(%rcx,%rdx,8) -- movq -16(%rax,%rdx,8),%rsi -- movq %rsi,-16(%rcx,%rdx,8) -- movq -8(%rax,%rdx,8),%rsi -- movq %rsi,-8(%rcx,%rdx,8) -- movq (%rax,%rdx,8),%rsi -- movq %rsi,(%rcx,%rdx,8) --3: addq $4,%rdx -- jle 2b -- subq $4,%rdx -- jl 1b -- ret --4: movq -8(%rdi,%rdx,8),%rcx -- movq %rcx,-8(%rsi,%rdx,8) -- subq $1,%rdx -- jnz 4b -- ret -- .align 16 --5: movq 24(%rdi,%rdx,8),%rcx -- movq %rcx,24(%rsi,%rdx,8) -- movq 16(%rdi,%rdx,8),%rcx -- movq %rcx,16(%rsi,%rdx,8) -- movq 8(%rdi,%rdx,8),%rcx -- movq %rcx,8(%rsi,%rdx,8) -- movq (%rdi,%rdx,8),%rcx -- movq %rcx,(%rsi,%rdx,8) --acl_CopyLeft: -- subq $4,%rdx -- jge 5b -- addq $4,%rdx -- jg 4b -- ret ---- old/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.cpp 2020-05-20 18:10:05.425698288 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,97 +0,0 @@ --/* -- * Copyright (c) 2003, 2020, Oracle and/or its affiliates. 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 "runtime/frame.inline.hpp" --#include "runtime/javaThread.hpp" -- --frame JavaThread::pd_last_frame() { -- assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); -- vmassert(_anchor.last_Java_pc() != NULL, "not walkable"); -- return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); --} -- --// For Forte Analyzer AsyncGetCallTrace profiling support - thread is --// currently interrupted by SIGPROF --bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, -- void* ucontext, bool isInJava) { -- assert(Thread::current() == this, "caller must be current thread"); -- return pd_get_top_frame(fr_addr, ucontext, isInJava); --} -- --bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, -- void* ucontext, bool isInJava) { -- return pd_get_top_frame(fr_addr, ucontext, isInJava); --} -- --bool JavaThread::pd_get_top_frame(frame* fr_addr, -- void* ucontext, bool isInJava) { -- assert(this->is_Java_thread(), "must be JavaThread"); -- JavaThread* jt = (JavaThread *)this; -- -- // There is small window where last_Java_frame is not walkable or safe -- if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { -- *fr_addr = jt->pd_last_frame(); -- return true; -- } -- -- ucontext_t* uc = (ucontext_t*) ucontext; -- -- // We always want to use the initial frame we create from the ucontext as -- // it certainly signals where we currently are. However that frame may not -- // be safe for calling sender. In that case if we have a last_Java_frame -- // then the forte walker will switch to that frame as the virtual sender -- // for the frame we create here which is not sender safe. -- -- intptr_t* ret_fp; -- intptr_t* ret_sp; -- address addr = os::fetch_frame_from_context(uc, &ret_sp, &ret_fp); -- -- // Something would really have to be screwed up to get a NULL pc -- -- if (addr == NULL) { -- // ucontext wasn't useful -- return false; -- } -- -- // If sp and fp are nonsense just leave them out -- -- if (!jt->is_in_full_stack((address)ret_sp)) { -- ret_sp = NULL; -- ret_fp = NULL; -- } else { -- // sp is reasonable is fp reasonable? -- if (!jt->is_in_stack_range_incl((address)ret_fp, (address)ret_sp)) { -- ret_fp = NULL; -- } -- } -- -- frame ret_frame(ret_sp, ret_fp, addr); -- -- *fr_addr = ret_frame; -- return true; -- --} -- --void JavaThread::cache_global_variables() { } ---- old/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.hpp 2020-05-20 18:10:06.173712649 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,59 +0,0 @@ --/* -- * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_JAVATHREAD_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_JAVATHREAD_SOLARIS_X86_HPP -- -- private: -- void pd_initialize() { _anchor.clear(); } -- -- frame pd_last_frame(); -- -- public: -- -- void set_base_of_stack_pointer(intptr_t* base_sp) {} -- -- static ByteSize last_Java_fp_offset() { -- return byte_offset_of(JavaThread, _anchor) + JavaFrameAnchor::last_Java_fp_offset(); -- } -- -- intptr_t* base_of_stack_pointer() { return NULL; } -- void record_base_of_stack_pointer() {} -- -- bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, -- bool isInJava); -- bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, -- bool isInJava); --private: -- bool pd_get_top_frame(frame* fr_addr, void* ucontext, -- bool isInJava); --public: -- -- // These routines are only used on cpu architectures that -- // have separate register stacks (Itanium). -- static bool register_stack_overflow() { return false; } -- static void enable_register_stack_guard() {} -- static void disable_register_stack_guard() {} -- --#endif // OS_CPU_SOLARIS_X86_JAVATHREAD_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp 2020-05-20 18:10:06.865725935 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,40 +0,0 @@ --/* -- * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. -- * -- */ -- --#ifndef OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP --#define OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP -- --// These are the OS and CPU-specific fields, types and integer --// constants required by the Serviceability Agent. This file is --// referenced by vmStructs.cpp. -- --#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) -- --#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) -- --#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -- --#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) -- --#endif // OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP ---- old/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp 2020-05-20 18:10:07.613740296 -0700 -+++ /dev/null 2020-03-09 18:57:19.455001459 -0700 -@@ -1,28 +0,0 @@ --/* -- * Copyright (c) 2006, 2019, Oracle and/or its affiliates. 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 "runtime/os.hpp" --#include "runtime/vm_version.hpp" -- --- old/src/hotspot/share/services/dtraceAttacher.cpp 2020-05-20 18:10:08.361754658 -0700 +++ /dev/null 2020-03-09 18:57:19.455001459 -0700 @@ -1,99 +0,0 @@ @@ -14000,7 +6324,7 @@ -class EventPortSelectorImpl - extends SelectorImpl -{ -- // maximum number of events to retrive in one call to port_getn +- // maximum number of events to retrieve in one call to port_getn - static final int MAX_EVENTS = Math.min(IOUtil.fdLimit()-1, 1024); - - // port file descriptor @@ -17971,7 +10295,7 @@ - J->bcp = bcp; - - /* On x86 with C2 JVM: native frame may have wrong regs[R_FP] -- * For example: JVM_SuspendThread frame poins to the top interpreted frame. +- * For example: JVM_SuspendThread frame points to the top interpreted frame. - * If we call is_method(J, methodPtr) before codecache_contains(J, pc) - * then we go over and omit both: nmethod and I2CAdapter frames. - * Note, that regs[R_PC] is always correct if frame defined correctly. @@ -18233,7 +10557,7 @@ -// generic error messages -#define JVM_ERR_OUT_OF_MEMORY "out of memory (native heap)" -#define JVM_ERR_INVALID_PARAM "invalid input parameter(s)" --#define JVM_ERR_NULL_PARAM "input paramater is NULL" +-#define JVM_ERR_NULL_PARAM "input parameter is NULL" - -// error messages for attach -#define JVM_ERR_CANT_OPEN_DOOR "cannot open door file" diff --git a/build/openjdk21/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h b/build/openjdk21/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h deleted file mode 100644 index 6e0efc6426..0000000000 --- a/build/openjdk21/patches/patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h +++ /dev/null @@ -1,15 +0,0 @@ -$NetBSD$ - -Fix build on SunOS in C99 mode. - ---- src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h.orig 2019-01-08 12:44:59.000000000 +0000 -+++ src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h -@@ -63,7 +63,7 @@ - * Windows/Visual Studio) there is no effect; the OS specific tests below are - * still required (as of 2011-05-02.) - */ --#ifndef _POSIX_SOURCE -+#if (!defined(__sun) || (__STDC_VERSION__-0 < 199901L)) && !defined(_POSIX_SOURCE) - # define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ - #endif - diff --git a/build/openjdk21/patches/restore_os_cpu_solaris_x86.patch b/build/openjdk21/patches/restore_os_cpu_solaris_x86.patch new file mode 100644 index 0000000000..1610fa84f0 --- /dev/null +++ b/build/openjdk21/patches/restore_os_cpu_solaris_x86.patch @@ -0,0 +1,1887 @@ +diff -urN /tmp/a/assembler_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp +--- /tmp/a/assembler_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp 2024-10-15 14:59:36.868225263 +0100 +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. 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 "asm/macroAssembler.inline.hpp" ++#include "runtime/os.hpp" ++ ++void MacroAssembler::int3() { ++ push(rax); ++ push(rdx); ++ push(rcx); ++ call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint))); ++ pop(rcx); ++ pop(rdx); ++ pop(rax); ++} +diff -urN /tmp/a/atomic_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp +--- /tmp/a/atomic_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp 2024-10-15 14:59:36.868356722 +0100 +@@ -0,0 +1,182 @@ ++/* ++ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP ++ ++inline int32_t _Atomic_add(int32_t add_value, volatile int32_t* dest) { ++ int32_t rv = add_value; ++ __asm__ volatile ("lock xaddl %0,(%2)" ++ : "=r" (rv) ++ : "0" (rv), "r" (dest) ++ : "cc", "memory"); ++ return rv + add_value; ++} ++inline int64_t _Atomic_add_long(int64_t add_value, volatile int64_t* dest) { ++ int64_t rv = add_value; ++ __asm__ volatile ("lock xaddq %0,(%2)" ++ : "=r" (rv) ++ : "0" (rv), "r" (dest) ++ : "cc", "memory"); ++ return rv + add_value; ++} ++inline int32_t _Atomic_xchg(int32_t exchange_value, volatile int32_t* dest) { ++ __asm__ __volatile__ ("xchgl (%2),%0" ++ : "=r" (exchange_value) ++ : "0" (exchange_value), "r" (dest) ++ : "memory"); ++ return exchange_value; ++} ++inline int64_t _Atomic_xchg_long(int64_t exchange_value, volatile int64_t* dest) { ++ __asm__ __volatile__ ("xchgq (%2),%0" ++ : "=r" (exchange_value) ++ : "0" (exchange_value), "r" (dest) ++ : "memory"); ++ return exchange_value; ++} ++inline int8_t _Atomic_cmpxchg_byte(int8_t exchange_value, volatile int8_t* dest, int8_t compare_value) { ++ __asm__ volatile ("lock cmpxchgb %1,(%3)" ++ : "=a" (exchange_value) ++ : "q" (exchange_value), "a" (compare_value), "r" (dest) ++ : "cc", "memory"); ++ return exchange_value; ++} ++inline int32_t _Atomic_cmpxchg(int32_t exchange_value, volatile int32_t* dest, int32_t compare_value) { ++ __asm__ volatile ("lock cmpxchgl %1,(%3)" ++ : "=a" (exchange_value) ++ : "q" (exchange_value), "a" (compare_value), "r" (dest) ++ : "cc", "memory"); ++ return exchange_value; ++} ++inline int64_t _Atomic_cmpxchg_long(int64_t exchange_value, volatile int64_t* dest, int64_t compare_value) { ++ __asm__ volatile ("lock cmpxchgq %1,(%3)" ++ : "=a" (exchange_value) ++ : "q" (exchange_value), "a" (compare_value), "r" (dest) ++ : "cc", "memory"); ++ return exchange_value; ++} ++ ++template ++struct Atomic::PlatformAdd { ++ template ++ D add_then_fetch(D volatile* dest, I add_value, atomic_memory_order order) const; ++ ++ template ++ D fetch_then_add(D volatile* dest, I add_value, atomic_memory_order order) const { ++ return add_then_fetch(dest, add_value, order) - add_value; ++ } ++}; ++ ++// Not using add_using_helper; see comment for cmpxchg. ++template<> ++template ++inline D Atomic::PlatformAdd<4>::add_then_fetch(D volatile* dest, I add_value, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(4 == sizeof(I)); ++ STATIC_ASSERT(4 == sizeof(D)); ++ return PrimitiveConversions::cast( ++ _Atomic_add(PrimitiveConversions::cast(add_value), ++ reinterpret_cast(dest))); ++} ++ ++// Not using add_using_helper; see comment for cmpxchg. ++template<> ++template ++inline D Atomic::PlatformAdd<8>::add_then_fetch(D volatile* dest, I add_value, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(8 == sizeof(I)); ++ STATIC_ASSERT(8 == sizeof(D)); ++ return PrimitiveConversions::cast( ++ _Atomic_add_long(PrimitiveConversions::cast(add_value), ++ reinterpret_cast(dest))); ++} ++ ++template<> ++template ++inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, ++ T exchange_value, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(4 == sizeof(T)); ++ return PrimitiveConversions::cast( ++ _Atomic_xchg(PrimitiveConversions::cast(exchange_value), ++ reinterpret_cast(dest))); ++} ++ ++template<> ++template ++inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest, ++ T exchange_value, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(8 == sizeof(T)); ++ return PrimitiveConversions::cast( ++ _Atomic_xchg_long(PrimitiveConversions::cast(exchange_value), ++ reinterpret_cast(dest))); ++} ++ ++// Not using cmpxchg_using_helper here, because some configurations of ++// Solaris compiler don't deal well with passing a "defined in .il" ++// function as an argument. We *should* switch to using gcc-style ++// inline assembly, but attempting to do so with Studio 12.4 ran into ++// segfaults. ++ ++template<> ++template ++inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest, ++ T compare_value, ++ T exchange_value, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(1 == sizeof(T)); ++ return PrimitiveConversions::cast( ++ _Atomic_cmpxchg_byte(PrimitiveConversions::cast(exchange_value), ++ reinterpret_cast(dest), ++ PrimitiveConversions::cast(compare_value))); ++} ++ ++template<> ++template ++inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest, ++ T compare_value, ++ T exchange_value, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(4 == sizeof(T)); ++ return PrimitiveConversions::cast( ++ _Atomic_cmpxchg(PrimitiveConversions::cast(exchange_value), ++ reinterpret_cast(dest), ++ PrimitiveConversions::cast(compare_value))); ++} ++ ++template<> ++template ++inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, ++ T compare_value, ++ T exchange_value, ++ atomic_memory_order order) const { ++ STATIC_ASSERT(8 == sizeof(T)); ++ return PrimitiveConversions::cast( ++ _Atomic_cmpxchg_long(PrimitiveConversions::cast(exchange_value), ++ reinterpret_cast(dest), ++ PrimitiveConversions::cast(compare_value))); ++} ++ ++#endif // OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP +diff -urN /tmp/a/bytes_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp +--- /tmp/a/bytes_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp 2024-10-15 14:59:36.868451442 +0100 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP ++ ++extern "C" { ++ inline u2 _raw_swap_u2(u2 x) { ++ unsigned short int __dest; ++ __asm__ ("rorw $8, %w0": "=r" (__dest): "0" (x): "cc"); ++ return __dest; ++ } ++ inline u4 _raw_swap_u4(u4 x) { ++ unsigned int __dest; ++ __asm__ ("bswap %0" : "=r" (__dest) : "0" (x)); ++ return __dest; ++ } ++ inline u8 _raw_swap_u8(u8 x) { ++ unsigned long __dest; ++ __asm__ ("bswap %q0" : "=r" (__dest) : "0" (x)); ++ return __dest; ++ } ++} ++ ++// Efficient swapping of data bytes from Java byte ++// ordering to native byte ordering and vice versa. ++inline u2 Bytes::swap_u2(u2 x) { ++ return _raw_swap_u2(x); ++} ++ ++inline u4 Bytes::swap_u4(u4 x) { ++ return _raw_swap_u4(x); ++} ++ ++inline u8 Bytes::swap_u8(u8 x) { ++ return _raw_swap_u8(x); ++} ++ ++#endif // OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP +diff -urN /tmp/a/copy_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp +--- /tmp/a/copy_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp 2024-10-15 14:59:36.868532464 +0100 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP ++ ++// now in central copy_x86.hpp ++ ++#endif // OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP +diff -urN /tmp/a/globals_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp +--- /tmp/a/globals_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp 2024-10-15 14:59:36.868622681 +0100 +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP ++ ++// Sets the default values for platform dependent flags used by the runtime system. ++// (see globals.hpp) ++ ++define_pd_global(bool, DontYieldALot, true); // Determined in the design center ++define_pd_global(intx, CompilerThreadStackSize, 1024); ++define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default ++define_pd_global(intx, VMThreadStackSize, 1024); ++define_pd_global(size_t, JVMInvokeMethodSlack, 8*K); ++ ++// Used on 64 bit platforms for UseCompressedOops base address ++define_pd_global(size_t, HeapBaseMinAddress, 2*G); ++ ++#endif // OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP +diff -urN /tmp/a/javaThread_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.cpp +--- /tmp/a/javaThread_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.cpp 2024-10-15 14:59:36.869548940 +0100 +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. 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 "runtime/frame.inline.hpp" ++#include "runtime/javaThread.hpp" ++ ++frame JavaThread::pd_last_frame() { ++ assert(has_last_Java_frame(), "must have last_Java_sp() when suspended"); ++ vmassert(_anchor.last_Java_pc() != NULL, "not walkable"); ++ return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc()); ++} ++ ++// For Forte Analyzer AsyncGetCallTrace profiling support - thread is ++// currently interrupted by SIGPROF ++bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr, ++ void* ucontext, bool isInJava) { ++ assert(Thread::current() == this, "caller must be current thread"); ++ return pd_get_top_frame(fr_addr, ucontext, isInJava); ++} ++ ++bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, ++ void* ucontext, bool isInJava) { ++ return pd_get_top_frame(fr_addr, ucontext, isInJava); ++} ++ ++bool JavaThread::pd_get_top_frame(frame* fr_addr, ++ void* ucontext, bool isInJava) { ++ assert(this->is_Java_thread(), "must be JavaThread"); ++ JavaThread* jt = (JavaThread *)this; ++ ++ // There is small window where last_Java_frame is not walkable or safe ++ if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) { ++ *fr_addr = jt->pd_last_frame(); ++ return true; ++ } ++ ++ ucontext_t* uc = (ucontext_t*) ucontext; ++ ++ // We always want to use the initial frame we create from the ucontext as ++ // it certainly signals where we currently are. However that frame may not ++ // be safe for calling sender. In that case if we have a last_Java_frame ++ // then the forte walker will switch to that frame as the virtual sender ++ // for the frame we create here which is not sender safe. ++ ++ intptr_t* ret_fp; ++ intptr_t* ret_sp; ++ address addr = os::fetch_frame_from_context(uc, &ret_sp, &ret_fp); ++ ++ // Something would really have to be screwed up to get a NULL pc ++ ++ if (addr == NULL) { ++ // ucontext wasn't useful ++ return false; ++ } ++ ++ // If sp and fp are nonsense just leave them out ++ ++ if (!jt->is_in_full_stack((address)ret_sp)) { ++ ret_sp = NULL; ++ ret_fp = NULL; ++ } else { ++ // sp is reasonable is fp reasonable? ++ if (!jt->is_in_stack_range_incl((address)ret_fp, (address)ret_sp)) { ++ ret_fp = NULL; ++ } ++ } ++ ++ frame ret_frame(ret_sp, ret_fp, addr); ++ ++ *fr_addr = ret_frame; ++ return true; ++ ++} ++ ++void JavaThread::cache_global_variables() { } +diff -urN /tmp/a/javaThread_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.hpp +--- /tmp/a/javaThread_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.hpp 2024-10-15 14:59:36.869648787 +0100 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_JAVATHREAD_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_JAVATHREAD_SOLARIS_X86_HPP ++ ++ private: ++ void pd_initialize() { _anchor.clear(); } ++ ++ frame pd_last_frame(); ++ ++ public: ++ ++ void set_base_of_stack_pointer(intptr_t* base_sp) {} ++ ++ static ByteSize last_Java_fp_offset() { ++ return byte_offset_of(JavaThread, _anchor) + JavaFrameAnchor::last_Java_fp_offset(); ++ } ++ ++ intptr_t* base_of_stack_pointer() { return NULL; } ++ void record_base_of_stack_pointer() {} ++ ++ bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext, ++ bool isInJava); ++ bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext, ++ bool isInJava); ++private: ++ bool pd_get_top_frame(frame* fr_addr, void* ucontext, ++ bool isInJava); ++public: ++ ++ // These routines are only used on cpu architectures that ++ // have separate register stacks (Itanium). ++ static bool register_stack_overflow() { return false; } ++ static void enable_register_stack_guard() {} ++ static void disable_register_stack_guard() {} ++ ++#endif // OS_CPU_SOLARIS_X86_JAVATHREAD_SOLARIS_X86_HPP +diff -urN /tmp/a/orderAccess_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp +--- /tmp/a/orderAccess_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp 2024-10-15 14:59:36.868709514 +0100 +@@ -0,0 +1,58 @@ ++/* ++ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP ++ ++// Included in orderAccess.hpp header file. ++ ++// Compiler version last used for testing: solaris studio 12u3 ++// Please update this information when this file changes ++ ++// Implementation of class OrderAccess. ++ ++// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions ++inline void compiler_barrier() { ++ __asm__ volatile ("" : : : "memory"); ++} ++ ++inline void OrderAccess::loadload() { compiler_barrier(); } ++inline void OrderAccess::storestore() { compiler_barrier(); } ++inline void OrderAccess::loadstore() { compiler_barrier(); } ++inline void OrderAccess::storeload() { fence(); } ++ ++inline void OrderAccess::acquire() { compiler_barrier(); } ++inline void OrderAccess::release() { compiler_barrier(); } ++ ++inline void OrderAccess::fence() { ++ __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory"); ++ compiler_barrier(); ++} ++ ++inline void OrderAccess::cross_modify_fence_impl() { ++ int idx = 0; ++ __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory"); ++} ++ ++#endif // OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP +diff -urN /tmp/a/os_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp +--- /tmp/a/os_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp 2024-10-15 14:59:36.911042968 +0100 +@@ -0,0 +1,610 @@ ++/* ++ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++// no precompiled headers ++#include "jvm.h" ++#include "asm/macroAssembler.hpp" ++#include "classfile/classLoader.hpp" ++#include "classfile/systemDictionary.hpp" ++#include "classfile/vmSymbols.hpp" ++#include "code/codeCache.hpp" ++#include "code/icBuffer.hpp" ++#include "code/vtableStubs.hpp" ++#include "interpreter/interpreter.hpp" ++#include "logging/log.hpp" ++#include "memory/allocation.inline.hpp" ++#include "os_solaris.hpp" ++#include "os_posix.hpp" ++#include "prims/jniFastGetField.hpp" ++#include "prims/jvm_misc.hpp" ++#include "runtime/arguments.hpp" ++#include "runtime/frame.inline.hpp" ++#include "runtime/interfaceSupport.inline.hpp" ++#include "runtime/java.hpp" ++#include "runtime/javaCalls.hpp" ++#include "runtime/mutexLocker.hpp" ++#include "runtime/osThread.hpp" ++#include "runtime/safepointMechanism.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/stubRoutines.hpp" ++#include "runtime/thread.inline.hpp" ++#include "runtime/timer.hpp" ++#include "signals_posix.hpp" ++#include "utilities/align.hpp" ++#include "utilities/events.hpp" ++#include "utilities/vmError.hpp" ++ ++// put OS-includes here ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++ ++#define MAX_PATH (2 * K) ++ ++// Minimum usable stack sizes required to get to user code. Space for ++// HotSpot guard pages is added later. ++#ifdef _LP64 ++// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler ++// threads requires a large stack with the Solaris Studio C++ compiler version 5.13 ++// and product VM builds (debug builds require significantly less stack space). ++size_t os::_compiler_thread_min_stack_allowed = 325 * K; ++size_t os::_java_thread_min_stack_allowed = 48 * K; ++size_t os::_vm_internal_thread_min_stack_allowed = 224 * K; ++#else ++size_t os::_compiler_thread_min_stack_allowed = 32 * K; ++size_t os::_java_thread_min_stack_allowed = 32 * K; ++size_t os::_vm_internal_thread_min_stack_allowed = 64 * K; ++#endif // _LP64 ++ ++#ifdef AMD64 ++#define REG_SP REG_RSP ++#define REG_PC REG_RIP ++#define REG_FP REG_RBP ++#else ++#define REG_SP UESP ++#define REG_PC EIP ++#define REG_FP EBP ++// 4900493 counter to prevent runaway LDTR refresh attempt ++ ++static volatile int ldtr_refresh = 0; ++// the libthread instruction that faults because of the stale LDTR ++ ++static const unsigned char movlfs[] = { 0x8e, 0xe0 // movl %eax,%fs ++ }; ++#endif // AMD64 ++ ++char* os::non_memory_address_word() { ++ // Must never look like an address returned by reserve_memory, ++ // even in its subfields (as defined by the CPU immediate fields, ++ // if the CPU splits constants across multiple instructions). ++ return (char*) -1; ++} ++ ++// ++// Validate a ucontext retrieved from walking a uc_link of a ucontext. ++// There are issues with libthread giving out uc_links for different threads ++// on the same uc_link chain and bad or circular links. ++// ++bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) { ++ if (valid >= suspect || ++ valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags || ++ valid->uc_stack.ss_sp != suspect->uc_stack.ss_sp || ++ valid->uc_stack.ss_size != suspect->uc_stack.ss_size) { ++ DEBUG_ONLY(tty->print_cr("valid_ucontext: failed test 1");) ++ return false; ++ } ++ ++ if (thread->is_Java_thread()) { ++ if (!thread->is_in_full_stack_checked((address)suspect)) { ++ DEBUG_ONLY(tty->print_cr("valid_ucontext: uc_link not in thread stack");) ++ return false; ++ } ++ if (!thread->is_in_full_stack_checked((address) suspect->uc_mcontext.gregs[REG_SP])) { ++ DEBUG_ONLY(tty->print_cr("valid_ucontext: stackpointer not in thread stack");) ++ return false; ++ } ++ } ++ return true; ++} ++ ++// We will only follow one level of uc_link since there are libthread ++// issues with ucontext linking and it is better to be safe and just ++// let caller retry later. ++const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread, ++ const ucontext_t *uc) { ++ ++ const ucontext_t *retuc = NULL; ++ ++ if (uc != NULL) { ++ if (uc->uc_link == NULL) { ++ // cannot validate without uc_link so accept current ucontext ++ retuc = uc; ++ } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { ++ // first ucontext is valid so try the next one ++ uc = uc->uc_link; ++ if (uc->uc_link == NULL) { ++ // cannot validate without uc_link so accept current ucontext ++ retuc = uc; ++ } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) { ++ // the ucontext one level down is also valid so return it ++ retuc = uc; ++ } ++ } ++ } ++ return retuc; ++} ++ ++void os::Posix::ucontext_set_pc(ucontext_t* uc, address pc) { ++ uc->uc_mcontext.gregs [REG_PC] = (greg_t) pc; ++} ++ ++// Assumes ucontext is valid ++intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) { ++ return (intptr_t*)uc->uc_mcontext.gregs[REG_SP]; ++} ++ ++// Assumes ucontext is valid ++intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) { ++ return (intptr_t*)uc->uc_mcontext.gregs[REG_FP]; ++} ++ ++address os::Posix::ucontext_get_pc(const ucontext_t *uc) { ++ return (address) uc->uc_mcontext.gregs[REG_PC]; ++} ++ ++address os::fetch_frame_from_context(const void* ucVoid, ++ intptr_t** ret_sp, intptr_t** ret_fp) { ++ ++ address epc; ++ const ucontext_t *uc = (const ucontext_t*)ucVoid; ++ ++ if (uc != NULL) { ++ epc = os::Posix::ucontext_get_pc(uc); ++ if (ret_sp) *ret_sp = os::Solaris::ucontext_get_sp(uc); ++ if (ret_fp) *ret_fp = os::Solaris::ucontext_get_fp(uc); ++ } else { ++ epc = NULL; ++ if (ret_sp) *ret_sp = (intptr_t *)NULL; ++ if (ret_fp) *ret_fp = (intptr_t *)NULL; ++ } ++ ++ return epc; ++} ++ ++frame os::fetch_frame_from_context(const void* ucVoid) { ++ intptr_t* sp; ++ intptr_t* fp; ++ address epc = fetch_frame_from_context(ucVoid, &sp, &fp); ++ return frame(sp, fp, epc); ++} ++ ++frame os::fetch_compiled_frame_from_context(const void* ucVoid) { ++ const ucontext_t* uc = (const ucontext_t*)ucVoid; ++ frame fr = os::fetch_frame_from_context(uc); ++ // in compiled code, the stack banging is performed just after the return pc ++ // has been pushed on the stack ++ return frame(fr.sp() + 1, fr.fp(), (address)*(fr.sp())); ++} ++ ++frame os::get_sender_for_C_frame(frame* fr) { ++ return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); ++} ++ ++extern "C" intptr_t *_get_current_sp() { ++ register intptr_t *rsp __asm__ ("rsp"); ++ return rsp; ++} ++ ++address os::current_stack_pointer() { ++ return (address)_get_current_sp(); ++} ++ ++extern "C" intptr_t *_get_current_fp() { ++ register intptr_t **rbp __asm__ ("rbp"); ++ return (intptr_t*) *rbp; ++} ++ ++frame os::current_frame() { ++ intptr_t* fp = _get_current_fp(); // it's inlined so want current fp ++ // fp is for os::current_frame. We want the fp for our caller. ++ frame myframe((intptr_t*)os::current_stack_pointer(), ++ (intptr_t*)fp, ++ CAST_FROM_FN_PTR(address, os::current_frame)); ++ frame caller_frame = os::get_sender_for_C_frame(&myframe); ++ ++ if (os::is_first_C_frame(&caller_frame)) { ++ // stack is not walkable ++ frame ret; // This will be a null useless frame ++ return ret; ++ } else { ++ // return frame for our caller's caller ++ return os::get_sender_for_C_frame(&caller_frame); ++ } ++} ++ ++ ++juint os::cpu_microcode_revision() { ++ juint result = 0; ++ // to implement this, look at the source for ucodeadm -v ++ return result; ++} ++ ++bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ++ ucontext_t* uc, JavaThread* thread) { ++ ++ if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) { ++ // can't decode this kind of signal ++ info = NULL; ++ } else { ++ assert(sig == info->si_signo, "bad siginfo"); ++ } ++ ++ // decide if this trap can be handled by a stub ++ address stub = NULL; ++ ++ address pc = NULL; ++ ++ //%note os_trap_1 ++ if (info != NULL && uc != NULL && thread != NULL) { ++ // factor me: getPCfromContext ++ pc = (address) uc->uc_mcontext.gregs[REG_PC]; ++ ++ // Handle ALL stack overflow variations here ++ if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) { ++ address addr = (address) info->si_addr; ++ if (thread->is_in_full_stack(addr)) { ++ // stack overflow ++ if (os::Posix::handle_stack_overflow(thread, addr, pc, uc, &stub)) { ++ return true; // continue ++ } ++ } ++ } ++ ++ if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) { ++ // Verify that OS save/restore AVX registers. ++ stub = VM_Version::cpuinfo_cont_addr(); ++ } ++ ++ if (thread->thread_state() == _thread_in_vm || ++ thread->thread_state() == _thread_in_native) { ++ if (sig == SIGBUS && info->si_code == BUS_OBJERR && thread->doing_unsafe_access()) { ++ address next_pc = Assembler::locate_next_instruction(pc); ++ if (UnsafeCopyMemory::contains_pc(pc)) { ++ next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); ++ } ++ stub = SharedRuntime::handle_unsafe_access(thread, next_pc); ++ } ++ } ++ ++ if (thread->thread_state() == _thread_in_Java) { ++ // Support Safepoint Polling ++ if ( sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) { ++ stub = SharedRuntime::get_poll_stub(pc); ++ } ++ else if (sig == SIGBUS && info->si_code == BUS_OBJERR) { ++ // BugId 4454115: A read from a MappedByteBuffer can fault ++ // here if the underlying file has been truncated. ++ // Do not crash the VM in such a case. ++ CodeBlob* cb = CodeCache::find_blob(pc); ++ if (cb != NULL) { ++ CompiledMethod* nm = cb->as_compiled_method_or_null(); ++ bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc); ++ if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) { ++ address next_pc = Assembler::locate_next_instruction(pc); ++ if (is_unsafe_arraycopy) { ++ next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); ++ } ++ stub = SharedRuntime::handle_unsafe_access(thread, next_pc); ++ } ++ } ++ } ++ else ++ if (sig == SIGFPE && info->si_code == FPE_INTDIV) { ++ // integer divide by zero ++ stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); ++ } ++#ifndef AMD64 ++ else if (sig == SIGFPE && info->si_code == FPE_FLTDIV) { ++ // floating-point divide by zero ++ stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO); ++ } ++ else if (sig == SIGFPE && info->si_code == FPE_FLTINV) { ++ // The encoding of D2I in i486.ad can cause an exception prior ++ // to the fist instruction if there was an invalid operation ++ // pending. We want to dismiss that exception. From the win_32 ++ // side it also seems that if it really was the fist causing ++ // the exception that we do the d2i by hand with different ++ // rounding. Seems kind of weird. QQQ TODO ++ // Note that we take the exception at the NEXT floating point instruction. ++ if (pc[0] == 0xDB) { ++ assert(pc[0] == 0xDB, "not a FIST opcode"); ++ assert(pc[1] == 0x14, "not a FIST opcode"); ++ assert(pc[2] == 0x24, "not a FIST opcode"); ++ return true; ++ } else { ++ assert(pc[-3] == 0xDB, "not an flt invalid opcode"); ++ assert(pc[-2] == 0x14, "not an flt invalid opcode"); ++ assert(pc[-1] == 0x24, "not an flt invalid opcode"); ++ } ++ } ++ else if (sig == SIGFPE ) { ++ tty->print_cr("caught SIGFPE, info 0x%x.", info->si_code); ++ } ++#endif // !AMD64 ++ ++ // QQQ It doesn't seem that we need to do this on x86 because we should be able ++ // to return properly from the handler without this extra stuff on the back side. ++ ++ else if (sig == SIGSEGV && info->si_code > 0 && ++ MacroAssembler::uses_implicit_null_check(info->si_addr)) { ++ // Determination of interpreter/vtable stub/compiled code null exception ++ stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL); ++ } ++ } ++ ++ // jni_fast_GetField can trap at certain pc's if a GC kicks in ++ // and the heap gets shrunk before the field access. ++ if ((sig == SIGSEGV) || (sig == SIGBUS)) { ++ address addr = JNI_FastGetField::find_slowcase_pc(pc); ++ if (addr != (address)-1) { ++ stub = addr; ++ } ++ } ++ } ++ ++ // Execution protection violation ++ // ++ // Preventative code for future versions of Solaris which may ++ // enable execution protection when running the 32-bit VM on AMD64. ++ // ++ // This should be kept as the last step in the triage. We don't ++ // have a dedicated trap number for a no-execute fault, so be ++ // conservative and allow other handlers the first shot. ++ // ++ // Note: We don't test that info->si_code == SEGV_ACCERR here. ++ // this si_code is so generic that it is almost meaningless; and ++ // the si_code for this condition may change in the future. ++ // Furthermore, a false-positive should be harmless. ++ if (UnguardOnExecutionViolation > 0 && ++ (sig == SIGSEGV || sig == SIGBUS) && ++ uc->uc_mcontext.gregs[TRAPNO] == T_PGFLT) { // page fault ++ int page_size = os::vm_page_size(); ++ address addr = (address) info->si_addr; ++ address pc = (address) uc->uc_mcontext.gregs[REG_PC]; ++ // Make sure the pc and the faulting address are sane. ++ // ++ // If an instruction spans a page boundary, and the page containing ++ // the beginning of the instruction is executable but the following ++ // page is not, the pc and the faulting address might be slightly ++ // different - we still want to unguard the 2nd page in this case. ++ // ++ // 15 bytes seems to be a (very) safe value for max instruction size. ++ bool pc_is_near_addr = ++ (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15); ++ bool instr_spans_page_boundary = ++ (align_down((intptr_t) pc ^ (intptr_t) addr, ++ (intptr_t) page_size) > 0); ++ ++ if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) { ++ static volatile address last_addr = ++ (address) os::non_memory_address_word(); ++ ++ // In conservative mode, don't unguard unless the address is in the VM ++ if (addr != last_addr && ++ (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) { ++ ++ // Make memory rwx and retry ++ address page_start = align_down(addr, page_size); ++ bool res = os::protect_memory((char*) page_start, page_size, ++ os::MEM_PROT_RWX); ++ ++ log_debug(os)("Execution protection violation " ++ "at " INTPTR_FORMAT ++ ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr), ++ p2i(page_start), (res ? "success" : "failed"), errno); ++ stub = pc; ++ ++ // Set last_addr so if we fault again at the same address, we don't end ++ // up in an endless loop. ++ // ++ // There are two potential complications here. Two threads trapping at ++ // the same address at the same time could cause one of the threads to ++ // think it already unguarded, and abort the VM. Likely very rare. ++ // ++ // The other race involves two threads alternately trapping at ++ // different addresses and failing to unguard the page, resulting in ++ // an endless loop. This condition is probably even more unlikely than ++ // the first. ++ // ++ // Although both cases could be avoided by using locks or thread local ++ // last_addr, these solutions are unnecessary complication: this ++ // handler is a best-effort safety net, not a complete solution. It is ++ // disabled by default and should only be used as a workaround in case ++ // we missed any no-execute-unsafe VM code. ++ ++ last_addr = addr; ++ } ++ } ++ } ++ ++ if (stub != NULL) { ++ // save all thread context in case we need to restore it ++ ++ if (thread != NULL) thread->set_saved_exception_pc(pc); ++ // 12/02/99: On Sparc it appears that the full context is also saved ++ // but as yet, no one looks at or restores that saved context ++ os::Posix::ucontext_set_pc(uc, stub); ++ return true; ++ } ++ ++ return false; ++} ++ ++void os::print_context(outputStream *st, const void *context) { ++ if (context == NULL) return; ++ ++ const ucontext_t *uc = (const ucontext_t*)context; ++ st->print_cr("Registers:"); ++#ifdef AMD64 ++ st->print( "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]); ++ st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]); ++ st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]); ++ st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]); ++ st->cr(); ++ st->print( "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]); ++ st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]); ++ st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]); ++ st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]); ++ st->cr(); ++ st->print( "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]); ++ st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]); ++ st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]); ++ st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]); ++ st->cr(); ++ st->print( "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]); ++ st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]); ++ st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]); ++ st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]); ++ st->cr(); ++ st->print( "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]); ++ st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]); ++#else ++ st->print( "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]); ++ st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]); ++ st->print(", ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ECX]); ++ st->print(", EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDX]); ++ st->cr(); ++ st->print( "ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[UESP]); ++ st->print(", EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBP]); ++ st->print(", ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ESI]); ++ st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDI]); ++ st->cr(); ++ st->print( "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]); ++ st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]); ++#endif // AMD64 ++ st->cr(); ++ st->cr(); ++} ++ ++void os::print_tos_pc(outputStream *st, const void *context) { ++ if (context == NULL) return; ++ ++ const ucontext_t* uc = (const ucontext_t*)context; ++ ++ intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc); ++ st->print_cr("Top of Stack: (sp=" INTPTR_FORMAT ")", (intptr_t)sp); ++ print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t)); ++ st->cr(); ++ ++ // Note: it may be unsafe to inspect memory near pc. For example, pc may ++ // point to garbage if entry point in an nmethod is corrupted. Leave ++ // this at the end, and hope for the best. ++ address pc = os::Posix::ucontext_get_pc(uc); ++ print_instructions(st, pc, sizeof(char)); ++ st->cr(); ++} ++ ++void os::print_register_info(outputStream *st, const void *context, int& continuation) { ++ const int register_count = AMD64_ONLY(16) NOT_AMD64(8); ++ int n = continuation; ++ assert(n >= 0 && n <= register_count, "Invalid continuation value"); ++ if (context == nullptr || n == register_count) { ++ return; ++ } ++ ++ const ucontext_t *uc = (const ucontext_t*)context; ++ while (n < register_count) { ++ // Update continuation with next index before printing location ++ continuation = n + 1; ++# define CASE_PRINT_REG(n, str, id) case n: st->print(str); print_location(st, uc->uc_mcontext.gregs[REG_##id]); ++ switch (n) { ++#ifdef AMD64 ++ CASE_PRINT_REG( 0, "RAX=", RAX); break; ++ CASE_PRINT_REG( 1, "RBX=", RBX); break; ++ CASE_PRINT_REG( 2, "RCX=", RCX); break; ++ CASE_PRINT_REG( 3, "RDX=", RDX); break; ++ CASE_PRINT_REG( 4, "RSP=", RSP); break; ++ CASE_PRINT_REG( 5, "RBP=", RBP); break; ++ CASE_PRINT_REG( 6, "RSI=", RSI); break; ++ CASE_PRINT_REG( 7, "RDI=", RDI); break; ++ CASE_PRINT_REG( 8, "R8 =", R8); break; ++ CASE_PRINT_REG( 9, "R9 =", R9); break; ++ CASE_PRINT_REG(10, "R10=", R10); break; ++ CASE_PRINT_REG(11, "R11=", R11); break; ++ CASE_PRINT_REG(12, "R12=", R12); break; ++ CASE_PRINT_REG(13, "R13=", R13); break; ++ CASE_PRINT_REG(14, "R14=", R14); break; ++ CASE_PRINT_REG(15, "R15=", R15); break; ++#else ++ CASE_PRINT_REG(0, "EAX=", EAX); break; ++ CASE_PRINT_REG(1, "EBX=", EBX); break; ++ CASE_PRINT_REG(2, "ECX=", ECX); break; ++ CASE_PRINT_REG(3, "EDX=", EDX); break; ++ CASE_PRINT_REG(4, "ESP=", ESP); break; ++ CASE_PRINT_REG(5, "EBP=", EBP); break; ++ CASE_PRINT_REG(6, "ESI=", ESI); break; ++ CASE_PRINT_REG(7, "EDI=", EDI); break; ++#endif // AMD64 ++ } ++# undef CASE_PRINT_REG ++ ++n; ++ } ++} ++ ++ ++void os::Solaris::init_thread_fpu_state(void) { ++ // Nothing to do ++} ++void os::setup_fpu() {} ++ ++#ifndef PRODUCT ++void os::verify_stack_alignment() { ++ assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment"); ++} ++#endif ++ ++int os::extra_bang_size_in_bytes() { ++ // JDK-8050147 requires the full cache line bang for x86. ++ return VM_Version::L1_line_size(); ++} +diff -urN /tmp/a/os_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp +--- /tmp/a/os_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp 2024-10-15 14:59:36.898145900 +0100 +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP ++ ++ // ++ // NOTE: we are back in class os here, not Solaris ++ // ++#ifdef AMD64 ++ static void setup_fpu() {} ++#else ++ static int32_t (*atomic_xchg_func) (int32_t, volatile int32_t*); ++ static int32_t (*atomic_cmpxchg_func) (int32_t, volatile int32_t*, int32_t); ++ static int64_t (*atomic_cmpxchg_long_func)(int64_t, volatile int64_t*, int64_t); ++ static int32_t (*atomic_add_func) (int32_t, volatile int32_t*); ++ ++ static int32_t atomic_xchg_bootstrap (int32_t, volatile int32_t*); ++ static int32_t atomic_cmpxchg_bootstrap (int32_t, volatile int32_t*, int32_t); ++ static int64_t atomic_cmpxchg_long_bootstrap(int64_t, volatile int64_t*, int64_t); ++ static int32_t atomic_add_bootstrap (int32_t, volatile int32_t*); ++ ++ static void setup_fpu(); ++#endif // AMD64 ++ ++ static juint cpu_microcode_revision(); ++ ++ static jlong rdtsc(); ++ ++ static bool is_allocatable(size_t bytes); ++ ++ // Used to register dynamic code cache area with the OS ++ // Note: Currently only used in 64 bit Windows implementations ++ static bool register_code_area(char *low, char *high) { return true; } ++ ++#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP +diff -urN /tmp/a/os_solaris_x86.inline.hpp b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp +--- /tmp/a/os_solaris_x86.inline.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp 2024-10-15 14:59:36.869168535 +0100 +@@ -0,0 +1,39 @@ ++/* ++ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP ++#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP ++ ++#include "runtime/os.hpp" ++ ++// See http://www.technovelty.org/code/c/reading-rdtsc.htl for details ++inline jlong os::rdtsc() { ++ uint64_t res; ++ uint32_t ts1, ts2; ++ __asm__ __volatile__ ("rdtsc" : "=a" (ts1), "=d" (ts2)); ++ res = ((uint64_t)ts1 | (uint64_t)ts2 << 32); ++ return (jlong)res; ++} ++ ++#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP +diff -urN /tmp/a/prefetch_solaris_x86.inline.hpp b/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp +--- /tmp/a/prefetch_solaris_x86.inline.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp 2024-10-15 14:59:36.869266764 +0100 +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP ++#define OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP ++ ++#include "runtime/prefetch.hpp" ++ ++inline void Prefetch::read (const void *loc, intx interval) { ++#ifdef AMD64 ++ __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); ++#endif // AMD64 ++} ++ ++inline void Prefetch::write(void *loc, intx interval) { ++#ifdef AMD64 ++ __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval)); ++#endif // AMD64 ++} ++ ++#endif // OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP +diff -urN /tmp/a/safefetch_solaris_x86_64.S b/src/hotspot/os_cpu/solaris_x86/safefetch_solaris_x86_64.S +--- /tmp/a/safefetch_solaris_x86_64.S 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/safefetch_solaris_x86_64.S 2024-10-15 14:59:36.915486184 +0100 +@@ -0,0 +1,58 @@ ++# ++# Copyright (c) 2022 SAP SE. All rights reserved. ++# Copyright (c) 2022, Oracle and/or its affiliates. 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. ++# ++ .globl SafeFetch32_impl ++ .globl SafeFetchN_impl ++ .globl _SafeFetch32_fault ++ .globl _SafeFetchN_fault ++ .globl _SafeFetch32_continuation ++ .globl _SafeFetchN_continuation ++ ++ .text ++ ++ ++ # Support for int SafeFetch32(int* address, int defaultval); ++ # ++ # %rdi : address ++ # %esi : defaultval ++ .type SafeFetch32_impl,@function ++SafeFetch32_impl: ++_SafeFetch32_fault: ++ movl (%rdi), %eax # load target value, may fault ++ ret ++_SafeFetch32_continuation: ++ movl %esi, %eax # return default ++ ret ++ ++ # Support for intptr_t SafeFetchN(intptr_t* address, intptr_t defaultval); ++ # ++ # %rdi : address ++ # %rsi : defaultval ++ .type SafeFetchN_impl,@function ++SafeFetchN_impl: ++_SafeFetchN_fault: ++ movq (%rdi), %rax # load target value, may fault ++ ret ++_SafeFetchN_continuation: ++ movq %rsi, %rax # return default ++ ret +diff -urN /tmp/a/solaris_x86_64.S b/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S +--- /tmp/a/solaris_x86_64.S 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S 2024-10-15 14:59:36.869441513 +0100 +@@ -0,0 +1,386 @@ ++# ++# Copyright (c) 2004, 2013, Oracle and/or its affiliates. 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. ++# ++ ++ .globl fs_load ++ .globl fs_thread ++ ++ ## NOTE WELL! The _Copy functions are called directly ++ ## from server-compiler-generated code via CallLeafNoFP, ++ ## which means that they *must* either not use floating ++ ## point or use it in the same manner as does the server ++ ## compiler. ++ ++ .globl _Copy_arrayof_conjoint_bytes ++ .globl _Copy_conjoint_jshorts_atomic ++ .globl _Copy_arrayof_conjoint_jshorts ++ .globl _Copy_conjoint_jints_atomic ++ .globl _Copy_arrayof_conjoint_jints ++ .globl _Copy_conjoint_jlongs_atomic ++ .globl _Copy_arrayof_conjoint_jlongs ++ ++ .section .text,"ax" ++ ++ # Fast thread accessors, used by threadLS_solaris_amd64.cpp ++ .align 16 ++fs_load: ++ movq %fs:(%rdi),%rax ++ ret ++ ++ .align 16 ++fs_thread: ++ movq %fs:0x0,%rax ++ ret ++ ++ .globl SpinPause ++ .align 16 ++SpinPause: ++ rep ++ nop ++ movq $1, %rax ++ ret ++ ++ ++ # Support for void Copy::arrayof_conjoint_bytes(void* from, ++ # void* to, ++ # size_t count) ++ # rdi - from ++ # rsi - to ++ # rdx - count, treated as ssize_t ++ # ++ .align 16 ++_Copy_arrayof_conjoint_bytes: ++ movq %rdx,%r8 # byte count ++ shrq $3,%rdx # qword count ++ cmpq %rdi,%rsi ++ leaq -1(%rdi,%r8,1),%rax # from + bcount*1 - 1 ++ jbe acb_CopyRight ++ cmpq %rax,%rsi ++ jbe acb_CopyLeft ++acb_CopyRight: ++ leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 ++ leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 ++ negq %rdx ++ jmp 7f ++ .align 16 ++1: movq 8(%rax,%rdx,8),%rsi ++ movq %rsi,8(%rcx,%rdx,8) ++ addq $1,%rdx ++ jnz 1b ++2: testq $4,%r8 # check for trailing dword ++ jz 3f ++ movl 8(%rax),%esi # copy trailing dword ++ movl %esi,8(%rcx) ++ addq $4,%rax ++ addq $4,%rcx # original %rsi is trashed, so we ++ # can't use it as a base register ++3: testq $2,%r8 # check for trailing word ++ jz 4f ++ movw 8(%rax),%si # copy trailing word ++ movw %si,8(%rcx) ++ addq $2,%rcx ++4: testq $1,%r8 # check for trailing byte ++ jz 5f ++ movb -1(%rdi,%r8,1),%al # copy trailing byte ++ movb %al,8(%rcx) ++5: ret ++ .align 16 ++6: movq -24(%rax,%rdx,8),%rsi ++ movq %rsi,-24(%rcx,%rdx,8) ++ movq -16(%rax,%rdx,8),%rsi ++ movq %rsi,-16(%rcx,%rdx,8) ++ movq -8(%rax,%rdx,8),%rsi ++ movq %rsi,-8(%rcx,%rdx,8) ++ movq (%rax,%rdx,8),%rsi ++ movq %rsi,(%rcx,%rdx,8) ++7: addq $4,%rdx ++ jle 6b ++ subq $4,%rdx ++ jl 1b ++ jmp 2b ++acb_CopyLeft: ++ testq $1,%r8 # check for trailing byte ++ jz 1f ++ movb -1(%rdi,%r8,1),%cl # copy trailing byte ++ movb %cl,-1(%rsi,%r8,1) ++ subq $1,%r8 # adjust for possible trailing word ++1: testq $2,%r8 # check for trailing word ++ jz 2f ++ movw -2(%rdi,%r8,1),%cx # copy trailing word ++ movw %cx,-2(%rsi,%r8,1) ++2: testq $4,%r8 # check for trailing dword ++ jz 5f ++ movl (%rdi,%rdx,8),%ecx # copy trailing dword ++ movl %ecx,(%rsi,%rdx,8) ++ jmp 5f ++ .align 16 ++3: movq -8(%rdi,%rdx,8),%rcx ++ movq %rcx,-8(%rsi,%rdx,8) ++ subq $1,%rdx ++ jnz 3b ++ ret ++ .align 16 ++4: movq 24(%rdi,%rdx,8),%rcx ++ movq %rcx,24(%rsi,%rdx,8) ++ movq 16(%rdi,%rdx,8),%rcx ++ movq %rcx,16(%rsi,%rdx,8) ++ movq 8(%rdi,%rdx,8),%rcx ++ movq %rcx,8(%rsi,%rdx,8) ++ movq (%rdi,%rdx,8),%rcx ++ movq %rcx,(%rsi,%rdx,8) ++5: subq $4,%rdx ++ jge 4b ++ addq $4,%rdx ++ jg 3b ++ ret ++ ++ # Support for void Copy::arrayof_conjoint_jshorts(void* from, ++ # void* to, ++ # size_t count) ++ # Equivalent to ++ # conjoint_jshorts_atomic ++ # ++ # If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we ++ # let the hardware handle it. The tow or four words within dwords ++ # or qwords that span cache line boundaries will still be loaded ++ # and stored atomically. ++ # ++ # rdi - from ++ # rsi - to ++ # rdx - count, treated as ssize_t ++ # ++ .align 16 ++_Copy_arrayof_conjoint_jshorts: ++_Copy_conjoint_jshorts_atomic: ++ movq %rdx,%r8 # word count ++ shrq $2,%rdx # qword count ++ cmpq %rdi,%rsi ++ leaq -2(%rdi,%r8,2),%rax # from + wcount*2 - 2 ++ jbe acs_CopyRight ++ cmpq %rax,%rsi ++ jbe acs_CopyLeft ++acs_CopyRight: ++ leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 ++ leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 ++ negq %rdx ++ jmp 6f ++1: movq 8(%rax,%rdx,8),%rsi ++ movq %rsi,8(%rcx,%rdx,8) ++ addq $1,%rdx ++ jnz 1b ++2: testq $2,%r8 # check for trailing dword ++ jz 3f ++ movl 8(%rax),%esi # copy trailing dword ++ movl %esi,8(%rcx) ++ addq $4,%rcx # original %rsi is trashed, so we ++ # can't use it as a base register ++3: testq $1,%r8 # check for trailing word ++ jz 4f ++ movw -2(%rdi,%r8,2),%si # copy trailing word ++ movw %si,8(%rcx) ++4: ret ++ .align 16 ++5: movq -24(%rax,%rdx,8),%rsi ++ movq %rsi,-24(%rcx,%rdx,8) ++ movq -16(%rax,%rdx,8),%rsi ++ movq %rsi,-16(%rcx,%rdx,8) ++ movq -8(%rax,%rdx,8),%rsi ++ movq %rsi,-8(%rcx,%rdx,8) ++ movq (%rax,%rdx,8),%rsi ++ movq %rsi,(%rcx,%rdx,8) ++6: addq $4,%rdx ++ jle 5b ++ subq $4,%rdx ++ jl 1b ++ jmp 2b ++acs_CopyLeft: ++ testq $1,%r8 # check for trailing word ++ jz 1f ++ movw -2(%rdi,%r8,2),%cx # copy trailing word ++ movw %cx,-2(%rsi,%r8,2) ++1: testq $2,%r8 # check for trailing dword ++ jz 4f ++ movl (%rdi,%rdx,8),%ecx # copy trailing dword ++ movl %ecx,(%rsi,%rdx,8) ++ jmp 4f ++2: movq -8(%rdi,%rdx,8),%rcx ++ movq %rcx,-8(%rsi,%rdx,8) ++ subq $1,%rdx ++ jnz 2b ++ ret ++ .align 16 ++3: movq 24(%rdi,%rdx,8),%rcx ++ movq %rcx,24(%rsi,%rdx,8) ++ movq 16(%rdi,%rdx,8),%rcx ++ movq %rcx,16(%rsi,%rdx,8) ++ movq 8(%rdi,%rdx,8),%rcx ++ movq %rcx,8(%rsi,%rdx,8) ++ movq (%rdi,%rdx,8),%rcx ++ movq %rcx,(%rsi,%rdx,8) ++4: subq $4,%rdx ++ jge 3b ++ addq $4,%rdx ++ jg 2b ++ ret ++ ++ # Support for void Copy::arrayof_conjoint_jints(jint* from, ++ # jint* to, ++ # size_t count) ++ # Equivalent to ++ # conjoint_jints_atomic ++ # ++ # If 'from' and/or 'to' are aligned on 4-byte boundaries, we let ++ # the hardware handle it. The two dwords within qwords that span ++ # cache line boundaries will still be loaded and stored atomically. ++ # ++ # rdi - from ++ # rsi - to ++ # rdx - count, treated as ssize_t ++ # ++ .align 16 ++_Copy_arrayof_conjoint_jints: ++_Copy_conjoint_jints_atomic: ++ movq %rdx,%r8 # dword count ++ shrq %rdx # qword count ++ cmpq %rdi,%rsi ++ leaq -4(%rdi,%r8,4),%rax # from + dcount*4 - 4 ++ jbe aci_CopyRight ++ cmpq %rax,%rsi ++ jbe aci_CopyLeft ++aci_CopyRight: ++ leaq -8(%rdi,%rdx,8),%rax # from + qcount*8 - 8 ++ leaq -8(%rsi,%rdx,8),%rcx # to + qcount*8 - 8 ++ negq %rdx ++ jmp 5f ++ .align 16 ++1: movq 8(%rax,%rdx,8),%rsi ++ movq %rsi,8(%rcx,%rdx,8) ++ addq $1,%rdx ++ jnz 1b ++2: testq $1,%r8 # check for trailing dword ++ jz 3f ++ movl 8(%rax),%esi # copy trailing dword ++ movl %esi,8(%rcx) ++3: ret ++ .align 16 ++4: movq -24(%rax,%rdx,8),%rsi ++ movq %rsi,-24(%rcx,%rdx,8) ++ movq -16(%rax,%rdx,8),%rsi ++ movq %rsi,-16(%rcx,%rdx,8) ++ movq -8(%rax,%rdx,8),%rsi ++ movq %rsi,-8(%rcx,%rdx,8) ++ movq (%rax,%rdx,8),%rsi ++ movq %rsi,(%rcx,%rdx,8) ++5: addq $4,%rdx ++ jle 4b ++ subq $4,%rdx ++ jl 1b ++ jmp 2b ++aci_CopyLeft: ++ testq $1,%r8 # check for trailing dword ++ jz 3f ++ movl -4(%rdi,%r8,4),%ecx # copy trailing dword ++ movl %ecx,-4(%rsi,%r8,4) ++ jmp 3f ++1: movq -8(%rdi,%rdx,8),%rcx ++ movq %rcx,-8(%rsi,%rdx,8) ++ subq $1,%rdx ++ jnz 1b ++ ret ++ .align 16 ++2: movq 24(%rdi,%rdx,8),%rcx ++ movq %rcx,24(%rsi,%rdx,8) ++ movq 16(%rdi,%rdx,8),%rcx ++ movq %rcx,16(%rsi,%rdx,8) ++ movq 8(%rdi,%rdx,8),%rcx ++ movq %rcx,8(%rsi,%rdx,8) ++ movq (%rdi,%rdx,8),%rcx ++ movq %rcx,(%rsi,%rdx,8) ++3: subq $4,%rdx ++ jge 2b ++ addq $4,%rdx ++ jg 1b ++ ret ++ ++ # Support for void Copy::arrayof_conjoint_jlongs(jlong* from, ++ # jlong* to, ++ # size_t count) ++ # Equivalent to ++ # conjoint_jlongs_atomic ++ # arrayof_conjoint_oops ++ # conjoint_oops_atomic ++ # ++ # rdi - from ++ # rsi - to ++ # rdx - count, treated as ssize_t ++ # ++ .align 16 ++_Copy_arrayof_conjoint_jlongs: ++_Copy_conjoint_jlongs_atomic: ++ cmpq %rdi,%rsi ++ leaq -8(%rdi,%rdx,8),%rax # from + count*8 - 8 ++ jbe acl_CopyRight ++ cmpq %rax,%rsi ++ jbe acl_CopyLeft ++acl_CopyRight: ++ leaq -8(%rsi,%rdx,8),%rcx # to + count*8 - 8 ++ negq %rdx ++ jmp 3f ++1: movq 8(%rax,%rdx,8),%rsi ++ movq %rsi,8(%rcx,%rdx,8) ++ addq $1,%rdx ++ jnz 1b ++ ret ++ .align 16 ++2: movq -24(%rax,%rdx,8),%rsi ++ movq %rsi,-24(%rcx,%rdx,8) ++ movq -16(%rax,%rdx,8),%rsi ++ movq %rsi,-16(%rcx,%rdx,8) ++ movq -8(%rax,%rdx,8),%rsi ++ movq %rsi,-8(%rcx,%rdx,8) ++ movq (%rax,%rdx,8),%rsi ++ movq %rsi,(%rcx,%rdx,8) ++3: addq $4,%rdx ++ jle 2b ++ subq $4,%rdx ++ jl 1b ++ ret ++4: movq -8(%rdi,%rdx,8),%rcx ++ movq %rcx,-8(%rsi,%rdx,8) ++ subq $1,%rdx ++ jnz 4b ++ ret ++ .align 16 ++5: movq 24(%rdi,%rdx,8),%rcx ++ movq %rcx,24(%rsi,%rdx,8) ++ movq 16(%rdi,%rdx,8),%rcx ++ movq %rcx,16(%rsi,%rdx,8) ++ movq 8(%rdi,%rdx,8),%rcx ++ movq %rcx,8(%rsi,%rdx,8) ++ movq (%rdi,%rdx,8),%rcx ++ movq %rcx,(%rsi,%rdx,8) ++acl_CopyLeft: ++ subq $4,%rdx ++ jge 5b ++ addq $4,%rdx ++ jg 4b ++ ret +diff -urN /tmp/a/vmStructs_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp +--- /tmp/a/vmStructs_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp 2024-10-15 14:59:36.869736563 +0100 +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP ++#define OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP ++ ++// These are the OS and CPU-specific fields, types and integer ++// constants required by the Serviceability Agent. This file is ++// referenced by vmStructs.cpp. ++ ++#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) ++ ++#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) ++ ++#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) ++ ++#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) ++ ++#endif // OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP +diff -urN /tmp/a/vm_version_solaris_x86.cpp b/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp +--- /tmp/a/vm_version_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp 2024-10-15 14:59:36.869816605 +0100 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. 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 "runtime/os.hpp" ++#include "runtime/vm_version.hpp" ++ diff --git a/build/openjdk21/patches/restore_os_solaris.patch b/build/openjdk21/patches/restore_os_solaris.patch new file mode 100644 index 0000000000..dae8aa9064 --- /dev/null +++ b/build/openjdk21/patches/restore_os_solaris.patch @@ -0,0 +1,5846 @@ +diff -urN /tmp/a/attachListener_solaris.cpp b/src/hotspot/os/solaris/attachListener_solaris.cpp +--- /tmp/a/attachListener_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/attachListener_solaris.cpp 2024-10-15 14:59:36.865690786 +0100 +@@ -0,0 +1,749 @@ ++/* ++ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. 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 "logging/log.hpp" ++#include "runtime/interfaceSupport.inline.hpp" ++#include "runtime/os.inline.hpp" ++#include "services/attachListener.hpp" ++#include "services/dtraceAttacher.hpp" ++#include "utilities/vmError.hpp" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++// stropts.h uses STR in stream ioctl defines ++#undef STR ++#include ++#undef STR ++#define STR(a) #a ++ ++// The attach mechanism on Solaris is implemented using the Doors IPC ++// mechanism. The first tool to attempt to attach causes the attach ++// listener thread to startup. This thread creates a door that is ++// associated with a function that enqueues an operation to the attach ++// listener. The door is attached to a file in the file system so that ++// client (tools) can locate it. To enqueue an operation to the VM the ++// client calls through the door which invokes the enqueue function in ++// this process. The credentials of the client are checked and if the ++// effective uid matches this process then the operation is enqueued. ++// When an operation completes the attach listener is required to send the ++// operation result and any result data to the client. In this implementation ++// the result is returned via a UNIX domain socket. A pair of connected ++// sockets (socketpair) is created in the enqueue function and the file ++// descriptor for one of the sockets is returned to the client as the ++// return from the door call. The other end is retained in this process. ++// When the operation completes the result is sent to the client and ++// the socket is closed. ++ ++// forward reference ++class SolarisAttachOperation; ++ ++class SolarisAttachListener: AllStatic { ++ private: ++ ++ // the path to which we attach the door file descriptor ++ static char _door_path[PATH_MAX+1]; ++ static volatile bool _has_door_path; ++ ++ // door descriptor returned by door_create ++ static int _door_descriptor; ++ ++ static bool _atexit_registered; ++ ++ // mutex to protect operation list ++ static pthread_mutex_t _mutex; ++ ++ // semaphore to wakeup listener thread ++ static sema_t _wakeup; ++ ++ static pthread_mutex_t* mutex() { return &_mutex; } ++ static sema_t* wakeup() { return &_wakeup; } ++ ++ // enqueued operation list ++ static SolarisAttachOperation* _head; ++ static SolarisAttachOperation* _tail; ++ ++ static SolarisAttachOperation* head() { return _head; } ++ static void set_head(SolarisAttachOperation* head) { _head = head; } ++ ++ static SolarisAttachOperation* tail() { return _tail; } ++ static void set_tail(SolarisAttachOperation* tail) { _tail = tail; } ++ ++ // create the door ++ static int create_door(); ++ ++ public: ++ enum { ++ ATTACH_PROTOCOL_VER = 1 // protocol version ++ }; ++ enum { ++ ATTACH_ERROR_BADREQUEST = 100, // error code returned by ++ ATTACH_ERROR_BADVERSION = 101, // the door call ++ ATTACH_ERROR_RESOURCE = 102, ++ ATTACH_ERROR_INTERNAL = 103, ++ ATTACH_ERROR_DENIED = 104 ++ }; ++ ++ static void set_door_path(char* path) { ++ if (path == NULL) { ++ _door_path[0] = '\0'; ++ _has_door_path = false; ++ } else { ++ strncpy(_door_path, path, PATH_MAX); ++ _door_path[PATH_MAX] = '\0'; // ensure it's nul terminated ++ _has_door_path = true; ++ } ++ } ++ ++ static void set_door_descriptor(int dd) { _door_descriptor = dd; } ++ ++ // initialize the listener ++ static int init(); ++ ++ static bool has_door_path() { return _has_door_path; } ++ static char* door_path() { return _door_path; } ++ static int door_descriptor() { return _door_descriptor; } ++ ++ // enqueue an operation ++ static void enqueue(SolarisAttachOperation* op); ++ ++ // dequeue an operation ++ static SolarisAttachOperation* dequeue(); ++}; ++ ++ ++// SolarisAttachOperation is an AttachOperation that additionally encapsulates ++// a socket connection to the requesting client/tool. SolarisAttachOperation ++// can additionally be held in a linked list. ++ ++class SolarisAttachOperation: public AttachOperation { ++ private: ++ friend class SolarisAttachListener; ++ ++ // connection to client ++ int _socket; ++ ++ // linked list support ++ SolarisAttachOperation* _next; ++ ++ SolarisAttachOperation* next() { return _next; } ++ void set_next(SolarisAttachOperation* next) { _next = next; } ++ ++ public: ++ void complete(jint res, bufferedStream* st); ++ ++ int socket() const { return _socket; } ++ void set_socket(int s) { _socket = s; } ++ ++ SolarisAttachOperation(char* name) : AttachOperation(name) { ++ set_socket(-1); ++ set_next(NULL); ++ } ++}; ++ ++// statics ++char SolarisAttachListener::_door_path[PATH_MAX+1]; ++volatile bool SolarisAttachListener::_has_door_path; ++int SolarisAttachListener::_door_descriptor = -1; ++bool SolarisAttachListener::_atexit_registered = false; ++pthread_mutex_t SolarisAttachListener::_mutex; ++sema_t SolarisAttachListener::_wakeup; ++SolarisAttachOperation* SolarisAttachListener::_head = NULL; ++SolarisAttachOperation* SolarisAttachListener::_tail = NULL; ++ ++// Supporting class to help split a buffer into individual components ++class ArgumentIterator : public StackObj { ++ private: ++ char* _pos; ++ char* _end; ++ public: ++ ArgumentIterator(char* arg_buffer, size_t arg_size) { ++ _pos = arg_buffer; ++ _end = _pos + arg_size - 1; ++ } ++ char* next() { ++ if (*_pos == '\0') { ++ // advance the iterator if possible (null arguments) ++ if (_pos < _end) { ++ _pos += 1; ++ } ++ return NULL; ++ } ++ char* res = _pos; ++ char* next_pos = strchr(_pos, '\0'); ++ if (next_pos < _end) { ++ next_pos++; ++ } ++ _pos = next_pos; ++ return res; ++ } ++}; ++ ++// Calls from the door function to check that the client credentials ++// match this process. Returns 0 if credentials okay, otherwise -1. ++static int check_credentials() { ++ ucred_t *cred_info = NULL; ++ int ret = -1; // deny by default ++ ++ // get client credentials ++ if (door_ucred(&cred_info) == -1) { ++ return -1; // unable to get them, deny ++ } ++ ++ // get euid/egid from ucred_free ++ uid_t ucred_euid = ucred_geteuid(cred_info); ++ gid_t ucred_egid = ucred_getegid(cred_info); ++ ++ // check that the effective uid/gid matches ++ if (os::Posix::matches_effective_uid_and_gid_or_root(ucred_euid, ucred_egid)) { ++ ret = 0; // allow ++ } ++ ++ ucred_free(cred_info); ++ return ret; ++} ++ ++ ++// Parses the argument buffer to create an AttachOperation that we should ++// enqueue to the attach listener. ++// The buffer is expected to be formatted as follows: ++// 00000 ++// where is the version number (must be "1"), is the command ++// name ("load, "datadump", ...) and is an argument. ++// ++static SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) { ++ // assume bad request until parsed ++ *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST; ++ ++ if (arg_size < 2 || argp[arg_size-1] != '\0') { ++ return NULL; // no ver or not null terminated ++ } ++ ++ // Use supporting class to iterate over the buffer ++ ArgumentIterator args(argp, arg_size); ++ ++ // First check the protocol version ++ char* ver = args.next(); ++ if (ver == NULL) { ++ return NULL; ++ } ++ if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) { ++ *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION; ++ return NULL; ++ } ++ ++ // Get command name and create the operation ++ char* name = args.next(); ++ if (name == NULL || strlen(name) > AttachOperation::name_length_max) { ++ return NULL; ++ } ++ SolarisAttachOperation* op = new SolarisAttachOperation(name); ++ ++ // Iterate over the arguments ++ for (int i=0; iset_arg(i, NULL); ++ } else { ++ if (strlen(arg) > AttachOperation::arg_length_max) { ++ delete op; ++ return NULL; ++ } ++ op->set_arg(i, arg); ++ } ++ } ++ ++ // return operation ++ *err = 0; ++ return op; ++} ++ ++// This is door function which the client executes via a door_call. ++extern "C" { ++ static void enqueue_proc(void* cookie, char* argp, size_t arg_size, ++ door_desc_t* dt, uint_t n_desc) ++ { ++ int return_fd = -1; ++ SolarisAttachOperation* op = NULL; ++ ++ // wait up to 10 seconds for listener to be up and running ++ jint res = 0; ++ int sleep_count = 0; ++ while (!AttachListener::is_initialized()) { ++ sleep(1); // 1 second ++ sleep_count++; ++ if (sleep_count > 10) { // try for 10 seconds ++ debug_only(warning("door_call when not enabled")); ++ res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL; ++ break; ++ } ++ } ++ ++ // check client credentials ++ if (res == 0) { ++ if (check_credentials() != 0) { ++ res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED; ++ } ++ } ++ ++ // if we are stopped at ShowMessageBoxOnError then maybe we can ++ // load a diagnostic library ++ if (res == 0 && VMError::is_error_reported()) { ++ if (ShowMessageBoxOnError) { ++ // TBD - support loading of diagnostic library here ++ } ++ ++ // can't enqueue operation after fatal error ++ res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; ++ } ++ ++ // create the operation ++ if (res == 0) { ++ int err; ++ op = create_operation(argp, arg_size, &err); ++ res = (op == NULL) ? (jint)err : 0; ++ } ++ ++ // create a pair of connected sockets. Store the file descriptor ++ // for one end in the operation and enqueue the operation. The ++ // file descriptor for the other end will be returned to the client. ++ if (res == 0) { ++ int s[2]; ++ if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) { ++ delete op; ++ res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE; ++ } else { ++ op->set_socket(s[0]); ++ return_fd = s[1]; ++ SolarisAttachListener::enqueue(op); ++ } ++ } ++ ++ // Return 0 (success) + file descriptor, or non-0 (error) ++ if (res == 0) { ++ door_desc_t desc; ++ // DOOR_RELEASE flag makes sure fd is closed after passing it to ++ // the client. See door_return(3DOOR) man page. ++ desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; ++ desc.d_data.d_desc.d_descriptor = return_fd; ++ door_return((char*)&res, sizeof(res), &desc, 1); ++ } else { ++ door_return((char*)&res, sizeof(res), NULL, 0); ++ } ++ } ++} ++ ++// atexit hook to detach the door and remove the file ++extern "C" { ++ static void listener_cleanup() { ++ int dd = SolarisAttachListener::door_descriptor(); ++ if (dd >= 0) { ++ SolarisAttachListener::set_door_descriptor(-1); ++ ::close(dd); ++ } ++ if (SolarisAttachListener::has_door_path()) { ++ char* path = SolarisAttachListener::door_path(); ++ ::fdetach(path); ++ ::unlink(path); ++ SolarisAttachListener::set_door_path(NULL); ++ } ++ } ++} ++ ++// Create the door ++int SolarisAttachListener::create_door() { ++ char door_path[PATH_MAX+1]; ++ char initial_path[PATH_MAX+1]; ++ int fd, res; ++ ++ // register exit function ++ if (!_atexit_registered) { ++ _atexit_registered = true; ++ ::atexit(listener_cleanup); ++ } ++ ++ // create the door descriptor ++ int dd = ::door_create(enqueue_proc, NULL, 0); ++ if (dd < 0) { ++ return -1; ++ } ++ ++ // create initial file to attach door descriptor ++ snprintf(door_path, sizeof(door_path), "%s/.java_pid%d", ++ os::get_temp_directory(), os::current_process_id()); ++ snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path); ++ RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd); ++ if (fd == -1) { ++ log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno); ++ ::door_revoke(dd); ++ return -1; ++ } ++ assert(fd >= 0, "bad file descriptor"); ++ ::close(fd); ++ ++ // attach the door descriptor to the file ++ if ((res = ::fattach(dd, initial_path)) == -1) { ++ // if busy then detach and try again ++ if (errno == EBUSY) { ++ ::fdetach(initial_path); ++ res = ::fattach(dd, initial_path); ++ } ++ if (res == -1) { ++ log_debug(attach)("unable to create door - fattach failed (%d)", errno); ++ ::door_revoke(dd); ++ dd = -1; ++ } ++ } ++ ++ // rename file so that clients can attach ++ if (dd >= 0) { ++ if (::rename(initial_path, door_path) == -1) { ++ ::close(dd); ++ ::fdetach(initial_path); ++ log_debug(attach)("unable to create door - rename %s to %s failed (%d)", initial_path, door_path, errno); ++ dd = -1; ++ } ++ } ++ if (dd >= 0) { ++ set_door_descriptor(dd); ++ set_door_path(door_path); ++ log_trace(attach)("door file %s created successfully", door_path); ++ } else { ++ // unable to create door, attach it to file, or rename file into place ++ ::unlink(initial_path); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++// Initialization - create the door, locks, and other initialization ++int SolarisAttachListener::init() { ++ if (create_door()) { ++ return -1; ++ } ++ ++ int status = pthread_mutex_init(&_mutex, NULL); ++ assert_status(status==0, status, "mutex_init"); ++ ++ status = ::sema_init(&_wakeup, 0, NULL, NULL); ++ assert_status(status==0, status, "sema_init"); ++ ++ set_head(NULL); ++ set_tail(NULL); ++ ++ return 0; ++} ++ ++// Dequeue an operation ++SolarisAttachOperation* SolarisAttachListener::dequeue() { ++ for (;;) { ++ int res; ++ ++ // wait for somebody to enqueue something ++ while ((res = ::sema_wait(wakeup())) == EINTR) ++ ; ++ if (res) { ++ warning("sema_wait failed: %s", os::strerror(res)); ++ return NULL; ++ } ++ ++ // lock the list ++ res = pthread_mutex_lock(mutex()); ++ assert(res == 0, "mutex_lock failed"); ++ ++ // remove the head of the list ++ SolarisAttachOperation* op = head(); ++ if (op != NULL) { ++ set_head(op->next()); ++ if (head() == NULL) { ++ set_tail(NULL); ++ } ++ } ++ ++ // unlock ++ pthread_mutex_unlock(mutex()); ++ ++ // if we got an operation when return it. ++ if (op != NULL) { ++ return op; ++ } ++ } ++} ++ ++// Enqueue an operation ++void SolarisAttachListener::enqueue(SolarisAttachOperation* op) { ++ // lock list ++ int res = pthread_mutex_lock(mutex()); ++ assert(res == 0, "mutex_lock failed"); ++ ++ // enqueue at tail ++ op->set_next(NULL); ++ if (head() == NULL) { ++ set_head(op); ++ } else { ++ tail()->set_next(op); ++ } ++ set_tail(op); ++ ++ // wakeup the attach listener ++ RESTARTABLE(::sema_post(wakeup()), res); ++ assert(res == 0, "sema_post failed"); ++ ++ // unlock ++ pthread_mutex_unlock(mutex()); ++} ++ ++ ++// support function - writes the (entire) buffer to a socket ++static int write_fully(int s, char* buf, int len) { ++ do { ++ int n = ::write(s, buf, len); ++ if (n == -1) { ++ if (errno != EINTR) return -1; ++ } else { ++ buf += n; ++ len -= n; ++ } ++ } ++ while (len > 0); ++ return 0; ++} ++ ++// Complete an operation by sending the operation result and any result ++// output to the client. At this time the socket is in blocking mode so ++// potentially we can block if there is a lot of data and the client is ++// non-responsive. For most operations this is a non-issue because the ++// default send buffer is sufficient to buffer everything. In the future ++// if there are operations that involves a very big reply then it the ++// socket could be made non-blocking and a timeout could be used. ++ ++void SolarisAttachOperation::complete(jint res, bufferedStream* st) { ++ if (this->socket() >= 0) { ++ JavaThread* thread = JavaThread::current(); ++ ThreadBlockInVM tbivm(thread); ++ ++ // write operation result ++ char msg[32]; ++ sprintf(msg, "%d\n", res); ++ int rc = write_fully(this->socket(), msg, strlen(msg)); ++ ++ // write any result data ++ if (rc == 0) { ++ write_fully(this->socket(), (char*) st->base(), st->size()); ++ ::shutdown(this->socket(), 2); ++ } ++ ++ // close socket and we're done ++ ::close(this->socket()); ++ } ++ delete this; ++} ++ ++ ++// AttachListener functions ++ ++AttachOperation* AttachListener::dequeue() { ++ JavaThread* thread = JavaThread::current(); ++ ThreadBlockInVM tbivm(thread); ++ ++ AttachOperation* op = SolarisAttachListener::dequeue(); ++ ++ return op; ++} ++ ++ ++// Performs initialization at vm startup ++// For Solaris we remove any stale .java_pid file which could cause ++// an attaching process to think we are ready to receive a door_call ++// before we are properly initialized ++ ++void AttachListener::vm_start() { ++ char fn[PATH_MAX+1]; ++ struct stat64 st; ++ int ret; ++ ++ int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d", ++ os::get_temp_directory(), os::current_process_id()); ++ assert(n < sizeof(fn), "java_pid file name buffer overflow"); ++ ++ RESTARTABLE(::stat64(fn, &st), ret); ++ if (ret == 0) { ++ ret = ::unlink(fn); ++ if (ret == -1) { ++ log_debug(attach)("Failed to remove stale attach pid file at %s", fn); ++ } ++ } ++} ++ ++int AttachListener::pd_init() { ++ JavaThread* thread = JavaThread::current(); ++ ThreadBlockInVM tbivm(thread); ++ ++ int ret_code = SolarisAttachListener::init(); ++ ++ return ret_code; ++} ++ ++// Attach Listener is started lazily except in the case when ++// +ReduseSignalUsage is used ++bool AttachListener::init_at_startup() { ++ if (ReduceSignalUsage) { ++ return true; ++ } else { ++ return false; ++ } ++} ++ ++bool AttachListener::check_socket_file() { ++ int ret; ++ struct stat64 st; ++ ret = stat64(SolarisAttachListener::door_path(), &st); ++ if (ret == -1) { // need to restart attach listener. ++ log_debug(attach)("Door file %s does not exist - Restart Attach Listener", ++ SolarisAttachListener::door_path()); ++ ++ listener_cleanup(); ++ ++ // wait to terminate current attach listener instance... ++ while (AttachListener::transit_state(AL_INITIALIZING, ++ AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) { ++ os::naked_yield(); ++ } ++ return is_init_trigger(); ++ } ++ return false; ++} ++ ++// If the file .attach_pid exists in the working directory ++// or /tmp then this is the trigger to start the attach mechanism ++bool AttachListener::is_init_trigger() { ++ if (init_at_startup() || is_initialized()) { ++ return false; // initialized at startup or already initialized ++ } ++ char fn[PATH_MAX + 1]; ++ int ret; ++ struct stat64 st; ++ sprintf(fn, ".attach_pid%d", os::current_process_id()); ++ RESTARTABLE(::stat64(fn, &st), ret); ++ if (ret == -1) { ++ log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); ++ snprintf(fn, sizeof(fn), "%s/.attach_pid%d", ++ os::get_temp_directory(), os::current_process_id()); ++ RESTARTABLE(::stat64(fn, &st), ret); ++ if (ret == -1) { ++ log_debug(attach)("Failed to find attach file: %s", fn); ++ } ++ } ++ if (ret == 0) { ++ // simple check to avoid starting the attach mechanism when ++ // a bogus non-root user creates the file ++ if (os::Posix::matches_effective_uid_or_root(st.st_uid)) { ++ init(); ++ log_trace(attach)("Attach triggered by %s", fn); ++ return true; ++ } else { ++ log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid()); ++ } ++ } ++ return false; ++} ++ ++// if VM aborts then detach/cleanup ++void AttachListener::abort() { ++ listener_cleanup(); ++} ++ ++void AttachListener::pd_data_dump() { ++ os::signal_notify(SIGQUIT); ++} ++ ++static jint enable_dprobes(AttachOperation* op, outputStream* out) { ++ const char* probe = op->arg(0); ++ if (probe == NULL || probe[0] == '\0') { ++ out->print_cr("No probe specified"); ++ return JNI_ERR; ++ } else { ++ char *end; ++ long val = strtol(probe, &end, 10); ++ if (end == probe || val < 0 || val > INT_MAX) { ++ out->print_cr("invalid probe type"); ++ return JNI_ERR; ++ } else { ++ int probe_typess = (int) val; ++ DTrace::enable_dprobes(probe_typess); ++ return JNI_OK; ++ } ++ } ++} ++ ++// platform specific operations table ++static AttachOperationFunctionInfo funcs[] = { ++ { "enabledprobes", enable_dprobes }, ++ { NULL, NULL } ++}; ++ ++AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* name) { ++ int i; ++ for (i = 0; funcs[i].name != NULL; i++) { ++ if (strcmp(funcs[i].name, name) == 0) { ++ return &funcs[i]; ++ } ++ } ++ return NULL; ++} ++ ++// Solaris specific global flag set. ++jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) { ++ const char* name = op->arg(0); ++ assert(name != NULL, "flag name should not be null"); ++ bool flag = true; ++ const char* arg1; ++ if ((arg1 = op->arg(1)) != NULL) { ++ char *end; ++ flag = (strtol(arg1, &end, 10) != 0); ++ if (arg1 == end) { ++ out->print_cr("flag value has to be an integer"); ++ return JNI_ERR; ++ } ++ } ++ ++ if (strcmp(name, "DTraceMonitorProbes") == 0) { ++ DTrace::set_monitor_dprobes(flag); ++ return JNI_OK; ++ } ++ ++ out->print_cr("flag '%s' cannot be changed", name); ++ return JNI_ERR; ++} ++ ++void AttachListener::pd_detachall() { ++ DTrace::detach_all_clients(); ++} +diff -urN /tmp/a/c1_globals_solaris.hpp b/src/hotspot/os/solaris/c1_globals_solaris.hpp +--- /tmp/a/c1_globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/c1_globals_solaris.hpp 2024-10-15 14:59:36.865791389 +0100 +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP ++#define OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP ++ ++#include "utilities/globalDefinitions.hpp" ++#include "utilities/macros.hpp" ++ ++// ++// Sets the default values for operating system dependent flags used by the ++// client compiler. (see c1_globals.hpp) ++// ++ ++#endif // OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP +diff -urN /tmp/a/c2_globals_solaris.hpp b/src/hotspot/os/solaris/c2_globals_solaris.hpp +--- /tmp/a/c2_globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/c2_globals_solaris.hpp 2024-10-15 14:59:36.865879080 +0100 +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP ++#define OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP ++ ++#include "utilities/globalDefinitions.hpp" ++#include "utilities/macros.hpp" ++ ++// ++// Sets the default values for operating system dependent flags used by the ++// server compiler. (see c2_globals.hpp) ++// ++ ++#endif // OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP +diff -urN /tmp/a/decoder_solaris.cpp b/src/hotspot/os/solaris/decoder_solaris.cpp +--- /tmp/a/decoder_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/decoder_solaris.cpp 2024-10-15 14:59:36.892630480 +0100 +@@ -0,0 +1,45 @@ ++/* ++ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. 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 "jvm.h" ++#include "utilities/decoder_elf.hpp" ++ ++#include ++ ++bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { ++ int status; ++ char* result; ++ size_t size = (size_t)buflen; ++ // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small, ++ // __cxa_demangle will call system "realloc" for additional memory, which ++ // may use different malloc/realloc mechanism that allocates 'buf'. ++ if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) { ++ jio_snprintf(buf, buflen, "%s", result); ++ // call c library's free ++ ::free(result); ++ return true; ++ } ++ return false; ++} ++ +diff -urN /tmp/a/dtrace/jhelper.d b/src/hotspot/os/solaris/dtrace/jhelper.d +--- /tmp/a/dtrace/jhelper.d 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/dtrace/jhelper.d 2024-10-15 14:59:36.866184620 +0100 +@@ -0,0 +1,540 @@ ++/* ++ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++/* This file is auto-generated */ ++#include "JvmOffsetsIndex.h" ++ ++#define DEBUG ++ ++#ifdef DEBUG ++#define MARK_LINE this->line = __LINE__ ++#else ++#define MARK_LINE ++#endif ++ ++#ifdef _LP64 ++#define STACK_BIAS 0x7ff ++#define pointer uint64_t ++#else ++#define STACK_BIAS 0 ++#define pointer uint32_t ++#endif ++ ++extern pointer __JvmOffsets; ++ ++/* GrowableArray* */ ++extern pointer __1cJCodeCacheG_heaps_; ++ ++extern pointer __1cIUniverseO_collectedHeap_; ++ ++extern pointer __1cHnmethodG__vtbl_; ++extern pointer __1cGMethodG__vtbl_; ++extern pointer __1cKBufferBlobG__vtbl_; ++ ++#define copyin_ptr(ADDR) *(pointer*) copyin((pointer) (ADDR), sizeof(pointer)) ++#define copyin_uchar(ADDR) *(uchar_t*) copyin((pointer) (ADDR), sizeof(uchar_t)) ++#define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t)) ++#define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t)) ++#define copyin_int32(ADDR) *(int32_t*) copyin((pointer) (ADDR), sizeof(int32_t)) ++#define copyin_uint8(ADDR) *(uint8_t*) copyin((pointer) (ADDR), sizeof(uint8_t)) ++ ++#define copyin_offset(JVM_CONST) JVM_CONST = \ ++ copyin_int32(JvmOffsetsPtr + IDX_##JVM_CONST * sizeof(int32_t)) ++ ++int init_done; ++ ++dtrace:helper:ustack: ++{ ++ MARK_LINE; ++ this->done = 0; ++ /* ++ * TBD: ++ * Here we initialize init_done, otherwise jhelper does not work. ++ * Therefore, copyin_offset() statements work multiple times now. ++ * There is a hope we could avoid it in the future, and so, ++ * this initialization can be removed. ++ */ ++ init_done = 0; ++ this->error = (char *) NULL; ++ this->result = (char *) NULL; ++ this->isMethod = 0; ++ this->codecache = 0; ++ this->klass = (pointer) NULL; ++ this->vtbl = (pointer) NULL; ++ this->suffix = '\0'; ++} ++ ++dtrace:helper:ustack: ++{ ++ MARK_LINE; ++ /* Initialization of JvmOffsets constants */ ++ JvmOffsetsPtr = (pointer) &``__JvmOffsets; ++} ++ ++dtrace:helper:ustack: ++/!init_done && !this->done/ ++{ ++ MARK_LINE; ++ ++ copyin_offset(POINTER_SIZE); ++ copyin_offset(COMPILER); ++ copyin_offset(OFFSET_CollectedHeap_reserved); ++ copyin_offset(OFFSET_MemRegion_start); ++ copyin_offset(OFFSET_MemRegion_word_size); ++ copyin_offset(SIZE_HeapWord); ++ ++ copyin_offset(OFFSET_interpreter_frame_method); ++ copyin_offset(OFFSET_Klass_name); ++ copyin_offset(OFFSET_ConstantPool_pool_holder); ++ ++ copyin_offset(OFFSET_HeapBlockHeader_used); ++ copyin_offset(OFFSET_oopDesc_metadata); ++ ++ copyin_offset(OFFSET_Symbol_length); ++ copyin_offset(OFFSET_Symbol_body); ++ ++ copyin_offset(OFFSET_Method_constMethod); ++ copyin_offset(OFFSET_ConstMethod_constants); ++ copyin_offset(OFFSET_ConstMethod_name_index); ++ copyin_offset(OFFSET_ConstMethod_signature_index); ++ ++ copyin_offset(OFFSET_CodeHeap_memory); ++ copyin_offset(OFFSET_CodeHeap_segmap); ++ copyin_offset(OFFSET_CodeHeap_log2_segment_size); ++ ++ copyin_offset(OFFSET_GrowableArray_CodeHeap_data); ++ copyin_offset(OFFSET_GrowableArray_CodeHeap_len); ++ ++ copyin_offset(OFFSET_VirtualSpace_low); ++ copyin_offset(OFFSET_VirtualSpace_high); ++ ++ copyin_offset(OFFSET_CodeBlob_name); ++ ++ copyin_offset(OFFSET_nmethod_method); ++ copyin_offset(SIZE_HeapBlockHeader); ++ copyin_offset(SIZE_oopDesc); ++ copyin_offset(SIZE_ConstantPool); ++ ++ copyin_offset(OFFSET_NarrowPtrStruct_base); ++ copyin_offset(OFFSET_NarrowPtrStruct_shift); ++ ++ /* ++ * The PC to translate is in arg0. ++ */ ++ this->pc = arg0; ++ ++#if defined(__i386) || defined(__amd64) ++ this->methodPtr = copyin_ptr(arg1 + OFFSET_interpreter_frame_method); ++#else ++#error "Don't know architecture" ++#endif ++ ++ /* Read address of GrowableArray */ ++ // this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_); ++ this->code_heaps_address = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cJCodeCacheG_heaps_ ) , sizeof ( uint64_t ) ); ++ ++ /* Read address of _data array field in GrowableArray */ ++ this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data); ++ this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len); ++ ++ this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_; ++ ++ /* ++ * Get Java heap bounds ++ */ ++ // this->Universe_collectedHeap = copyin_ptr(&``__1cIUniverseO_collectedHeap_); ++ this->Universe_collectedHeap = * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cIUniverseO_collectedHeap_ ) , sizeof ( uint64_t ) ); ++ ++ this->heap_start = copyin_ptr(this->Universe_collectedHeap + ++ OFFSET_CollectedHeap_reserved + ++ OFFSET_MemRegion_start); ++ this->heap_size = SIZE_HeapWord * ++ copyin_ptr(this->Universe_collectedHeap + ++ OFFSET_CollectedHeap_reserved + ++ OFFSET_MemRegion_word_size ++ ); ++ this->heap_end = this->heap_start + this->heap_size; ++} ++ ++/* ++ * IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in ++ * the code cache. If more code heaps are added the following probes have to ++ * be extended. This is done by simply adding a probe to get the heap bounds ++ * and another probe to set the code heap address of the newly created heap. ++ */ ++ ++/* ++ * ----- BEGIN: Get bounds of code heaps ----- ++ */ ++dtrace:helper:ustack: ++/init_done < 1 && this->number_of_heaps >= 1 && !this->done/ ++{ ++ MARK_LINE; ++ /* CodeHeap 1 */ ++ init_done = 1; ++ this->code_heap1_address = copyin_ptr(this->code_heaps_array_address); ++ this->code_heap1_low = copyin_ptr(this->code_heap1_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); ++ this->code_heap1_high = copyin_ptr(this->code_heap1_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); ++} ++ ++dtrace:helper:ustack: ++/init_done < 2 && this->number_of_heaps >= 2 && !this->done/ ++{ ++ MARK_LINE; ++ /* CodeHeap 2 */ ++ init_done = 2; ++ this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; ++ this->code_heap2_address = copyin_ptr(this->code_heaps_array_address); ++ this->code_heap2_low = copyin_ptr(this->code_heap2_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); ++ this->code_heap2_high = copyin_ptr(this->code_heap2_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); ++} ++ ++dtrace:helper:ustack: ++/init_done < 3 && this->number_of_heaps >= 3 && !this->done/ ++{ ++ /* CodeHeap 3 */ ++ init_done = 3; ++ this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; ++ this->code_heap3_address = copyin_ptr(this->code_heaps_array_address); ++ this->code_heap3_low = copyin_ptr(this->code_heap3_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); ++ this->code_heap3_high = copyin_ptr(this->code_heap3_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); ++} ++ ++dtrace:helper:ustack: ++/init_done < 4 && this->number_of_heaps >= 4 && !this->done/ ++{ ++ /* CodeHeap 4 */ ++ init_done = 4; ++ this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; ++ this->code_heap4_address = copyin_ptr(this->code_heaps_array_address); ++ this->code_heap4_low = copyin_ptr(this->code_heap4_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); ++ this->code_heap4_high = copyin_ptr(this->code_heap4_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); ++} ++ ++dtrace:helper:ustack: ++/init_done < 5 && this->number_of_heaps >= 5 && !this->done/ ++{ ++ /* CodeHeap 5 */ ++ init_done = 5; ++ this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE; ++ this->code_heap5_address = copyin_ptr(this->code_heaps_array_address); ++ this->code_heap5_low = copyin_ptr(this->code_heap5_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); ++ this->code_heap5_high = copyin_ptr(this->code_heap5_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high); ++} ++/* ++ * ----- END: Get bounds of code heaps ----- ++ */ ++ ++/* ++ * ----- BEGIN: Get address of the code heap pc points to ----- ++ */ ++dtrace:helper:ustack: ++/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/ ++{ ++ MARK_LINE; ++ this->codecache = 1; ++ this->code_heap_address = this->code_heap1_address; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/ ++{ ++ MARK_LINE; ++ this->codecache = 1; ++ this->code_heap_address = this->code_heap2_address; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/ ++{ ++ MARK_LINE; ++ this->codecache = 1; ++ this->code_heap_address = this->code_heap3_address; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/ ++{ ++ MARK_LINE; ++ this->codecache = 1; ++ this->code_heap_address = this->code_heap4_address; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/ ++{ ++ MARK_LINE; ++ this->codecache = 1; ++ this->code_heap_address = this->code_heap5_address; ++} ++/* ++ * ----- END: Get address of the code heap pc points to ----- ++ */ ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache/ ++{ ++ MARK_LINE; ++ /* ++ * Get code heap configuration ++ */ ++ this->code_heap_low = copyin_ptr(this->code_heap_address + ++ OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low); ++ this->code_heap_segmap_low = copyin_ptr(this->code_heap_address + ++ OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low); ++ this->code_heap_log2_segment_size = copyin_uint32( ++ this->code_heap_address + OFFSET_CodeHeap_log2_segment_size); ++ ++ /* ++ * Find start ++ */ ++ this->segment = (this->pc - this->code_heap_low) >> ++ this->code_heap_log2_segment_size; ++ this->block = this->code_heap_segmap_low; ++ this->tag = copyin_uchar(this->block + this->segment); ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache && this->tag > 0/ ++{ ++ MARK_LINE; ++ this->tag = copyin_uchar(this->block + this->segment); ++ this->segment = this->segment - this->tag; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache && this->tag > 0/ ++{ ++ MARK_LINE; ++ this->tag = copyin_uchar(this->block + this->segment); ++ this->segment = this->segment - this->tag; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache && this->tag > 0/ ++{ ++ MARK_LINE; ++ this->tag = copyin_uchar(this->block + this->segment); ++ this->segment = this->segment - this->tag; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache && this->tag > 0/ ++{ ++ MARK_LINE; ++ this->tag = copyin_uchar(this->block + this->segment); ++ this->segment = this->segment - this->tag; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache && this->tag > 0/ ++{ ++ MARK_LINE; ++ this->tag = copyin_uchar(this->block + this->segment); ++ this->segment = this->segment - this->tag; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache && this->tag > 0/ ++{ ++ MARK_LINE; ++ this->error = ""; ++ this->done = 1; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache/ ++{ ++ MARK_LINE; ++ this->block = this->code_heap_low + ++ (this->segment << this->code_heap_log2_segment_size); ++ this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used); ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache && !this->used/ ++{ ++ MARK_LINE; ++ this->error = ""; ++ this->done = 1; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache/ ++{ ++ MARK_LINE; ++ this->start = this->block + SIZE_HeapBlockHeader; ++ this->vtbl = copyin_ptr(this->start); ++ ++ this->nmethod_vtbl = (pointer) &``__1cHnmethodG__vtbl_; ++ this->BufferBlob_vtbl = (pointer) &``__1cKBufferBlobG__vtbl_; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->vtbl == this->nmethod_vtbl/ ++{ ++ MARK_LINE; ++ this->methodPtr = copyin_ptr(this->start + OFFSET_nmethod_method); ++ this->suffix = '*'; ++ this->isMethod = 1; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->vtbl == this->BufferBlob_vtbl/ ++{ ++ MARK_LINE; ++ this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name); ++} ++ ++ ++dtrace:helper:ustack: ++/!this->done && this->vtbl == this->BufferBlob_vtbl && this->methodPtr != 0/ ++{ ++ MARK_LINE; ++ this->klass = copyin_ptr(this->methodPtr); ++ this->isMethod = this->klass == this->Method_vtbl; ++ this->done = !this->isMethod; ++} ++ ++dtrace:helper:ustack: ++/!this->done && !this->isMethod/ ++{ ++ MARK_LINE; ++ this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name); ++ this->result = this->name != 0 ? copyinstr(this->name) : ""; ++ this->done = 1; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->isMethod/ ++{ ++ MARK_LINE; ++ this->constMethod = copyin_ptr(this->methodPtr + ++ OFFSET_Method_constMethod); ++ ++ this->nameIndex = copyin_uint16(this->constMethod + ++ OFFSET_ConstMethod_name_index); ++ ++ this->signatureIndex = copyin_uint16(this->constMethod + ++ OFFSET_ConstMethod_signature_index); ++ ++ this->constantPool = copyin_ptr(this->constMethod + ++ OFFSET_ConstMethod_constants); ++ ++ this->nameSymbol = copyin_ptr(this->constantPool + ++ this->nameIndex * sizeof (pointer) + SIZE_ConstantPool); ++ /* The symbol is a CPSlot and has lower bit set to indicate metadata */ ++ this->nameSymbol &= (~1); /* remove metadata lsb */ ++ ++ this->nameSymbolLength = copyin_uint16(this->nameSymbol + ++ OFFSET_Symbol_length); ++ ++ this->signatureSymbol = copyin_ptr(this->constantPool + ++ this->signatureIndex * sizeof (pointer) + SIZE_ConstantPool); ++ this->signatureSymbol &= (~1); /* remove metadata lsb */ ++ ++ this->signatureSymbolLength = copyin_uint16(this->signatureSymbol + ++ OFFSET_Symbol_length); ++ ++ this->klassPtr = copyin_ptr(this->constantPool + ++ OFFSET_ConstantPool_pool_holder); ++ ++ this->klassSymbol = copyin_ptr(this->klassPtr + ++ OFFSET_Klass_name); ++ ++ this->klassSymbolLength = copyin_uint16(this->klassSymbol + ++ OFFSET_Symbol_length); ++ ++ /* ++ * Enough for three strings, plus the '.', plus the trailing '\0'. ++ */ ++ this->result = (char *) alloca(this->klassSymbolLength + ++ this->nameSymbolLength + ++ this->signatureSymbolLength + 2 + 1); ++ ++ copyinto(this->klassSymbol + OFFSET_Symbol_body, ++ this->klassSymbolLength, this->result); ++ ++ /* ++ * Add the '.' between the class and the name. ++ */ ++ this->result[this->klassSymbolLength] = '.'; ++ ++ copyinto(this->nameSymbol + OFFSET_Symbol_body, ++ this->nameSymbolLength, ++ this->result + this->klassSymbolLength + 1); ++ ++ copyinto(this->signatureSymbol + OFFSET_Symbol_body, ++ this->signatureSymbolLength, ++ this->result + this->klassSymbolLength + ++ this->nameSymbolLength + 1); ++ ++ /* ++ * Now we need to add a trailing '\0' and possibly a tag character. ++ */ ++ this->result[this->klassSymbolLength + 1 + ++ this->nameSymbolLength + ++ this->signatureSymbolLength] = this->suffix; ++ this->result[this->klassSymbolLength + 2 + ++ this->nameSymbolLength + ++ this->signatureSymbolLength] = '\0'; ++ ++ this->done = 1; ++} ++ ++dtrace:helper:ustack: ++/this->done && this->error == (char *) NULL/ ++{ ++ this->result; ++} ++ ++dtrace:helper:ustack: ++/this->done && this->error != (char *) NULL/ ++{ ++ this->error; ++} ++ ++dtrace:helper:ustack: ++/!this->done && this->codecache/ ++{ ++ this->done = 1; ++ "error"; ++} ++ ++ ++dtrace:helper:ustack: ++/!this->done/ ++{ ++ NULL; ++} +diff -urN /tmp/a/globals_solaris.hpp b/src/hotspot/os/solaris/globals_solaris.hpp +--- /tmp/a/globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/globals_solaris.hpp 2024-10-15 14:59:36.866277900 +0100 +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2005, 2020, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_SOLARIS_GLOBALS_SOLARIS_HPP ++#define OS_SOLARIS_GLOBALS_SOLARIS_HPP ++ ++// ++// Defines Solaris specific flags. They are not available on other platforms. ++// ++#define RUNTIME_OS_FLAGS(develop, \ ++ develop_pd, \ ++ product, \ ++ product_pd, \ ++ notproduct, \ ++ range, \ ++ constraint) ++ ++// ++// Defines Solaris-specific default values. The flags are available on all ++// platforms, but they may have different default values on other platforms. ++// ++define_pd_global(size_t, PreTouchParallelChunkSize, 1 * G); ++define_pd_global(bool, UseLargePages, true); ++define_pd_global(bool, UseLargePagesIndividualAllocation, false); ++define_pd_global(bool, UseOSErrorReporting, false); ++define_pd_global(bool, UseThreadPriorities, false); ++ ++#endif // OS_SOLARIS_GLOBALS_SOLARIS_HPP +diff -urN /tmp/a/osThread_solaris.cpp b/src/hotspot/os/solaris/osThread_solaris.cpp +--- /tmp/a/osThread_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/osThread_solaris.cpp 2024-10-15 14:59:36.866366994 +0100 +@@ -0,0 +1,47 @@ ++/* ++ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++// no precompiled headers ++#include "runtime/handles.inline.hpp" ++#include "runtime/mutexLocker.hpp" ++#include "runtime/os.hpp" ++#include "runtime/osThread.hpp" ++#include "runtime/safepoint.hpp" ++#include "runtime/vmThread.hpp" ++ ++#include ++ ++ // *************************************************************** ++ // Platform dependent initialization and cleanup ++ // *************************************************************** ++ ++void OSThread::pd_initialize() { ++ _thread_id = 0; ++ sigemptyset(&_caller_sigmask); ++ ++ _vm_created_thread = false; ++} ++ ++void OSThread::pd_destroy() { ++} +diff -urN /tmp/a/osThread_solaris.hpp b/src/hotspot/os/solaris/osThread_solaris.hpp +--- /tmp/a/osThread_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/osThread_solaris.hpp 2024-10-15 14:59:36.866470811 +0100 +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_SOLARIS_OSTHREAD_SOLARIS_HPP ++#define OS_SOLARIS_OSTHREAD_SOLARIS_HPP ++ ++// This is embedded via include into the class OSThread ++ public: ++ typedef thread_t thread_id_t; ++ ++ private: ++ uint _lwp_id; // lwp ID, only used with bound threads ++ int _native_priority; // Saved native priority when starting ++ // a bound thread ++ sigset_t _caller_sigmask; // Caller's signal mask ++ bool _vm_created_thread; // true if the VM created this thread, ++ // false if primary thread or attached thread ++ public: ++ uint lwp_id() const { return _lwp_id; } ++ int native_priority() const { return _native_priority; } ++ ++ // Set and get state of _vm_created_thread flag ++ void set_vm_created() { _vm_created_thread = true; } ++ bool is_vm_created() { return _vm_created_thread; } ++ ++ // Methods to save/restore caller's signal mask ++ sigset_t caller_sigmask() const { return _caller_sigmask; } ++ void set_caller_sigmask(sigset_t sigmask) { _caller_sigmask = sigmask; } ++ ++#ifndef PRODUCT ++ // Used for debugging, return a unique integer for each thread. ++ int thread_identifier() const { return _thread_id; } ++#endif ++#ifdef ASSERT ++ // On solaris reposition can fail in two ways: ++ // 1: a mismatched pc, because signal is delivered too late, target thread ++ // is resumed. ++ // 2: on a timeout where signal is lost, target thread is resumed. ++ bool valid_reposition_failure() { ++ // only 1 and 2 can happen and we can handle both of them ++ return true; ++ } ++#endif ++ void set_lwp_id(uint id) { _lwp_id = id; } ++ void set_native_priority(int prio) { _native_priority = prio; } ++ ++ public: ++ pthread_t pthread_id() const { ++ // Here: same as OSThread::thread_id() ++ return _thread_id; ++ } ++ SuspendResume sr; ++ ++ private: ++ void* _siginfo; ++ ucontext_t* _ucontext; ++ ++ public: ++ void set_siginfo(void* ptr) { _siginfo = ptr; } ++ ucontext_t* ucontext() const { return _ucontext; } ++ void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; } ++ ++ // *************************************************************** ++ // Platform dependent initialization and cleanup ++ // *************************************************************** ++ ++private: ++ ++ void pd_initialize(); ++ void pd_destroy(); ++ ++#endif // OS_SOLARIS_OSTHREAD_SOLARIS_HPP +diff -urN /tmp/a/os_perf_solaris.cpp b/src/hotspot/os/solaris/os_perf_solaris.cpp +--- /tmp/a/os_perf_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/os_perf_solaris.cpp 2024-10-15 14:59:36.866740494 +0100 +@@ -0,0 +1,808 @@ ++/* ++ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. 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 "jvm.h" ++#include "memory/allocation.inline.hpp" ++#include "runtime/os.hpp" ++#include "runtime/os_perf.hpp" ++#include "runtime/vm_version.hpp" ++#include "os_solaris.inline.hpp" ++#include "utilities/globalDefinitions.hpp" ++#include "utilities/macros.hpp" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static const double NANOS_PER_SEC = 1000000000.0; ++ ++struct CPUPerfTicks { ++ kstat_t* kstat; ++ uint64_t last_idle; ++ uint64_t last_total; ++ double last_ratio; ++}; ++ ++struct CPUPerfCounters { ++ int nProcs; ++ CPUPerfTicks* jvmTicks; ++ kstat_ctl_t* kstat_ctrl; ++}; ++ ++static int get_info(const char* path, void* info, size_t s, off_t o) { ++ assert(path != NULL, "path is NULL!"); ++ assert(info != NULL, "info is NULL!"); ++ ++ int fd = -1; ++ ++ if ((fd = os::open(path, O_RDONLY, 0)) < 0) { ++ return OS_ERR; ++ } ++ if (pread(fd, info, s, o) != s) { ++ close(fd); ++ return OS_ERR; ++ } ++ close(fd); ++ return OS_OK; ++} ++ ++static int get_psinfo2(void* info, size_t s, off_t o) { ++ return get_info("/proc/self/psinfo", info, s, o); ++} ++ ++static int get_psinfo(psinfo_t* info) { ++ return get_psinfo2(info, sizeof(*info), 0); ++} ++ ++static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) { ++ assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!"); ++ assert(load != NULL, "load pointer is NULL!"); ++ assert(cpu_stat != NULL, "cpu_stat pointer is NULL!"); ++ ++ if (load->kstat == NULL) { ++ // no handle. ++ return OS_ERR; ++ } ++ if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) { ++ // disable handle for this CPU ++ load->kstat = NULL; ++ return OS_ERR; ++ } ++ return OS_OK; ++} ++ ++static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) { ++ assert(counters != NULL, "counters pointer is NULL!"); ++ ++ cpu_stat_t cpu_stat = {0}; ++ ++ if (which_logical_cpu >= counters->nProcs) { ++ return .0; ++ } ++ ++ CPUPerfTicks load = counters->jvmTicks[which_logical_cpu]; ++ if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) { ++ return .0; ++ } ++ ++ uint_t* usage = cpu_stat.cpu_sysinfo.cpu; ++ if (usage == NULL) { ++ return .0; ++ } ++ ++ uint64_t c_idle = usage[CPU_IDLE]; ++ uint64_t c_total = 0; ++ ++ for (int i = 0; i < CPU_STATES; i++) { ++ c_total += usage[i]; ++ } ++ ++ // Calculate diff against previous snapshot ++ uint64_t d_idle = c_idle - load.last_idle; ++ uint64_t d_total = c_total - load.last_total; ++ ++ /** update if weve moved */ ++ if (d_total > 0) { ++ // Save current values for next time around ++ load.last_idle = c_idle; ++ load.last_total = c_total; ++ load.last_ratio = (double) (d_total - d_idle) / d_total; ++ } ++ ++ return load.last_ratio; ++} ++ ++static int get_boot_time(uint64_t* time) { ++ assert(time != NULL, "time pointer is NULL!"); ++ setutxent(); ++ for(;;) { ++ struct utmpx* u; ++ if ((u = getutxent()) == NULL) { ++ break; ++ } ++ if (u->ut_type == BOOT_TIME) { ++ *time = u->ut_xtime; ++ endutxent(); ++ return OS_OK; ++ } ++ } ++ endutxent(); ++ return OS_ERR; ++} ++ ++static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) { ++ assert(switches != NULL, "switches pointer is NULL!"); ++ assert(counters != NULL, "counter pointer is NULL!"); ++ *switches = 0; ++ uint64_t s = 0; ++ ++ // Collect data from all CPUs ++ for (int i = 0; i < counters->nProcs; i++) { ++ cpu_stat_t cpu_stat = {0}; ++ CPUPerfTicks load = counters->jvmTicks[i]; ++ ++ if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) { ++ s += cpu_stat.cpu_sysinfo.pswitch; ++ } else { ++ //fail fast... ++ return OS_ERR; ++ } ++ } ++ *switches = s; ++ return OS_OK; ++} ++ ++static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) { ++ assert(counters != NULL, "counters is NULL!"); ++ assert(rate != NULL, "rate pointer is NULL!"); ++ static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER; ++ static uint64_t lastTime = 0; ++ static uint64_t lastSwitches = 0; ++ static double lastRate = 0.0; ++ ++ uint64_t lt = 0; ++ int res = 0; ++ ++ if (lastTime == 0) { ++ uint64_t tmp; ++ if (get_boot_time(&tmp) < 0) { ++ return OS_ERR; ++ } ++ lt = tmp * 1000; ++ } ++ ++ res = OS_OK; ++ ++ pthread_mutex_lock(&contextSwitchLock); ++ { ++ ++ uint64_t sw = 0; ++ clock_t t, d; ++ ++ if (lastTime == 0) { ++ lastTime = lt; ++ } ++ ++ t = clock(); ++ d = t - lastTime; ++ ++ if (d == 0) { ++ *rate = lastRate; ++ } else if (get_noof_context_switches(counters, &sw)== OS_OK) { ++ *rate = ((double)(sw - lastSwitches) / d) * 1000; ++ lastRate = *rate; ++ lastSwitches = sw; ++ lastTime = t; ++ } else { ++ *rate = 0.0; ++ res = OS_ERR; ++ } ++ if (*rate < 0.0) { ++ *rate = 0.0; ++ lastRate = 0.0; ++ } ++ } ++ pthread_mutex_unlock(&contextSwitchLock); ++ return res; ++ } ++ ++ ++ ++class CPUPerformanceInterface::CPUPerformance : public CHeapObj { ++ friend class CPUPerformanceInterface; ++ private: ++ CPUPerfCounters _counters; ++ int cpu_load(int which_logical_cpu, double* cpu_load); ++ int context_switch_rate(double* rate); ++ int cpu_load_total_process(double* cpu_load); ++ int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad); ++ ++ CPUPerformance(); ++ ~CPUPerformance(); ++ bool initialize(); ++}; ++ ++CPUPerformanceInterface::CPUPerformance::CPUPerformance() { ++ _counters.nProcs = 0; ++ _counters.jvmTicks = NULL; ++ _counters.kstat_ctrl = NULL; ++} ++ ++bool CPUPerformanceInterface::CPUPerformance::initialize() { ++ // initialize kstat control structure, ++ _counters.kstat_ctrl = kstat_open(); ++ assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!"); ++ ++ if (NULL == _counters.kstat_ctrl) { ++ return false; ++ } ++ ++ // Get number of CPU(s) ++ if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) { ++ // ignore error? ++ _counters.nProcs = 1; ++ } ++ ++ assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!"); ++ if (_counters.nProcs == 0) { ++ return false; ++ } ++ ++ // Data structure(s) for saving CPU load (one per CPU) ++ size_t array_entry_count = _counters.nProcs; ++ _counters.jvmTicks = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal); ++ memset(_counters.jvmTicks, 0, array_entry_count * sizeof(*_counters.jvmTicks)); ++ ++ // Get kstat cpu_stat counters for every CPU ++ // loop over kstat to find our cpu_stat(s) ++ int i = 0; ++ for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) { ++ if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) { ++ if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) { ++ continue; ++ } ++ if (i == _counters.nProcs) { ++ // more cpu_stats than reported CPUs ++ break; ++ } ++ _counters.jvmTicks[i++].kstat = kstat; ++ } ++ } ++ return true; ++} ++ ++CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { ++ FREE_C_HEAP_ARRAY(char, _counters.jvmTicks); ++ if (_counters.kstat_ctrl != NULL) { ++ kstat_close(_counters.kstat_ctrl); ++ } ++} ++ ++int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) { ++ assert(cpu_load != NULL, "cpu_load pointer is NULL!"); ++ double t = .0; ++ if (-1 == which_logical_cpu) { ++ for (int i = 0; i < _counters.nProcs; i++) { ++ t += get_cpu_load(i, &_counters); ++ } ++ // Cap total systemload to 1.0 ++ t = MIN2((t / _counters.nProcs), 1.0); ++ } else { ++ t = MIN2(get_cpu_load(which_logical_cpu, &_counters), 1.0); ++ } ++ ++ *cpu_load = t; ++ return OS_OK; ++} ++ ++int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) { ++ assert(cpu_load != NULL, "cpu_load pointer is NULL!"); ++ ++ psinfo_t info; ++ ++ // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s ++ // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000. ++ if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) { ++ *cpu_load = 0.0; ++ return OS_ERR; ++ } ++ *cpu_load = (double) info.pr_pctcpu / 0x8000; ++ return OS_OK; ++} ++ ++int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) { ++ assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited"); ++ assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited"); ++ assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited"); ++ ++ static uint64_t lastTime; ++ static uint64_t lastUser, lastKernel; ++ static double lastUserRes, lastKernelRes; ++ ++ pstatus_t pss; ++ psinfo_t info; ++ ++ *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0; ++ if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) { ++ return OS_ERR; ++ } ++ ++ if (get_psinfo(&info) != 0) { ++ return OS_ERR; ++ } ++ ++ // get the total time in user, kernel and total time ++ // check ratios for 'lately' and multiply the 'recent load'. ++ uint64_t time = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec; ++ uint64_t user = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec; ++ uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec; ++ uint64_t diff = time - lastTime; ++ double load = (double) info.pr_pctcpu / 0x8000; ++ ++ if (diff > 0) { ++ lastUserRes = (load * (user - lastUser)) / diff; ++ lastKernelRes = (load * (kernel - lastKernel)) / diff; ++ ++ // BUG9182835 - patch for clamping these values to sane ones. ++ lastUserRes = MIN2(1, lastUserRes); ++ lastUserRes = MAX2(0, lastUserRes); ++ lastKernelRes = MIN2(1, lastKernelRes); ++ lastKernelRes = MAX2(0, lastKernelRes); ++ } ++ ++ double t = .0; ++ cpu_load(-1, &t); ++ // clamp at user+system and 1.0 ++ if (lastUserRes + lastKernelRes > t) { ++ t = MIN2(lastUserRes + lastKernelRes, 1.0); ++ } ++ ++ *pjvmUserLoad = lastUserRes; ++ *pjvmKernelLoad = lastKernelRes; ++ *psystemTotalLoad = t; ++ ++ lastTime = time; ++ lastUser = user; ++ lastKernel = kernel; ++ ++ return OS_OK; ++} ++ ++int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) { ++ return perf_context_switch_rate(&_counters, rate); ++} ++ ++CPUPerformanceInterface::CPUPerformanceInterface() { ++ _impl = NULL; ++} ++ ++bool CPUPerformanceInterface::initialize() { ++ _impl = new CPUPerformanceInterface::CPUPerformance(); ++ return _impl->initialize(); ++} ++ ++CPUPerformanceInterface::~CPUPerformanceInterface(void) { ++ if (_impl != NULL) { ++ delete _impl; ++ } ++} ++ ++int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const { ++ return _impl->cpu_load(which_logical_cpu, cpu_load); ++} ++ ++int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const { ++ return _impl->cpu_load_total_process(cpu_load); ++} ++ ++int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const { ++ return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad); ++} ++ ++int CPUPerformanceInterface::context_switch_rate(double* rate) const { ++ return _impl->context_switch_rate(rate); ++} ++ ++class SystemProcessInterface::SystemProcesses : public CHeapObj { ++ friend class SystemProcessInterface; ++ private: ++ class ProcessIterator : public CHeapObj { ++ friend class SystemProcessInterface::SystemProcesses; ++ private: ++ DIR* _dir; ++ struct dirent* _entry; ++ bool _valid; ++ ++ ProcessIterator(); ++ ~ProcessIterator(); ++ bool initialize(); ++ ++ bool is_valid() const { return _valid; } ++ bool is_valid_entry(struct dirent* const entry) const; ++ bool is_dir(const char* const name) const; ++ char* allocate_string(const char* const str) const; ++ int current(SystemProcess* const process_info); ++ int next_process(); ++ }; ++ ++ ProcessIterator* _iterator; ++ SystemProcesses(); ++ bool initialize(); ++ ~SystemProcesses(); ++ ++ //information about system processes ++ int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const; ++}; ++ ++bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const { ++ struct stat64 mystat; ++ int ret_val = 0; ++ ++ ret_val = ::stat64(name, &mystat); ++ ++ if (ret_val < 0) { ++ return false; ++ } ++ ret_val = S_ISDIR(mystat.st_mode); ++ return ret_val > 0; ++} ++ ++// if it has a numeric name, is a directory and has a 'psinfo' file in it ++bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const { ++ // ignore the "." and ".." directories ++ if ((strcmp(entry->d_name, ".") == 0) || ++ (strcmp(entry->d_name, "..") == 0)) { ++ return false; ++ } ++ ++ char buffer[PATH_MAX] = {0}; ++ uint64_t size = 0; ++ bool result = false; ++ FILE *fp = NULL; ++ ++ if (atoi(entry->d_name) != 0) { ++ jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name); ++ ++ if (is_dir(buffer)) { ++ memset(buffer, 0, PATH_MAX); ++ jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name); ++ if ((fp = fopen(buffer, "r")) != NULL) { ++ int nread = 0; ++ psinfo_t psinfo_data; ++ if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) { ++ // only considering system process owned by root ++ if (psinfo_data.pr_uid == 0) { ++ result = true; ++ } ++ } ++ } ++ } ++ } ++ ++ if (fp != NULL) { ++ fclose(fp); ++ } ++ ++ return result; ++} ++ ++char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const { ++ if (str != NULL) { ++ return os::strdup_check_oom(str, mtInternal); ++ } ++ return NULL; ++} ++ ++int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) { ++ if (!is_valid()) { ++ return OS_ERR; ++ } ++ ++ char psinfo_path[PATH_MAX] = {0}; ++ jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name); ++ ++ FILE *fp = NULL; ++ if ((fp = fopen(psinfo_path, "r")) == NULL) { ++ return OS_ERR; ++ } ++ ++ int nread = 0; ++ psinfo_t psinfo_data; ++ if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) { ++ fclose(fp); ++ return OS_ERR; ++ } ++ ++ char *exe_path = NULL; ++ if ((psinfo_data.pr_fname != NULL) && ++ (psinfo_data.pr_psargs != NULL)) { ++ char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname); ++ if (path_substring != NULL) { ++ int len = path_substring - psinfo_data.pr_psargs; ++ exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal); ++ jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs); ++ exe_path[len] = '\0'; ++ } ++ } ++ ++ process_info->set_pid(atoi(_entry->d_name)); ++ process_info->set_name(allocate_string(psinfo_data.pr_fname)); ++ process_info->set_path(allocate_string(exe_path)); ++ process_info->set_command_line(allocate_string(psinfo_data.pr_psargs)); ++ ++ if (exe_path != NULL) { ++ FREE_C_HEAP_ARRAY(char, exe_path); ++ } ++ ++ if (fp != NULL) { ++ fclose(fp); ++ } ++ ++ return OS_OK; ++} ++ ++int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() { ++ if (!is_valid()) { ++ return OS_ERR; ++ } ++ ++ do { ++ _entry = os::readdir(_dir); ++ if (_entry == NULL) { ++ // Error or reached end. Could use errno to distinguish those cases. ++ _valid = false; ++ return OS_ERR; ++ } ++ } while(!is_valid_entry(_entry)); ++ ++ _valid = true; ++ return OS_OK; ++} ++ ++SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() { ++ _dir = NULL; ++ _entry = NULL; ++ _valid = false; ++} ++ ++bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() { ++ _dir = os::opendir("/proc"); ++ _entry = NULL; ++ _valid = true; ++ next_process(); ++ ++ return true; ++} ++ ++SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() { ++ if (_dir != NULL) { ++ os::closedir(_dir); ++ } ++} ++ ++SystemProcessInterface::SystemProcesses::SystemProcesses() { ++ _iterator = NULL; ++} ++ ++bool SystemProcessInterface::SystemProcesses::initialize() { ++ _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator(); ++ return _iterator->initialize(); ++} ++ ++SystemProcessInterface::SystemProcesses::~SystemProcesses() { ++ if (_iterator != NULL) { ++ delete _iterator; ++ } ++} ++ ++int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const { ++ assert(system_processes != NULL, "system_processes pointer is NULL!"); ++ assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!"); ++ assert(_iterator != NULL, "iterator is NULL!"); ++ ++ // initialize pointers ++ *no_of_sys_processes = 0; ++ *system_processes = NULL; ++ ++ while (_iterator->is_valid()) { ++ SystemProcess* tmp = new SystemProcess(); ++ _iterator->current(tmp); ++ ++ //if already existing head ++ if (*system_processes != NULL) { ++ //move "first to second" ++ tmp->set_next(*system_processes); ++ } ++ // new head ++ *system_processes = tmp; ++ // increment ++ (*no_of_sys_processes)++; ++ // step forward ++ _iterator->next_process(); ++ } ++ return OS_OK; ++} ++ ++int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const { ++ return _impl->system_processes(system_procs, no_of_sys_processes); ++} ++ ++SystemProcessInterface::SystemProcessInterface() { ++ _impl = NULL; ++} ++ ++bool SystemProcessInterface::initialize() { ++ _impl = new SystemProcessInterface::SystemProcesses(); ++ return _impl->initialize(); ++ ++} ++ ++SystemProcessInterface::~SystemProcessInterface() { ++ if (_impl != NULL) { ++ delete _impl; ++ } ++} ++ ++CPUInformationInterface::CPUInformationInterface() { ++ _cpu_info = NULL; ++} ++ ++bool CPUInformationInterface::initialize() { ++ _cpu_info = new CPUInformation(); ++ VM_Version::initialize_cpu_information(); ++ _cpu_info->set_number_of_hardware_threads(VM_Version::number_of_threads()); ++ _cpu_info->set_number_of_cores(VM_Version::number_of_cores()); ++ _cpu_info->set_number_of_sockets(VM_Version::number_of_sockets()); ++ _cpu_info->set_cpu_name(VM_Version::cpu_name()); ++ _cpu_info->set_cpu_description(VM_Version::cpu_description()); ++ return true; ++} ++ ++CPUInformationInterface::~CPUInformationInterface() { ++ if (_cpu_info != NULL) { ++ if (_cpu_info->cpu_name() != NULL) { ++ const char* cpu_name = _cpu_info->cpu_name(); ++ FREE_C_HEAP_ARRAY(char, cpu_name); ++ _cpu_info->set_cpu_name(NULL); ++ } ++ if (_cpu_info->cpu_description() != NULL) { ++ const char* cpu_desc = _cpu_info->cpu_description(); ++ FREE_C_HEAP_ARRAY(char, cpu_desc); ++ _cpu_info->set_cpu_description(NULL); ++ } ++ delete _cpu_info; ++ } ++} ++ ++int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) { ++ if (_cpu_info == NULL) { ++ return OS_ERR; ++ } ++ ++ cpu_info = *_cpu_info; // shallow copy assignment ++ return OS_OK; ++} ++ ++class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj { ++ friend class NetworkPerformanceInterface; ++ private: ++ NetworkPerformance(); ++ NONCOPYABLE(NetworkPerformance); ++ bool initialize(); ++ ~NetworkPerformance(); ++ int network_utilization(NetworkInterface** network_interfaces) const; ++}; ++ ++NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() { ++ ++} ++ ++bool NetworkPerformanceInterface::NetworkPerformance::initialize() { ++ return true; ++} ++ ++NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { ++ ++} ++ ++int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const ++{ ++ kstat_ctl_t* ctl = kstat_open(); ++ if (ctl == NULL) { ++ return OS_ERR; ++ } ++ ++ NetworkInterface* ret = NULL; ++ for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) { ++ if (strcmp(k->ks_class, "net") != 0) { ++ continue; ++ } ++ if (strcmp(k->ks_module, "link") != 0) { ++ continue; ++ } ++ ++ if (kstat_read(ctl, k, NULL) == -1) { ++ return OS_ERR; ++ } ++ ++ uint64_t bytes_in = UINT64_MAX; ++ uint64_t bytes_out = UINT64_MAX; ++ for (unsigned int i = 0; i < k->ks_ndata; ++i) { ++ kstat_named_t* data = &reinterpret_cast(k->ks_data)[i]; ++ if (strcmp(data->name, "rbytes64") == 0) { ++ bytes_in = data->value.ui64; ++ } ++ else if (strcmp(data->name, "obytes64") == 0) { ++ bytes_out = data->value.ui64; ++ } ++ } ++ ++ if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) { ++ NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret); ++ ret = cur; ++ } ++ } ++ ++ kstat_close(ctl); ++ *network_interfaces = ret; ++ ++ return OS_OK; ++} ++ ++NetworkPerformanceInterface::NetworkPerformanceInterface() { ++ _impl = NULL; ++} ++ ++NetworkPerformanceInterface::~NetworkPerformanceInterface() { ++ if (_impl != NULL) { ++ delete _impl; ++ } ++} ++ ++bool NetworkPerformanceInterface::initialize() { ++ _impl = new NetworkPerformanceInterface::NetworkPerformance(); ++ return _impl->initialize(); ++} ++ ++int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const { ++ return _impl->network_utilization(network_interfaces); ++} +diff -urN /tmp/a/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp +--- /tmp/a/os_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/os_solaris.cpp 2024-10-15 14:59:36.867779471 +0100 +@@ -0,0 +1,3077 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++// no precompiled headers ++#include "jvm.h" ++#include "classfile/classLoader.hpp" ++#include "classfile/systemDictionary.hpp" ++#include "classfile/vmSymbols.hpp" ++#include "code/icBuffer.hpp" ++#include "code/vtableStubs.hpp" ++#include "compiler/compileBroker.hpp" ++#include "compiler/disassembler.hpp" ++#include "interpreter/interpreter.hpp" ++#include "jvmtifiles/jvmti.h" ++#include "logging/log.hpp" ++#include "logging/logStream.hpp" ++#include "memory/allocation.inline.hpp" ++#include "memory/universe.hpp" ++#include "oops/oop.inline.hpp" ++#include "os_solaris.inline.hpp" ++#include "prims/jniFastGetField.hpp" ++#include "prims/jvm_misc.hpp" ++#include "runtime/arguments.hpp" ++#include "runtime/atomic.hpp" ++#include "runtime/globals.hpp" ++#include "runtime/globals_extension.hpp" ++#include "runtime/interfaceSupport.inline.hpp" ++#include "runtime/java.hpp" ++#include "runtime/javaCalls.hpp" ++#include "runtime/javaThread.hpp" ++#include "runtime/mutexLocker.hpp" ++#include "runtime/objectMonitor.hpp" ++#include "runtime/osInfo.hpp" ++#include "runtime/orderAccess.hpp" ++#include "runtime/osThread.hpp" ++#include "runtime/park.hpp" ++#include "runtime/perfMemory.hpp" ++#include "runtime/sharedRuntime.hpp" ++#include "runtime/statSampler.hpp" ++#include "runtime/stubRoutines.hpp" ++#include "runtime/threadCritical.hpp" ++#include "runtime/threads.hpp" ++#include "runtime/timer.hpp" ++#include "runtime/vm_version.hpp" ++#include "semaphore_posix.hpp" ++#include "services/attachListener.hpp" ++#include "services/memTracker.hpp" ++#include "services/runtimeService.hpp" ++#include "signals_posix.hpp" ++#include "utilities/align.hpp" ++#include "utilities/decoder.hpp" ++#include "utilities/defaultStream.hpp" ++#include "utilities/events.hpp" ++#include "utilities/growableArray.hpp" ++#include "utilities/macros.hpp" ++#include "utilities/vmError.hpp" ++ ++// put OS-includes here ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include // for elf Sym structure used by dladdr1 ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++# include ++ ++# include ++ ++#define MAX_PATH (2 * K) ++ ++// for timer info max values which include all bits ++#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) ++ ++// Here are some liblgrp types from sys/lgrp_user.h to be able to ++// compile on older systems without this header file. ++ ++#ifndef MADV_ACCESS_LWP ++ #define MADV_ACCESS_LWP 7 /* next LWP to access heavily */ ++#endif ++#ifndef MADV_ACCESS_MANY ++ #define MADV_ACCESS_MANY 8 /* many processes to access heavily */ ++#endif ++ ++#ifndef LGRP_RSRC_CPU ++ #define LGRP_RSRC_CPU 0 /* CPU resources */ ++#endif ++#ifndef LGRP_RSRC_MEM ++ #define LGRP_RSRC_MEM 1 /* memory resources */ ++#endif ++ ++// guarded in sys/mman.h ++extern "C" { ++extern int getpagesizes(size_t[], int); ++} ++ ++// Values for ThreadPriorityPolicy == 1 ++int prio_policy1[CriticalPriority+1] = { ++ -99999, 0, 16, 32, 48, 64, ++ 80, 96, 112, 124, 127, 127 }; ++ ++// System parameters used internally ++static clock_t clock_tics_per_sec = 100; ++ ++// For diagnostics to print a message once. see run_periodic_checks ++static bool check_addr0_done = false; ++ ++address os::Solaris::handler_start; // start pc of thr_sighndlrinfo ++address os::Solaris::handler_end; // end pc of thr_sighndlrinfo ++ ++address os::Solaris::_main_stack_base = NULL; // 4352906 workaround ++ ++os::Solaris::pthread_setname_np_func_t os::Solaris::_pthread_setname_np = NULL; ++ ++// "default" initializers for missing libc APIs ++extern "C" { ++ int memcntl(void *, size_t, int, void *, int, int); ++ int meminfo(const uint64_t *, int, const uint_t *, int, uint64_t *, uint_t *); ++} ++ ++static inline size_t adjust_stack_size(address base, size_t size) { ++ if ((ssize_t)size < 0) { ++ // 4759953: Compensate for ridiculous stack size. ++ size = max_intx; ++ } ++ if (size > (size_t)base) { ++ // 4812466: Make sure size doesn't allow the stack to wrap the address space. ++ size = (size_t)base; ++ } ++ return size; ++} ++ ++static inline stack_t get_stack_info() { ++ stack_t st; ++ int retval = thr_stksegment(&st); ++ st.ss_size = adjust_stack_size((address)st.ss_sp, st.ss_size); ++ assert(retval == 0, "incorrect return value from thr_stksegment"); ++ assert((address)&st < (address)st.ss_sp, "Invalid stack base returned"); ++ assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned"); ++ return st; ++} ++ ++bool os::is_primordial_thread(void) { ++ int r = thr_main(); ++ guarantee(r == 0 || r == 1, "CR6501650 or CR6493689"); ++ return r == 1; ++} ++ ++address os::current_stack_base() { ++ bool _is_primordial_thread = is_primordial_thread(); ++ ++ // Workaround 4352906, avoid calls to thr_stksegment by ++ // thr_main after the first one (it looks like we trash ++ // some data, causing the value for ss_sp to be incorrect). ++ if (!_is_primordial_thread || os::Solaris::_main_stack_base == NULL) { ++ stack_t st = get_stack_info(); ++ if (_is_primordial_thread) { ++ // cache initial value of stack base ++ os::Solaris::_main_stack_base = (address)st.ss_sp; ++ } ++ return (address)st.ss_sp; ++ } else { ++ guarantee(os::Solaris::_main_stack_base != NULL, "Attempt to use null cached stack base"); ++ return os::Solaris::_main_stack_base; ++ } ++} ++ ++size_t os::current_stack_size() { ++ size_t size; ++ ++ if (!is_primordial_thread()) { ++ size = get_stack_info().ss_size; ++ } else { ++ struct rlimit limits; ++ getrlimit(RLIMIT_STACK, &limits); ++ size = adjust_stack_size(os::Solaris::_main_stack_base, (size_t)limits.rlim_cur); ++ } ++ // base may not be page aligned ++ address base = current_stack_base(); ++ address bottom = align_up(base - size, os::vm_page_size());; ++ return (size_t)(base - bottom); ++} ++ ++jint os::Solaris::_os_thread_limit = 0; ++volatile jint os::Solaris::_os_thread_count = 0; ++ ++julong os::available_memory() { ++ return Solaris::available_memory(); ++} ++ ++julong os::free_memory() { ++ return Solaris::available_memory(); ++} ++ ++julong os::Solaris::available_memory() { ++ return (julong)sysconf(_SC_AVPHYS_PAGES) * os::vm_page_size(); ++} ++ ++julong os::Solaris::_physical_memory = 0; ++ ++julong os::physical_memory() { ++ return Solaris::physical_memory(); ++} ++ ++static hrtime_t first_hrtime = 0; ++static const hrtime_t hrtime_hz = 1000*1000*1000; ++static volatile hrtime_t max_hrtime = 0; ++ ++ ++void os::Solaris::initialize_system_info() { ++ set_processor_count(sysconf(_SC_NPROCESSORS_CONF)); ++ _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * ++ (julong)sysconf(_SC_PAGESIZE); ++} ++ ++uint os::processor_id() { ++ const processorid_t id = ::getcpuid(); ++ assert(id >= 0 && id < _processor_count, "Invalid processor id"); ++ return (uint)id; ++} ++ ++int os::active_processor_count() { ++ // User has overridden the number of active processors ++ if (ActiveProcessorCount > 0) { ++ log_trace(os)("active_processor_count: " ++ "active processor count set by user : %d", ++ ActiveProcessorCount); ++ return ActiveProcessorCount; ++ } ++ ++ int online_cpus = sysconf(_SC_NPROCESSORS_ONLN); ++ pid_t pid = getpid(); ++ psetid_t pset = PS_NONE; ++ // Are we running in a processor set or is there any processor set around? ++ if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) { ++ uint_t pset_cpus; ++ // Query the number of cpus available to us. ++ if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) { ++ assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check"); ++ return pset_cpus; ++ } ++ } ++ // Otherwise return number of online cpus ++ return online_cpus; ++} ++ ++void os::set_native_thread_name(const char *name) { ++ if (Solaris::_pthread_setname_np != NULL) { ++ // Only the first 31 bytes of 'name' are processed by pthread_setname_np ++ // but we explicitly copy into a size-limited buffer to avoid any ++ // possible overflow. ++ char buf[32]; ++ snprintf(buf, sizeof(buf), "%s", name); ++ buf[sizeof(buf) - 1] = '\0'; ++ Solaris::_pthread_setname_np(pthread_self(), buf); ++ } ++} ++ ++void os::init_system_properties_values() { ++ // The next steps are taken in the product version: ++ // ++ // Obtain the JAVA_HOME value from the location of libjvm.so. ++ // This library should be located at: ++ // /jre/lib//{client|server}/libjvm.so. ++ // ++ // If "/jre/lib/" appears at the right place in the path, then we ++ // assume libjvm.so is installed in a JDK and we use this path. ++ // ++ // Otherwise exit with message: "Could not create the Java virtual machine." ++ // ++ // The following extra steps are taken in the debugging version: ++ // ++ // If "/jre/lib/" does NOT appear at the right place in the path ++ // instead of exit check for $JAVA_HOME environment variable. ++ // ++ // If it is defined and we are able to locate $JAVA_HOME/jre/lib/, ++ // then we append a fake suffix "hotspot/libjvm.so" to this path so ++ // it looks like libjvm.so is installed there ++ // /jre/lib//hotspot/libjvm.so. ++ // ++ // Otherwise exit. ++ // ++ // Important note: if the location of libjvm.so changes this ++ // code needs to be changed accordingly. ++ ++// Base path of extensions installed on the system. ++#define SYS_EXT_DIR "/usr/jdk/packages" ++#define EXTENSIONS_DIR "/lib/ext" ++ ++ // Buffer that fits several sprintfs. ++ // Note that the space for the colon and the trailing null are provided ++ // by the nulls included by the sizeof operator. ++ const size_t bufsize = ++ MAX3((size_t)MAXPATHLEN, // For dll_dir & friends. ++ sizeof(SYS_EXT_DIR) + sizeof("/lib/"), // invariant ld_library_path ++ (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir ++ char *buf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal); ++ ++ // sysclasspath, java_home, dll_dir ++ { ++ char *pslash; ++ os::jvm_path(buf, bufsize); ++ ++ // Found the full path to libjvm.so. ++ // Now cut the path to /jre if we can. ++ *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so. ++ pslash = strrchr(buf, '/'); ++ if (pslash != NULL) { ++ *pslash = '\0'; // Get rid of /{client|server|hotspot}. ++ } ++ Arguments::set_dll_dir(buf); ++ ++ if (pslash != NULL) { ++ pslash = strrchr(buf, '/'); ++ if (pslash != NULL) { ++ *pslash = '\0'; // Get rid of /lib. ++ } ++ } ++ Arguments::set_java_home(buf); ++ if (!set_boot_path('/', ':')) { ++ vm_exit_during_initialization("Failed setting boot class path.", NULL); ++ } ++ } ++ ++ // Where to look for native libraries. ++ { ++ // Use dlinfo() to determine the correct java.library.path. ++ // ++ // If we're launched by the Java launcher, and the user ++ // does not set java.library.path explicitly on the commandline, ++ // the Java launcher sets LD_LIBRARY_PATH for us and unsets ++ // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64. In this case ++ // dlinfo returns LD_LIBRARY_PATH + crle settings (including ++ // /usr/lib), which is exactly what we want. ++ // ++ // If the user does set java.library.path, it completely ++ // overwrites this setting, and always has. ++ // ++ // If we're not launched by the Java launcher, we may ++ // get here with any/all of the LD_LIBRARY_PATH[_32|64] ++ // settings. Again, dlinfo does exactly what we want. ++ ++ Dl_serinfo info_sz, *info = &info_sz; ++ Dl_serpath *path; ++ char *library_path; ++ char *common_path = buf; ++ ++ // Determine search path count and required buffer size. ++ if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) { ++ FREE_C_HEAP_ARRAY(char, buf); ++ vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror()); ++ } ++ ++ // Allocate new buffer and initialize. ++ info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal); ++ info->dls_size = info_sz.dls_size; ++ info->dls_cnt = info_sz.dls_cnt; ++ ++ // Obtain search path information. ++ if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) { ++ FREE_C_HEAP_ARRAY(char, buf); ++ FREE_C_HEAP_ARRAY(char, info); ++ vm_exit_during_initialization("dlinfo SERINFO request", dlerror()); ++ } ++ ++ path = &info->dls_serpath[0]; ++ ++ // Note: Due to a legacy implementation, most of the library path ++ // is set in the launcher. This was to accommodate linking restrictions ++ // on legacy Solaris implementations (which are no longer supported). ++ // Eventually, all the library path setting will be done here. ++ // ++ // However, to prevent the proliferation of improperly built native ++ // libraries, the new path component /usr/jdk/packages is added here. ++ ++ // Construct the invariant part of ld_library_path. ++ sprintf(common_path, SYS_EXT_DIR "/lib"); ++ ++ // Struct size is more than sufficient for the path components obtained ++ // through the dlinfo() call, so only add additional space for the path ++ // components explicitly added here. ++ size_t library_path_size = info->dls_size + strlen(common_path); ++ library_path = NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal); ++ library_path[0] = '\0'; ++ ++ // Construct the desired Java library path from the linker's library ++ // search path. ++ // ++ // For compatibility, it is optimal that we insert the additional path ++ // components specific to the Java VM after those components specified ++ // in LD_LIBRARY_PATH (if any) but before those added by the ld.so ++ // infrastructure. ++ if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it. ++ strcpy(library_path, common_path); ++ } else { ++ int inserted = 0; ++ uint_t i; ++ for (i = 0; i < info->dls_cnt; i++, path++) { ++ uint_t flags = path->dls_flags & LA_SER_MASK; ++ if (((flags & LA_SER_LIBPATH) == 0) && !inserted) { ++ strcat(library_path, common_path); ++ strcat(library_path, os::path_separator()); ++ inserted = 1; ++ } ++ strcat(library_path, path->dls_name); ++ strcat(library_path, os::path_separator()); ++ } ++ // Eliminate trailing path separator. ++ library_path[strlen(library_path)-1] = '\0'; ++ } ++ ++ // happens before argument parsing - can't use a trace flag ++ // tty->print_raw("init_system_properties_values: native lib path: "); ++ // tty->print_raw_cr(library_path); ++ ++ // Callee copies into its own buffer. ++ Arguments::set_library_path(library_path); ++ ++ FREE_C_HEAP_ARRAY(char, library_path); ++ FREE_C_HEAP_ARRAY(char, info); ++ } ++ ++ // Extensions directories. ++ sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); ++ Arguments::set_ext_dirs(buf); ++ ++ FREE_C_HEAP_ARRAY(char, buf); ++ ++#undef SYS_EXT_DIR ++#undef EXTENSIONS_DIR ++} ++ ++static thread_t main_thread; ++ ++// Thread start routine for all newly created threads ++extern "C" void* thread_native_entry(void* thread_addr) { ++ ++ Thread* thread = (Thread*)thread_addr; ++ ++ thread->record_stack_base_and_size(); ++ ++ // Try to randomize the cache line index of hot stack frames. ++ // This helps when threads of the same stack traces evict each other's ++ // cache lines. The threads can be either from the same JVM instance, or ++ // from different JVM instances. The benefit is especially true for ++ // processors with hyperthreading technology. ++ static int counter = 0; ++ int pid = os::current_process_id(); ++ alloca(((pid ^ counter++) & 7) * 128); ++ ++ int prio; ++ ++ thread->initialize_thread_current(); ++ ++ OSThread* osthr = thread->osthread(); ++ ++ osthr->set_lwp_id(_lwp_self()); // Store lwp in case we are bound ++ ++ log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").", ++ os::current_thread_id()); ++ ++ if (UseNUMA) { ++ int lgrp_id = os::numa_get_group_id(); ++ if (lgrp_id != -1) { ++ thread->set_lgrp_id(lgrp_id); ++ } ++ } ++ ++ // Our priority was set when we were created, and stored in the ++ // osthread, but couldn't be passed through to our LWP until now. ++ // So read back the priority and set it again. ++ ++ if (osthr->thread_id() != -1) { ++ if (UseThreadPriorities) { ++ int prio = osthr->native_priority(); ++ os::set_native_priority(thread, prio); ++ } ++ } ++ ++ assert(osthr->get_state() == RUNNABLE, "invalid os thread state"); ++ ++ // initialize signal mask for this thread ++ PosixSignals::hotspot_sigmask(thread); ++ ++ os::Solaris::init_thread_fpu_state(); ++ ++ thread->call_run(); ++ ++ // Note: at this point the thread object may already have deleted itself. ++ // Do not dereference it from here on out. ++ ++ // One less thread is executing ++ // When the VMThread gets here, the main thread may have already exited ++ // which frees the CodeHeap containing the Atomic::dec code ++ if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) { ++ Atomic::dec(&os::Solaris::_os_thread_count); ++ } ++ ++ log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id()); ++ ++ thr_exit(NULL); ++ ShouldNotReachHere(); ++ ++ return NULL; ++} ++ ++static OSThread* create_os_thread(Thread* thread, thread_t thread_id) { ++ // Allocate the OSThread object ++ OSThread* osthread = new OSThread(); ++ if (osthread == NULL) return NULL; ++ ++ // Store info on the Solaris thread into the OSThread ++ osthread->set_thread_id(thread_id); ++ osthread->set_lwp_id(_lwp_self()); ++ ++ if (UseNUMA) { ++ int lgrp_id = os::numa_get_group_id(); ++ if (lgrp_id != -1) { ++ thread->set_lgrp_id(lgrp_id); ++ } ++ } ++ ++ // Initial thread state is INITIALIZED, not SUSPENDED ++ osthread->set_state(INITIALIZED); ++ ++ return osthread; ++} ++ ++bool os::create_attached_thread(JavaThread* thread) { ++#ifdef ASSERT ++ thread->verify_not_published(); ++#endif ++ OSThread* osthread = create_os_thread(thread, thr_self()); ++ if (osthread == NULL) { ++ return false; ++ } ++ ++ // Initial thread state is RUNNABLE ++ osthread->set_state(RUNNABLE); ++ thread->set_osthread(osthread); ++ ++ if (os::is_primordial_thread()) { ++ os::Solaris::correct_stack_boundaries_for_primordial_thread(thread); ++ } ++ ++ // initialize signal mask for this thread ++ // and save the caller's signal mask ++ PosixSignals::hotspot_sigmask(thread); ++ ++ log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").", ++ os::current_thread_id()); ++ ++ return true; ++} ++ ++bool os::create_main_thread(JavaThread* thread) { ++#ifdef ASSERT ++ thread->verify_not_published(); ++#endif ++ if (_starting_thread == NULL) { ++ _starting_thread = create_os_thread(thread, main_thread); ++ if (_starting_thread == NULL) { ++ return false; ++ } ++ } ++ ++ // The primodial thread is runnable from the start ++ _starting_thread->set_state(RUNNABLE); ++ ++ thread->set_osthread(_starting_thread); ++ ++ // initialize signal mask for this thread ++ // and save the caller's signal mask ++ PosixSignals::hotspot_sigmask(thread); ++ ++ return true; ++} ++ ++// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr() ++static char* describe_thr_create_attributes(char* buf, size_t buflen, ++ size_t stacksize, long flags) { ++ stringStream ss(buf, buflen); ++ ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024); ++ ss.print("flags: "); ++ #define PRINT_FLAG(f) if (flags & f) ss.print( #f " "); ++ #define ALL(X) \ ++ X(THR_SUSPENDED) \ ++ X(THR_DETACHED) \ ++ X(THR_BOUND) \ ++ X(THR_NEW_LWP) \ ++ X(THR_DAEMON) ++ ALL(PRINT_FLAG) ++ #undef ALL ++ #undef PRINT_FLAG ++ return buf; ++} ++ ++// return default stack size for thr_type ++size_t os::Posix::default_stack_size(os::ThreadType thr_type) { ++ // default stack size when not specified by caller is 1M (2M for LP64) ++ size_t s = (BytesPerWord >> 2) * K * K; ++ return s; ++} ++ ++bool os::create_thread(Thread* thread, ThreadType thr_type, ++ size_t req_stack_size) { ++ // Allocate the OSThread object ++ OSThread* osthread = new OSThread(); ++ if (osthread == NULL) { ++ return false; ++ } ++ ++ // calculate stack size if it's not specified by caller ++ size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size); ++ ++ // Initial state is ALLOCATED but not INITIALIZED ++ osthread->set_state(ALLOCATED); ++ ++ if (os::Solaris::_os_thread_count > os::Solaris::_os_thread_limit) { ++ // We got lots of threads. Check if we still have some address space left. ++ // Need to be at least 5Mb of unreserved address space. We do check by ++ // trying to reserve some. ++ const size_t VirtualMemoryBangSize = 20*K*K; ++ char* mem = os::reserve_memory(VirtualMemoryBangSize); ++ if (mem == NULL) { ++ delete osthread; ++ return false; ++ } else { ++ // Release the memory again ++ os::release_memory(mem, VirtualMemoryBangSize); ++ } ++ } ++ ++ // Setup osthread because the child thread may need it. ++ thread->set_osthread(osthread); ++ ++ // Create the Solaris thread ++ thread_t tid = 0; ++ long flags = THR_DETACHED | THR_SUSPENDED; ++ int status; ++ ++ // Mark that we don't have an lwp or thread id yet. ++ // In case we attempt to set the priority before the thread starts. ++ osthread->set_lwp_id(-1); ++ osthread->set_thread_id(-1); ++ ++ status = thr_create(NULL, stack_size, thread_native_entry, thread, flags, &tid); ++ ++ char buf[64]; ++ if (status == 0) { ++ log_info(os, thread)("Thread \"%s\" started (tid: " UINTX_FORMAT ", attributes: %s). ", ++ thread->name(), (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); ++ } else { ++ log_warning(os, thread)("Failed to start thread \"%s\" - thr_create failed (%s) for attributes: %s.", ++ thread->name(), os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); ++ // Log some OS information which might explain why creating the thread failed. ++ log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads()); ++ LogStream st(Log(os, thread)::info()); ++ os::Posix::print_rlimit_info(&st); ++ os::print_memory_info(&st); ++ } ++ ++ if (status != 0) { ++ thread->set_osthread(NULL); ++ // Need to clean up stuff we've allocated so far ++ delete osthread; ++ return false; ++ } ++ ++ Atomic::inc(&os::Solaris::_os_thread_count); ++ ++ // Store info on the Solaris thread into the OSThread ++ osthread->set_thread_id(tid); ++ ++ // Remember that we created this thread so we can set priority on it ++ osthread->set_vm_created(); ++ ++ // Most thread types will set an explicit priority before starting the thread, ++ // but for those that don't we need a valid value to read back in thread_native_entry. ++ osthread->set_native_priority(NormPriority); ++ ++ // Initial thread state is INITIALIZED, not SUSPENDED ++ osthread->set_state(INITIALIZED); ++ ++ // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain ++ return true; ++} ++ ++// CR 7190089: on Solaris, primordial thread's stack needs adjusting. ++// Without the adjustment, stack size is incorrect if stack is set to unlimited (ulimit -s unlimited). ++void os::Solaris::correct_stack_boundaries_for_primordial_thread(Thread* thr) { ++ assert(is_primordial_thread(), "Call only for primordial thread"); ++ ++ JavaThread* jt = (JavaThread *)thr; ++ assert(jt != NULL, "Sanity check"); ++ size_t stack_size; ++ address base = jt->stack_base(); ++ if (Arguments::created_by_java_launcher()) { ++ // Use 2MB to allow for Solaris 7 64 bit mode. ++ stack_size = JavaThread::stack_size_at_create() == 0 ++ ? 2048*K : JavaThread::stack_size_at_create(); ++ ++ // There are rare cases when we may have already used more than ++ // the basic stack size allotment before this method is invoked. ++ // Attempt to allow for a normally sized java_stack. ++ size_t current_stack_offset = (size_t)(base - (address)&stack_size); ++ stack_size += ReservedSpace::page_align_size_down(current_stack_offset); ++ } else { ++ // 6269555: If we were not created by a Java launcher, i.e. if we are ++ // running embedded in a native application, treat the primordial thread ++ // as much like a native attached thread as possible. This means using ++ // the current stack size from thr_stksegment(), unless it is too large ++ // to reliably setup guard pages. A reasonable max size is 8MB. ++ size_t current_size = os::current_stack_size(); ++ // This should never happen, but just in case.... ++ if (current_size == 0) current_size = 2 * K * K; ++ stack_size = current_size > (8 * K * K) ? (8 * K * K) : current_size; ++ } ++ address bottom = align_up(base - stack_size, os::vm_page_size());; ++ stack_size = (size_t)(base - bottom); ++ ++ assert(stack_size > 0, "Stack size calculation problem"); ++ ++ if (stack_size > jt->stack_size()) { ++#ifndef PRODUCT ++ struct rlimit limits; ++ getrlimit(RLIMIT_STACK, &limits); ++ size_t size = adjust_stack_size(base, (size_t)limits.rlim_cur); ++ assert(size >= jt->stack_size(), "Stack size problem in main thread"); ++#endif ++ tty->print_cr("Stack size of " SIZE_FORMAT " Kb exceeds current limit of " SIZE_FORMAT " Kb.\n" ++ "(Stack sizes are rounded up to a multiple of the system page size.)\n" ++ "See limit(1) to increase the stack size limit.", ++ stack_size / K, jt->stack_size() / K); ++ vm_exit(1); ++ } ++ assert(jt->stack_size() >= stack_size, ++ "Attempt to map more stack than was allocated"); ++ jt->set_stack_size(stack_size); ++ ++} ++ ++ ++ ++// Free Solaris resources related to the OSThread ++void os::free_thread(OSThread* osthread) { ++ assert(osthread != NULL, "os::free_thread but osthread not set"); ++ ++ // We are told to free resources of the argument thread, ++ // but we can only really operate on the current thread. ++ assert(Thread::current()->osthread() == osthread, ++ "os::free_thread but not current thread"); ++ ++ // Restore caller's signal mask ++ sigset_t sigmask = osthread->caller_sigmask(); ++ pthread_sigmask(SIG_SETMASK, &sigmask, NULL); ++ ++ delete osthread; ++} ++ ++void os::pd_start_thread(Thread* thread) { ++ int status = thr_continue(thread->osthread()->thread_id()); ++ assert_status(status == 0, status, "thr_continue failed"); ++} ++ ++ ++intx os::current_thread_id() { ++ return (intx)thr_self(); ++} ++ ++static pid_t _initial_pid = 0; ++ ++int os::current_process_id() { ++ return (int)(_initial_pid ? _initial_pid : getpid()); ++} ++ ++// gethrtime() should be monotonic according to the documentation, ++// but some virtualized platforms are known to break this guarantee. ++// getTimeNanos() must be guaranteed not to move backwards, so we ++// are forced to add a check here. ++inline hrtime_t getTimeNanos() { ++ const hrtime_t now = gethrtime(); ++ const hrtime_t prev = max_hrtime; ++ if (now <= prev) { ++ return prev; // same or retrograde time; ++ } ++ const hrtime_t obsv = Atomic::cmpxchg(&max_hrtime, prev, now); ++ assert(obsv >= prev, "invariant"); // Monotonicity ++ // If the CAS succeeded then we're done and return "now". ++ // If the CAS failed and the observed value "obsv" is >= now then ++ // we should return "obsv". If the CAS failed and now > obsv > prv then ++ // some other thread raced this thread and installed a new value, in which case ++ // we could either (a) retry the entire operation, (b) retry trying to install now ++ // or (c) just return obsv. We use (c). No loop is required although in some cases ++ // we might discard a higher "now" value in deference to a slightly lower but freshly ++ // installed obsv value. That's entirely benign -- it admits no new orderings compared ++ // to (a) or (b) -- and greatly reduces coherence traffic. ++ // We might also condition (c) on the magnitude of the delta between obsv and now. ++ // Avoiding excessive CAS operations to hot RW locations is critical. ++ // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate ++ return (prev == obsv) ? now : obsv; ++} ++ ++double os::elapsedVTime() { ++ return (double)gethrvtime() / (double)hrtime_hz; ++} ++ ++// DLL functions ++ ++// This must be hard coded because it's the system's temporary ++// directory not the java application's temp directory, ala java.io.tmpdir. ++const char* os::get_temp_directory() { return "/tmp"; } ++ ++// check if addr is inside libjvm.so ++bool os::address_is_in_vm(address addr) { ++ static address libjvm_base_addr; ++ Dl_info dlinfo; ++ ++ if (libjvm_base_addr == NULL) { ++ if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) { ++ libjvm_base_addr = (address)dlinfo.dli_fbase; ++ } ++ assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm"); ++ } ++ ++ if (dladdr((void *)addr, &dlinfo) != 0) { ++ if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true; ++ } ++ ++ return false; ++} ++ ++void os::prepare_native_symbols() { ++} ++ ++typedef int (*dladdr1_func_type)(void *, Dl_info *, void **, int); ++static dladdr1_func_type dladdr1_func = NULL; ++ ++bool os::dll_address_to_function_name(address addr, char *buf, ++ int buflen, int * offset, ++ bool demangle) { ++ // buf is not optional, but offset is optional ++ assert(buf != NULL, "sanity check"); ++ ++ Dl_info dlinfo; ++ ++ // dladdr1_func was initialized in os::init() ++ if (dladdr1_func != NULL) { ++ // yes, we have dladdr1 ++ ++ // Support for dladdr1 is checked at runtime; it may be ++ // available even if the vm is built on a machine that does ++ // not have dladdr1 support. Make sure there is a value for ++ // RTLD_DL_SYMENT. ++#ifndef RTLD_DL_SYMENT ++ #define RTLD_DL_SYMENT 1 ++#endif ++#ifdef _LP64 ++ Elf64_Sym * info; ++#else ++ Elf32_Sym * info; ++#endif ++ if (dladdr1_func((void *)addr, &dlinfo, (void **)&info, ++ RTLD_DL_SYMENT) != 0) { ++ // see if we have a matching symbol that covers our address ++ if (dlinfo.dli_saddr != NULL && ++ (char *)dlinfo.dli_saddr + info->st_size > (char *)addr) { ++ if (dlinfo.dli_sname != NULL) { ++ if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) { ++ jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname); ++ } ++ if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; ++ return true; ++ } ++ } ++ // no matching symbol so try for just file info ++ if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) { ++ if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), ++ buf, buflen, offset, dlinfo.dli_fname, demangle)) { ++ return true; ++ } ++ } ++ } ++ buf[0] = '\0'; ++ if (offset != NULL) *offset = -1; ++ return false; ++ } ++ ++ // no, only dladdr is available ++ if (dladdr((void *)addr, &dlinfo) != 0) { ++ // see if we have a matching symbol ++ if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) { ++ if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) { ++ jio_snprintf(buf, buflen, dlinfo.dli_sname); ++ } ++ if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr; ++ return true; ++ } ++ // no matching symbol so try for just file info ++ if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) { ++ if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase), ++ buf, buflen, offset, dlinfo.dli_fname, demangle)) { ++ return true; ++ } ++ } ++ } ++ buf[0] = '\0'; ++ if (offset != NULL) *offset = -1; ++ return false; ++} ++ ++bool os::dll_address_to_library_name(address addr, char* buf, ++ int buflen, int* offset) { ++ // buf is not optional, but offset is optional ++ assert(buf != NULL, "sanity check"); ++ ++ Dl_info dlinfo; ++ ++ if (dladdr((void*)addr, &dlinfo) != 0) { ++ if (dlinfo.dli_fname != NULL) { ++ jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname); ++ } ++ if (dlinfo.dli_fbase != NULL && offset != NULL) { ++ *offset = addr - (address)dlinfo.dli_fbase; ++ } ++ return true; ++ } ++ ++ buf[0] = '\0'; ++ if (offset) *offset = -1; ++ return false; ++} ++ ++int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) { ++ Dl_info dli; ++ // Sanity check? ++ if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 || ++ dli.dli_fname == NULL) { ++ return 1; ++ } ++ ++ void * handle = dlopen(dli.dli_fname, RTLD_LAZY); ++ if (handle == NULL) { ++ return 1; ++ } ++ ++ Link_map *map; ++ dlinfo(handle, RTLD_DI_LINKMAP, &map); ++ if (map == NULL) { ++ dlclose(handle); ++ return 1; ++ } ++ ++ while (map->l_prev != NULL) { ++ map = map->l_prev; ++ } ++ ++ while (map != NULL) { ++ // Iterate through all map entries and call callback with fields of interest ++ if(callback(map->l_name, (address)map->l_addr, (address)0, param)) { ++ dlclose(handle); ++ return 1; ++ } ++ map = map->l_next; ++ } ++ ++ dlclose(handle); ++ return 0; ++} ++ ++int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) { ++ outputStream * out = (outputStream *) param; ++ out->print_cr(INTPTR_FORMAT " \t%s", (intptr_t)base_address, name); ++ return 0; ++} ++ ++void os::print_dll_info(outputStream * st) { ++ st->print_cr("Dynamic libraries:"); st->flush(); ++ if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) { ++ st->print_cr("Error: Cannot print dynamic libraries."); ++ } ++} ++ ++static void change_endianness(Elf32_Half& val) { ++ unsigned char *ptr = (unsigned char *)&val; ++ unsigned char swp = ptr[0]; ++ ptr[0] = ptr[1]; ++ ptr[1] = swp; ++} ++ ++// Loads .dll/.so and ++// in case of error it checks if .dll/.so was built for the ++// same architecture as Hotspot is running on ++ ++void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { ++ log_info(os)("attempting shared library load of %s", filename); ++ ++ void * result= ::dlopen(filename, RTLD_LAZY); ++ if (result != NULL) { ++ // Successful loading ++ Events::log(NULL, "Loaded shared library %s", filename); ++ log_info(os)("shared library load of %s was successful", filename); ++ return result; ++ } ++ ++ Elf32_Ehdr elf_head; ++ const char* error_report = ::dlerror(); ++ if (error_report == NULL) { ++ error_report = "dlerror returned no error description"; ++ } ++ if (ebuf != NULL && ebuflen > 0) { ++ ::strncpy(ebuf, error_report, ebuflen-1); ++ ebuf[ebuflen-1]='\0'; ++ } ++ ++ Events::log(NULL, "Loading shared library %s failed, %s", filename, error_report); ++ log_info(os)("shared library load of %s failed, %s", filename, error_report); ++ ++ int diag_msg_max_length=ebuflen-strlen(ebuf); ++ char* diag_msg_buf=ebuf+strlen(ebuf); ++ ++ if (diag_msg_max_length==0) { ++ // No more space in ebuf for additional diagnostics message ++ return NULL; ++ } ++ ++ ++ int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK); ++ ++ if (file_descriptor < 0) { ++ // Can't open library, report dlerror() message ++ return NULL; ++ } ++ ++ bool failed_to_read_elf_head= ++ (sizeof(elf_head)!= ++ (::read(file_descriptor, &elf_head,sizeof(elf_head)))); ++ ++ ::close(file_descriptor); ++ if (failed_to_read_elf_head) { ++ // file i/o error - report dlerror() msg ++ return NULL; ++ } ++ ++ if (elf_head.e_ident[EI_DATA] != LITTLE_ENDIAN_ONLY(ELFDATA2LSB) BIG_ENDIAN_ONLY(ELFDATA2MSB)) { ++ // handle invalid/out of range endianness values ++ if (elf_head.e_ident[EI_DATA] == 0 || elf_head.e_ident[EI_DATA] > 2) { ++ return NULL; ++ } ++ change_endianness(elf_head.e_machine); ++ } ++ ++ typedef struct { ++ Elf32_Half code; // Actual value as defined in elf.h ++ Elf32_Half compat_class; // Compatibility of archs at VM's sense ++ unsigned char elf_class; // 32 or 64 bit ++ unsigned char endianess; // MSB or LSB ++ char* name; // String representation ++ } arch_t; ++ ++ static const arch_t arch_array[]={ ++ {EM_386, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, ++ {EM_486, EM_386, ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"}, ++ {EM_IA_64, EM_IA_64, ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"}, ++ {EM_X86_64, EM_X86_64, ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"}, ++ {EM_SPARC, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, ++ {EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"}, ++ {EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"}, ++ {EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"}, ++ {EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"}, ++ {EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"}, ++ // we only support 64 bit z architecture ++ {EM_S390, EM_S390, ELFCLASS64, ELFDATA2MSB, (char*)"IBM System/390"}, ++ {EM_AARCH64, EM_AARCH64, ELFCLASS64, ELFDATA2LSB, (char*)"AARCH64"} ++ }; ++ ++#if (defined IA32) ++ static Elf32_Half running_arch_code=EM_386; ++#elif (defined AMD64) ++ static Elf32_Half running_arch_code=EM_X86_64; ++#elif (defined IA64) ++ static Elf32_Half running_arch_code=EM_IA_64; ++#elif (defined __sparc) && (defined _LP64) ++ static Elf32_Half running_arch_code=EM_SPARCV9; ++#elif (defined __sparc) && (!defined _LP64) ++ static Elf32_Half running_arch_code=EM_SPARC; ++#elif (defined __powerpc64__) ++ static Elf32_Half running_arch_code=EM_PPC64; ++#elif (defined __powerpc__) ++ static Elf32_Half running_arch_code=EM_PPC; ++#elif (defined ARM) ++ static Elf32_Half running_arch_code=EM_ARM; ++#else ++ #error Method os::dll_load requires that one of following is defined:\ ++ IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM ++#endif ++ ++ // Identify compatibility class for VM's architecture and library's architecture ++ // Obtain string descriptions for architectures ++ ++ arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL}; ++ int running_arch_index=-1; ++ ++ for (unsigned int i=0; i < ARRAY_SIZE(arch_array); i++) { ++ if (running_arch_code == arch_array[i].code) { ++ running_arch_index = i; ++ } ++ if (lib_arch.code == arch_array[i].code) { ++ lib_arch.compat_class = arch_array[i].compat_class; ++ lib_arch.name = arch_array[i].name; ++ } ++ } ++ ++ assert(running_arch_index != -1, ++ "Didn't find running architecture code (running_arch_code) in arch_array"); ++ if (running_arch_index == -1) { ++ // Even though running architecture detection failed ++ // we may still continue with reporting dlerror() message ++ return NULL; ++ } ++ ++ if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) { ++ if (lib_arch.name != NULL) { ++ ::snprintf(diag_msg_buf, diag_msg_max_length-1, ++ " (Possible cause: can't load %s .so on a %s platform)", ++ lib_arch.name, arch_array[running_arch_index].name); ++ } else { ++ ::snprintf(diag_msg_buf, diag_msg_max_length-1, ++ " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)", ++ lib_arch.code, arch_array[running_arch_index].name); ++ } ++ return NULL; ++ } ++ ++ if (lib_arch.endianess != arch_array[running_arch_index].endianess) { ++ ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)"); ++ return NULL; ++ } ++ ++ // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit ++ if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) { ++ ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)"); ++ return NULL; ++ } ++ ++ if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) { ++ ::snprintf(diag_msg_buf, diag_msg_max_length-1, ++ " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)", ++ (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32); ++ return NULL; ++ } ++ ++ return NULL; ++} ++ ++static inline time_t get_mtime(const char* filename) { ++ struct stat st; ++ int ret = os::stat(filename, &st); ++ assert(ret == 0, "failed to stat() file '%s': %s", filename, os::strerror(errno)); ++ return st.st_mtime; ++} ++ ++int os::compare_file_modified_times(const char* file1, const char* file2) { ++ time_t t1 = get_mtime(file1); ++ time_t t2 = get_mtime(file2); ++ return t1 - t2; ++} ++ ++static bool _print_ascii_file(const char* filename, outputStream* st) { ++ int fd = ::open(filename, O_RDONLY); ++ if (fd == -1) { ++ return false; ++ } ++ ++ char buf[32]; ++ int bytes; ++ while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) { ++ st->print_raw(buf, bytes); ++ } ++ ++ ::close(fd); ++ ++ return true; ++} ++ ++void os::print_os_info_brief(outputStream* st) { ++ os::Solaris::print_distro_info(st); ++ ++ os::Posix::print_uname_info(st); ++ ++ os::Solaris::print_libversion_info(st); ++} ++ ++void os::print_os_info(outputStream* st) { ++ st->print("OS:"); ++ ++ os::Solaris::print_distro_info(st); ++ ++ os::Posix::print_uname_info(st); ++ ++ os::Posix::print_uptime_info(st); ++ ++ os::Solaris::print_libversion_info(st); ++ ++ os::Posix::print_rlimit_info(st); ++ ++ os::Posix::print_load_average(st); ++} ++ ++void os::Solaris::print_distro_info(outputStream* st) { ++ if (!_print_ascii_file("/etc/release", st)) { ++ st->print("Solaris"); ++ } ++ st->cr(); ++} ++ ++void os::get_summary_os_info(char* buf, size_t buflen) { ++ strncpy(buf, "Solaris", buflen); // default to plain solaris ++ FILE* fp = fopen("/etc/release", "r"); ++ if (fp != NULL) { ++ char tmp[256]; ++ // Only get the first line and chop out everything but the os name. ++ if (fgets(tmp, sizeof(tmp), fp)) { ++ char* ptr = tmp; ++ // skip past whitespace characters ++ while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++; ++ if (*ptr != '\0') { ++ char* nl = strchr(ptr, '\n'); ++ if (nl != NULL) *nl = '\0'; ++ strncpy(buf, ptr, buflen); ++ } ++ } ++ fclose(fp); ++ } ++} ++ ++void os::Solaris::print_libversion_info(outputStream* st) { ++ st->print(" (T2 libthread)"); ++ st->cr(); ++} ++ ++static bool check_addr0(outputStream* st) { ++ jboolean status = false; ++ const int read_chunk = 200; ++ int ret = 0; ++ int nmap = 0; ++ int fd = ::open("/proc/self/map",O_RDONLY); ++ if (fd >= 0) { ++ prmap_t *p = NULL; ++ char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t)); ++ if (NULL == mbuff) { ++ ::close(fd); ++ return status; ++ } ++ while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) { ++ //check if read() has not read partial data ++ if( 0 != ret % sizeof(prmap_t)){ ++ break; ++ } ++ nmap = ret / sizeof(prmap_t); ++ p = (prmap_t *)mbuff; ++ for(int i = 0; i < nmap; i++){ ++ if (p->pr_vaddr == 0x0) { ++ st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024); ++ st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname); ++ st->print("Access: "); ++ st->print("%s",(p->pr_mflags & MA_READ) ? "r" : "-"); ++ st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-"); ++ st->print("%s",(p->pr_mflags & MA_EXEC) ? "x" : "-"); ++ st->cr(); ++ status = true; ++ } ++ p++; ++ } ++ } ++ free(mbuff); ++ ::close(fd); ++ } ++ return status; ++} ++ ++void os::get_summary_cpu_info(char* buf, size_t buflen) { ++ // Get MHz with system call. We don't seem to already have this. ++ processor_info_t stats; ++ processorid_t id = getcpuid(); ++ int clock = 0; ++ if (processor_info(id, &stats) != -1) { ++ clock = stats.pi_clock; // pi_processor_type isn't more informative than below ++ } ++ snprintf(buf, buflen, "64 bit %d MHz", clock); ++} ++ ++void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { ++ // Nothing to do for now. ++} ++ ++void os::print_memory_info(outputStream* st) { ++ st->print("Memory:"); ++ st->print(" " SIZE_FORMAT "k page", os::vm_page_size()>>10); ++ st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10); ++ st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10); ++ st->cr(); ++ (void) check_addr0(st); ++} ++ ++static int Maxsignum = 0; ++ ++static char saved_jvm_path[MAXPATHLEN] = { 0 }; ++ ++// Find the full path to the current module, libjvm.so ++void os::jvm_path(char *buf, jint buflen) { ++ // Error checking. ++ if (buflen < MAXPATHLEN) { ++ assert(false, "must use a large-enough buffer"); ++ buf[0] = '\0'; ++ return; ++ } ++ // Lazy resolve the path to current module. ++ if (saved_jvm_path[0] != 0) { ++ strcpy(buf, saved_jvm_path); ++ return; ++ } ++ ++ Dl_info dlinfo; ++ int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo); ++ assert(ret != 0, "cannot locate libjvm"); ++ if (ret != 0 && dlinfo.dli_fname != NULL) { ++ if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { ++ return; ++ } ++ } else { ++ buf[0] = '\0'; ++ return; ++ } ++ ++ if (Arguments::sun_java_launcher_is_altjvm()) { ++ // Support for the java launcher's '-XXaltjvm=' option. Typical ++ // value for buf is "/jre/lib///libjvm.so". ++ // If "/jre/lib/" appears at the right place in the string, then ++ // assume we are installed in a JDK and we're done. Otherwise, check ++ // for a JAVA_HOME environment variable and fix up the path so it ++ // looks like libjvm.so is installed there (append a fake suffix ++ // hotspot/libjvm.so). ++ const char *p = buf + strlen(buf) - 1; ++ for (int count = 0; p > buf && count < 5; ++count) { ++ for (--p; p > buf && *p != '/'; --p) ++ /* empty */ ; ++ } ++ ++ if (strncmp(p, "/jre/lib/", 9) != 0) { ++ // Look for JAVA_HOME in the environment. ++ char* java_home_var = ::getenv("JAVA_HOME"); ++ if (java_home_var != NULL && java_home_var[0] != 0) { ++ char* jrelib_p; ++ int len; ++ ++ // Check the current module name "libjvm.so". ++ p = strrchr(buf, '/'); ++ assert(strstr(p, "/libjvm") == p, "invalid library name"); ++ ++ if (os::Posix::realpath(java_home_var, buf, buflen) == NULL) { ++ return; ++ } ++ // determine if this is a legacy image or modules image ++ // modules image doesn't have "jre" subdirectory ++ len = strlen(buf); ++ assert(len < buflen, "Ran out of buffer space"); ++ jrelib_p = buf + len; ++ snprintf(jrelib_p, buflen-len, "/jre/lib"); ++ if (0 != access(buf, F_OK)) { ++ snprintf(jrelib_p, buflen-len, "/lib"); ++ } ++ ++ if (0 == access(buf, F_OK)) { ++ // Use current module name "libjvm.so" ++ len = strlen(buf); ++ snprintf(buf + len, buflen-len, "/hotspot/libjvm.so"); ++ } else { ++ // Go back to path of .so ++ if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) { ++ return; ++ } ++ } ++ } ++ } ++ } ++ ++ strncpy(saved_jvm_path, buf, MAXPATHLEN); ++ saved_jvm_path[MAXPATHLEN - 1] = '\0'; ++} ++ ++//////////////////////////////////////////////////////////////////////////////// ++// Virtual Memory ++ ++static bool recoverable_mmap_error(int err) { ++ // See if the error is one we can let the caller handle. This ++ // list of errno values comes from the Solaris mmap(2) man page. ++ switch (err) { ++ case EBADF: ++ case EINVAL: ++ case ENOTSUP: ++ // let the caller deal with these errors ++ return true; ++ ++ default: ++ // Any remaining errors on this OS can cause our reserved mapping ++ // to be lost. That can cause confusion where different data ++ // structures think they have the same memory mapped. The worst ++ // scenario is if both the VM and a library think they have the ++ // same memory mapped. ++ return false; ++ } ++} ++ ++static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec, ++ int err) { ++ warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ++ ", %d) failed; error='%s' (errno=%d)", p2i(addr), bytes, exec, ++ os::strerror(err), err); ++} ++ ++static void warn_fail_commit_memory(char* addr, size_t bytes, ++ size_t alignment_hint, bool exec, ++ int err) { ++ warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT ++ ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr), ++ bytes, alignment_hint, exec, os::strerror(err), err); ++} ++ ++int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) { ++ int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE; ++ size_t size = bytes; ++ char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot); ++ if (res != NULL) { ++ if (UseNUMAInterleaving) { ++ numa_make_global(addr, bytes); ++ } ++ return 0; ++ } ++ ++ int err = errno; // save errno from mmap() call in mmap_chunk() ++ ++ if (!recoverable_mmap_error(err)) { ++ warn_fail_commit_memory(addr, bytes, exec, err); ++ vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "committing reserved memory."); ++ } ++ ++ return err; ++} ++ ++bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) { ++ return Solaris::commit_memory_impl(addr, bytes, exec) == 0; ++} ++ ++void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec, ++ const char* mesg) { ++ assert(mesg != NULL, "mesg must be specified"); ++ int err = os::Solaris::commit_memory_impl(addr, bytes, exec); ++ if (err != 0) { ++ // the caller wants all commit errors to exit with the specified mesg: ++ warn_fail_commit_memory(addr, bytes, exec, err); ++ vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); ++ } ++} ++ ++size_t os::Solaris::page_size_for_alignment(size_t alignment) { ++ assert(is_aligned(alignment, (size_t) os::vm_page_size()), ++ SIZE_FORMAT " is not aligned to " SIZE_FORMAT, ++ alignment, (size_t) os::vm_page_size()); ++ ++ int page_sizes_max = 9; ++ size_t _illumos_page_sizes[page_sizes_max]; ++ int n = getpagesizes(_illumos_page_sizes, page_sizes_max); ++ for (int i = 0; _illumos_page_sizes[i] != 0; i++) { ++ if (is_aligned(alignment, _illumos_page_sizes[i])) { ++ return _illumos_page_sizes[i]; ++ } ++ } ++ ++ return (size_t) os::vm_page_size(); ++} ++ ++int os::Solaris::commit_memory_impl(char* addr, size_t bytes, ++ size_t alignment_hint, bool exec) { ++ int err = Solaris::commit_memory_impl(addr, bytes, exec); ++ if (err == 0 && UseLargePages && alignment_hint > 0) { ++ assert(is_aligned(bytes, alignment_hint), ++ SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint); ++ ++ // The syscall memcntl requires an exact page size (see man memcntl for details). ++ size_t page_size = page_size_for_alignment(alignment_hint); ++ if (page_size > (size_t) os::vm_page_size()) { ++ (void)Solaris::setup_large_pages(addr, bytes, page_size); ++ } ++ } ++ return err; ++} ++ ++bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint, ++ bool exec) { ++ return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0; ++} ++ ++void os::pd_commit_memory_or_exit(char* addr, size_t bytes, ++ size_t alignment_hint, bool exec, ++ const char* mesg) { ++ assert(mesg != NULL, "mesg must be specified"); ++ int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec); ++ if (err != 0) { ++ // the caller wants all commit errors to exit with the specified mesg: ++ warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err); ++ vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg); ++ } ++} ++ ++// Uncommit the pages in a specified region. ++void os::pd_free_memory(char* addr, size_t bytes, size_t alignment_hint) { ++ if (posix_madvise(addr, bytes, MADV_FREE) < 0) { ++ debug_only(warning("MADV_FREE failed.")); ++ return; ++ } ++} ++ ++size_t os::pd_pretouch_memory(void* first, void* last, size_t page_size) { ++ return page_size; ++} ++ ++bool os::pd_create_stack_guard_pages(char* addr, size_t size) { ++ return os::commit_memory(addr, size, !ExecMem); ++} ++ ++bool os::remove_stack_guard_pages(char* addr, size_t size) { ++ return os::uncommit_memory(addr, size); ++} ++ ++// Change the page size in a given range. ++void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) { ++ assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned."); ++ assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned."); ++ if (UseLargePages) { ++ size_t page_size = Solaris::page_size_for_alignment(alignment_hint); ++ if (page_size > (size_t) os::vm_page_size()) { ++ Solaris::setup_large_pages(addr, bytes, page_size); ++ } ++ } ++} ++ ++// Tell the OS to make the range local to the first-touching LWP ++void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { ++ assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned."); ++ if (posix_madvise(addr, bytes, MADV_ACCESS_LWP) < 0) { ++ debug_only(warning("MADV_ACCESS_LWP failed.")); ++ } ++} ++ ++// Tell the OS that this range would be accessed from different LWPs. ++void os::numa_make_global(char *addr, size_t bytes) { ++ assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned."); ++ if (posix_madvise(addr, bytes, MADV_ACCESS_MANY) < 0) { ++ debug_only(warning("MADV_ACCESS_MANY failed.")); ++ } ++} ++ ++// Get the number of the locality groups. ++size_t os::numa_get_groups_num() { ++ size_t n = Solaris::lgrp_nlgrps(Solaris::lgrp_cookie()); ++ return n != -1 ? n : 1; ++} ++ ++// Get a list of leaf locality groups. A leaf lgroup is group that ++// doesn't have any children. Typical leaf group is a CPU or a CPU/memory ++// board. An LWP is assigned to one of these groups upon creation. ++size_t os::numa_get_leaf_groups(int *ids, size_t size) { ++ if ((ids[0] = Solaris::lgrp_root(Solaris::lgrp_cookie())) == -1) { ++ ids[0] = 0; ++ return 1; ++ } ++ int result_size = 0, top = 1, bottom = 0, cur = 0; ++ for (unsigned int k = 0; k < size; k++) { ++ int r = Solaris::lgrp_children(Solaris::lgrp_cookie(), ids[cur], ++ (Solaris::lgrp_id_t*)&ids[top], size - top); ++ if (r == -1) { ++ ids[0] = 0; ++ return 1; ++ } ++ if (!r) { ++ // That's a leaf node. ++ assert(bottom <= cur, "Sanity check"); ++ // Check if the node has memory ++ if (Solaris::lgrp_resources(Solaris::lgrp_cookie(), ids[cur], ++ NULL, 0, LGRP_RSRC_MEM) > 0) { ++ ids[bottom++] = ids[cur]; ++ } ++ } ++ top += r; ++ cur++; ++ } ++ if (bottom == 0) { ++ // Handle a situation, when the OS reports no memory available. ++ // Assume UMA architecture. ++ ids[0] = 0; ++ return 1; ++ } ++ return bottom; ++} ++ ++// Detect the topology change. Typically happens during CPU plugging-unplugging. ++bool os::numa_topology_changed() { ++ int is_stale = Solaris::lgrp_cookie_stale(Solaris::lgrp_cookie()); ++ if (is_stale != -1 && is_stale) { ++ Solaris::lgrp_fini(Solaris::lgrp_cookie()); ++ Solaris::lgrp_cookie_t c = Solaris::lgrp_init(Solaris::LGRP_VIEW_CALLER); ++ assert(c != 0, "Failure to initialize LGRP API"); ++ Solaris::set_lgrp_cookie(c); ++ return true; ++ } ++ return false; ++} ++ ++// Get the group id of the current LWP. ++int os::numa_get_group_id() { ++ int lgrp_id = Solaris::lgrp_home(P_LWPID, P_MYID); ++ if (lgrp_id == -1) { ++ return 0; ++ } ++ const int size = os::numa_get_groups_num(); ++ int *ids = (int*)alloca(size * sizeof(int)); ++ ++ // Get the ids of all lgroups with memory; r is the count. ++ int r = Solaris::lgrp_resources(Solaris::lgrp_cookie(), lgrp_id, ++ (Solaris::lgrp_id_t*)ids, size, LGRP_RSRC_MEM); ++ if (r <= 0) { ++ return 0; ++ } ++ return ids[os::random() % r]; ++} ++ ++int os::numa_get_group_id_for_address(const void* address) { ++ return 0; ++} ++ ++bool os::numa_get_group_ids_for_range(const void** addresses, int* lgrp_ids, size_t count) { ++ return false; ++} ++ ++// Scan the pages from start to end until a page different than ++// the one described in the info parameter is encountered. ++char *os::scan_pages(char *start, char* end, page_info* page_expected, ++ page_info* page_found) { ++ const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE }; ++ const size_t types = sizeof(info_types) / sizeof(info_types[0]); ++ uint64_t addrs[MAX_MEMINFO_CNT], outdata[types * MAX_MEMINFO_CNT + 1]; ++ uint_t validity[MAX_MEMINFO_CNT]; ++ ++ size_t page_size = MAX2((size_t)os::vm_page_size(), page_expected->size); ++ uint64_t p = (uint64_t)start; ++ while (p < (uint64_t)end) { ++ addrs[0] = p; ++ size_t addrs_count = 1; ++ while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) { ++ addrs[addrs_count] = addrs[addrs_count - 1] + page_size; ++ addrs_count++; ++ } ++ ++ if (meminfo(addrs, addrs_count, info_types, types, outdata, validity) < 0) { ++ return NULL; ++ } ++ ++ size_t i = 0; ++ for (; i < addrs_count; i++) { ++ if ((validity[i] & 1) != 0) { ++ if ((validity[i] & 4) != 0) { ++ if (outdata[types * i + 1] != page_expected->size) { ++ break; ++ } ++ } else if (page_expected->size != 0) { ++ break; ++ } ++ ++ if ((validity[i] & 2) != 0 && page_expected->lgrp_id > 0) { ++ if (outdata[types * i] != page_expected->lgrp_id) { ++ break; ++ } ++ } ++ } else { ++ return NULL; ++ } ++ } ++ ++ if (i < addrs_count) { ++ if ((validity[i] & 2) != 0) { ++ page_found->lgrp_id = outdata[types * i]; ++ } else { ++ page_found->lgrp_id = -1; ++ } ++ if ((validity[i] & 4) != 0) { ++ page_found->size = outdata[types * i + 1]; ++ } else { ++ page_found->size = 0; ++ } ++ return (char*)addrs[i]; ++ } ++ ++ p = addrs[addrs_count - 1] + page_size; ++ } ++ return end; ++} ++ ++bool os::pd_uncommit_memory(char* addr, size_t bytes, bool exec) { ++ size_t size = bytes; ++ // Map uncommitted pages PROT_NONE so we fail early if we touch an ++ // uncommitted page. Otherwise, the read/write might succeed if we ++ // have enough swap space to back the physical page. ++ return ++ NULL != Solaris::mmap_chunk(addr, size, ++ MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE, ++ PROT_NONE); ++} ++ ++char* os::Solaris::mmap_chunk(char *addr, size_t size, int flags, int prot) { ++ char *b = (char *)mmap(addr, size, prot, flags, os::Solaris::_dev_zero_fd, 0); ++ ++ if (b == MAP_FAILED) { ++ return NULL; ++ } ++ return b; ++} ++ ++char* os::Solaris::anon_mmap(char* requested_addr, size_t bytes) { ++ char* addr = requested_addr; ++ int flags = MAP_PRIVATE | MAP_NORESERVE; ++ ++ // Map uncommitted pages PROT_NONE so we fail early if we touch an ++ // uncommitted page. Otherwise, the read/write might succeed if we ++ // have enough swap space to back the physical page. ++ return mmap_chunk(addr, bytes, flags, PROT_NONE); ++} ++ ++char* os::pd_reserve_memory(size_t bytes, bool exec) { ++ char* addr = Solaris::anon_mmap(NULL, bytes); ++ ++ return addr; ++} ++ ++char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) { ++ assert(file_desc >= 0, "file_desc is not valid"); ++ char* result = pd_attempt_reserve_memory_at(requested_addr, bytes, !ExecMem); ++ if (result != NULL) { ++ if (replace_existing_mapping_with_file_mapping(result, bytes, file_desc) == NULL) { ++ vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory")); ++ } ++ } ++ return result; ++} ++ ++// Reserve memory at an arbitrary address, only if that area is ++// available (and not reserved for something else). ++ ++char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool exec) { ++ // Assert only that the size is a multiple of the page size, since ++ // that's all that mmap requires, and since that's all we really know ++ // about at this low abstraction level. If we need higher alignment, ++ // we can either pass an alignment to this method or verify alignment ++ // in one of the methods further up the call chain. See bug 5044738. ++ assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block"); ++ ++ // Since snv_84, Solaris attempts to honor the address hint - see 5003415. ++ char* addr = Solaris::anon_mmap(requested_addr, bytes); ++ ++ volatile int err = errno; ++ if (addr == requested_addr) { ++ return addr; ++ } ++ ++ if (addr != NULL) { ++ pd_unmap_memory(addr, bytes); ++ } ++ ++ return NULL; ++} ++ ++bool os::pd_release_memory(char* addr, size_t bytes) { ++ size_t size = bytes; ++ return munmap(addr, size) == 0; ++} ++ ++static bool solaris_mprotect(char* addr, size_t bytes, int prot) { ++ assert(addr == (char*)align_down((uintptr_t)addr, os::vm_page_size()), ++ "addr must be page aligned"); ++ Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+bytes), prot); ++ int retVal = mprotect(addr, bytes, prot); ++ return retVal == 0; ++} ++ ++// Protect memory (Used to pass readonly pages through ++// JNI GetArrayElements with empty arrays.) ++// Also, used for serialization page and for compressed oops null pointer ++// checking. ++bool os::protect_memory(char* addr, size_t bytes, ProtType prot, ++ bool is_committed) { ++ unsigned int p = 0; ++ switch (prot) { ++ case MEM_PROT_NONE: p = PROT_NONE; break; ++ case MEM_PROT_READ: p = PROT_READ; break; ++ case MEM_PROT_RW: p = PROT_READ|PROT_WRITE; break; ++ case MEM_PROT_RWX: p = PROT_READ|PROT_WRITE|PROT_EXEC; break; ++ default: ++ ShouldNotReachHere(); ++ } ++ // is_committed is unused. ++ return solaris_mprotect(addr, bytes, p); ++} ++ ++// guard_memory and unguard_memory only happens within stack guard pages. ++// Since ISM pertains only to the heap, guard and unguard memory should not ++/// happen with an ISM region. ++bool os::guard_memory(char* addr, size_t bytes) { ++ return solaris_mprotect(addr, bytes, PROT_NONE); ++} ++ ++bool os::unguard_memory(char* addr, size_t bytes) { ++ return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE); ++} ++ ++// Large page support ++static size_t _large_page_size = 0; ++ ++bool os::Solaris::mpss_sanity_check(bool warn, size_t* page_size) { ++ // Find the page sizes supported by the system ++ int page_sizes_max = 9; ++ size_t _illumos_page_sizes[page_sizes_max]; ++ int n = getpagesizes(_illumos_page_sizes, page_sizes_max); ++ assert(n > 0, "illumos bug?"); ++ ++ if (n == 1) return false; // Only one page size available. ++ ++ // Skip sizes larger than 4M (or LargePageSizeInBytes if it was set) ++ const size_t size_limit = ++ FLAG_IS_DEFAULT(LargePageSizeInBytes) ? 4 * M : LargePageSizeInBytes; ++ int beg; ++ for (beg = 0; beg < n; ++beg) { ++ if (_illumos_page_sizes[beg] <= size_limit) { ++ _page_sizes.add(_illumos_page_sizes[beg]); ++ if (_illumos_page_sizes[beg] > *page_size) { ++ *page_size = _illumos_page_sizes[beg]; ++ } ++ } ++ } ++ // make sure we add the default ++ _page_sizes.add(os::vm_page_size()); ++ return true; ++} ++ ++void os::large_page_init() { ++ if (UseLargePages) { ++ // print a warning if any large page related flag is specified on command line ++ bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages) || ++ !FLAG_IS_DEFAULT(LargePageSizeInBytes); ++ ++ UseLargePages = Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size); ++ } ++} ++ ++bool os::Solaris::is_valid_page_size(size_t bytes) { ++ return _page_sizes.contains(bytes); ++} ++ ++bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) { ++ assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align); ++ assert(is_aligned((void*) start, align), ++ PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align); ++ assert(is_aligned(bytes, align), ++ SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align); ++ ++ // Signal to OS that we want large pages for addresses ++ // from addr, addr + bytes ++ struct memcntl_mha mpss_struct; ++ mpss_struct.mha_cmd = MHA_MAPSIZE_VA; ++ mpss_struct.mha_pagesize = align; ++ mpss_struct.mha_flags = 0; ++ // Upon successful completion, memcntl() returns 0 ++ if (memcntl(start, bytes, MC_HAT_ADVISE, (caddr_t) &mpss_struct, 0, 0)) { ++ debug_only(warning("Attempt to use MPSS failed.")); ++ return false; ++ } ++ return true; ++} ++ ++char* os::pd_reserve_memory_special(size_t size, size_t alignment, size_t page_size, char* addr, bool exec) { ++ fatal("os::reserve_memory_special should not be called on Solaris."); ++ return NULL; ++} ++ ++bool os::pd_release_memory_special(char* base, size_t bytes) { ++ fatal("os::release_memory_special should not be called on Solaris."); ++ return false; ++} ++ ++size_t os::large_page_size() { ++ return _large_page_size; ++} ++ ++// MPSS allows application to commit large page memory on demand; with ISM ++// the entire memory region must be allocated as shared memory. ++bool os::can_commit_large_page_memory() { ++ return true; ++} ++ ++bool os::can_execute_large_page_memory() { ++ return true; ++} ++ ++// Interface for setting lwp priorities. We are using T2 libthread, ++// which forces the use of bound threads, so all of our threads will ++// be assigned to real lwp's. Using the thr_setprio function is ++// meaningless in this mode so we must adjust the real lwp's priority. ++// The routines below implement the getting and setting of lwp priorities. ++// ++// Note: There are three priority scales used on Solaris. Java priorities ++// which range from 1 to 10, libthread "thr_setprio" scale which range ++// from 0 to 127, and the current scheduling class of the process we ++// are running in. This is typically from -60 to +60. ++// The setting of the lwp priorities is done after a call to thr_setprio ++// so Java priorities are mapped to libthread priorities and we map from ++// the latter to lwp priorities. We don't keep priorities stored in ++// Java priorities since some of our worker threads want to set priorities ++// higher than all Java threads. ++// ++// For related information: ++// (1) man -s 2 priocntl ++// (2) man -s 4 priocntl ++// (3) man dispadmin ++// = librt.so ++// = libthread/common/rtsched.c - thrp_setlwpprio(). ++// = ps -cL ... to validate priority. ++// = sched_get_priority_min and _max ++// pthread_create ++// sched_setparam ++// pthread_setschedparam ++// ++// Assumptions: ++// + We assume that all threads in the process belong to the same ++// scheduling class. IE. a homogeneous process. ++// + Must be root or in IA group to change change "interactive" attribute. ++// Priocntl() will fail silently. The only indication of failure is when ++// we read-back the value and notice that it hasn't changed. ++// + Interactive threads enter the runq at the head, non-interactive at the tail. ++// + For RT, change timeslice as well. Invariant: ++// constant "priority integral" ++// Konst == TimeSlice * (60-Priority) ++// Given a priority, compute appropriate timeslice. ++// + Higher numerical values have higher priority. ++ ++// sched class attributes ++typedef struct { ++ int schedPolicy; // classID ++ int maxPrio; ++ int minPrio; ++} SchedInfo; ++ ++ ++static SchedInfo tsLimits, iaLimits, rtLimits, fxLimits; ++ ++#ifdef ASSERT ++static int ReadBackValidate = 1; ++#endif ++static int myClass = 0; ++static int myMin = 0; ++static int myMax = 0; ++static int myCur = 0; ++static bool priocntl_enable = false; ++ ++static const int criticalPrio = FXCriticalPriority; ++static int java_MaxPriority_to_os_priority = 0; // Saved mapping ++ ++ ++// lwp_priocntl_init ++// ++// Try to determine the priority scale for our process. ++// ++// Return errno or 0 if OK. ++// ++static int lwp_priocntl_init() { ++ int rslt; ++ pcinfo_t ClassInfo; ++ pcparms_t ParmInfo; ++ int i; ++ ++ if (!UseThreadPriorities) return 0; ++ ++ // If ThreadPriorityPolicy is 1, switch tables ++ if (ThreadPriorityPolicy == 1) { ++ for (i = 0; i < CriticalPriority+1; i++) ++ os::java_to_os_priority[i] = prio_policy1[i]; ++ } ++ if (UseCriticalJavaThreadPriority) { ++ // MaxPriority always maps to the FX scheduling class and criticalPrio. ++ // See set_native_priority() and set_lwp_class_and_priority(). ++ // Save original MaxPriority mapping in case attempt to ++ // use critical priority fails. ++ java_MaxPriority_to_os_priority = os::java_to_os_priority[MaxPriority]; ++ // Set negative to distinguish from other priorities ++ os::java_to_os_priority[MaxPriority] = -criticalPrio; ++ } ++ ++ // Get IDs for a set of well-known scheduling classes. ++ // TODO-FIXME: GETCLINFO returns the current # of classes in the ++ // the system. We should have a loop that iterates over the ++ // classID values, which are known to be "small" integers. ++ ++ strcpy(ClassInfo.pc_clname, "TS"); ++ ClassInfo.pc_cid = -1; ++ rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); ++ if (rslt < 0) return errno; ++ assert(ClassInfo.pc_cid != -1, "cid for TS class is -1"); ++ tsLimits.schedPolicy = ClassInfo.pc_cid; ++ tsLimits.maxPrio = ((tsinfo_t*)ClassInfo.pc_clinfo)->ts_maxupri; ++ tsLimits.minPrio = -tsLimits.maxPrio; ++ ++ strcpy(ClassInfo.pc_clname, "IA"); ++ ClassInfo.pc_cid = -1; ++ rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); ++ if (rslt < 0) return errno; ++ assert(ClassInfo.pc_cid != -1, "cid for IA class is -1"); ++ iaLimits.schedPolicy = ClassInfo.pc_cid; ++ iaLimits.maxPrio = ((iainfo_t*)ClassInfo.pc_clinfo)->ia_maxupri; ++ iaLimits.minPrio = -iaLimits.maxPrio; ++ ++ strcpy(ClassInfo.pc_clname, "RT"); ++ ClassInfo.pc_cid = -1; ++ rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); ++ if (rslt < 0) return errno; ++ assert(ClassInfo.pc_cid != -1, "cid for RT class is -1"); ++ rtLimits.schedPolicy = ClassInfo.pc_cid; ++ rtLimits.maxPrio = ((rtinfo_t*)ClassInfo.pc_clinfo)->rt_maxpri; ++ rtLimits.minPrio = 0; ++ ++ strcpy(ClassInfo.pc_clname, "FX"); ++ ClassInfo.pc_cid = -1; ++ rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo); ++ if (rslt < 0) return errno; ++ assert(ClassInfo.pc_cid != -1, "cid for FX class is -1"); ++ fxLimits.schedPolicy = ClassInfo.pc_cid; ++ fxLimits.maxPrio = ((fxinfo_t*)ClassInfo.pc_clinfo)->fx_maxupri; ++ fxLimits.minPrio = 0; ++ ++ // Query our "current" scheduling class. ++ // This will normally be IA, TS or, rarely, FX or RT. ++ memset(&ParmInfo, 0, sizeof(ParmInfo)); ++ ParmInfo.pc_cid = PC_CLNULL; ++ rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo); ++ if (rslt < 0) return errno; ++ myClass = ParmInfo.pc_cid; ++ ++ // We now know our scheduling classId, get specific information ++ // about the class. ++ ClassInfo.pc_cid = myClass; ++ ClassInfo.pc_clname[0] = 0; ++ rslt = priocntl((idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo); ++ if (rslt < 0) return errno; ++ ++ memset(&ParmInfo, 0, sizeof(pcparms_t)); ++ ParmInfo.pc_cid = PC_CLNULL; ++ rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo); ++ if (rslt < 0) return errno; ++ ++ if (ParmInfo.pc_cid == rtLimits.schedPolicy) { ++ myMin = rtLimits.minPrio; ++ myMax = rtLimits.maxPrio; ++ } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) { ++ iaparms_t *iaInfo = (iaparms_t*)ParmInfo.pc_clparms; ++ myMin = iaLimits.minPrio; ++ myMax = iaLimits.maxPrio; ++ myMax = MIN2(myMax, (int)iaInfo->ia_uprilim); // clamp - restrict ++ } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) { ++ tsparms_t *tsInfo = (tsparms_t*)ParmInfo.pc_clparms; ++ myMin = tsLimits.minPrio; ++ myMax = tsLimits.maxPrio; ++ myMax = MIN2(myMax, (int)tsInfo->ts_uprilim); // clamp - restrict ++ } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) { ++ fxparms_t *fxInfo = (fxparms_t*)ParmInfo.pc_clparms; ++ myMin = fxLimits.minPrio; ++ myMax = fxLimits.maxPrio; ++ myMax = MIN2(myMax, (int)fxInfo->fx_uprilim); // clamp - restrict ++ } else { ++ return EINVAL; // no clue, punt ++ } ++ ++ priocntl_enable = true; // Enable changing priorities ++ return 0; ++} ++ ++#define IAPRI(x) ((iaparms_t *)((x).pc_clparms)) ++#define RTPRI(x) ((rtparms_t *)((x).pc_clparms)) ++#define TSPRI(x) ((tsparms_t *)((x).pc_clparms)) ++#define FXPRI(x) ((fxparms_t *)((x).pc_clparms)) ++ ++ ++// scale_to_lwp_priority ++// ++// Convert from the libthread "thr_setprio" scale to our current ++// lwp scheduling class scale. ++// ++static int scale_to_lwp_priority(int rMin, int rMax, int x) { ++ int v; ++ ++ if (x == 127) return rMax; // avoid round-down ++ v = (((x*(rMax-rMin)))/128)+rMin; ++ return v; ++} ++ ++ ++// set_lwp_class_and_priority ++int set_lwp_class_and_priority(int ThreadID, int lwpid, ++ int newPrio, int new_class, bool scale) { ++ int rslt; ++ int Actual, Expected, prv; ++ pcparms_t ParmInfo; // for GET-SET ++#ifdef ASSERT ++ pcparms_t ReadBack; // for readback ++#endif ++ ++ // Set priority via PC_GETPARMS, update, PC_SETPARMS ++ // Query current values. ++ // TODO: accelerate this by eliminating the PC_GETPARMS call. ++ // Cache "pcparms_t" in global ParmCache. ++ // TODO: elide set-to-same-value ++ ++ // If something went wrong on init, don't change priorities. ++ if (!priocntl_enable) { ++ return EINVAL; ++ } ++ ++ // If lwp hasn't started yet, just return ++ // the _start routine will call us again. ++ if (lwpid <= 0) { ++ return 0; ++ } ++ ++ memset(&ParmInfo, 0, sizeof(pcparms_t)); ++ ParmInfo.pc_cid = PC_CLNULL; ++ rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo); ++ if (rslt < 0) return errno; ++ ++ int cur_class = ParmInfo.pc_cid; ++ ParmInfo.pc_cid = (id_t)new_class; ++ ++ if (new_class == rtLimits.schedPolicy) { ++ rtparms_t *rtInfo = (rtparms_t*)ParmInfo.pc_clparms; ++ rtInfo->rt_pri = scale ? scale_to_lwp_priority(rtLimits.minPrio, ++ rtLimits.maxPrio, newPrio) ++ : newPrio; ++ rtInfo->rt_tqsecs = RT_NOCHANGE; ++ rtInfo->rt_tqnsecs = RT_NOCHANGE; ++ } else if (new_class == iaLimits.schedPolicy) { ++ iaparms_t* iaInfo = (iaparms_t*)ParmInfo.pc_clparms; ++ int maxClamped = MIN2(iaLimits.maxPrio, ++ cur_class == new_class ++ ? (int)iaInfo->ia_uprilim : iaLimits.maxPrio); ++ iaInfo->ia_upri = scale ? scale_to_lwp_priority(iaLimits.minPrio, ++ maxClamped, newPrio) ++ : newPrio; ++ iaInfo->ia_uprilim = cur_class == new_class ++ ? IA_NOCHANGE : (pri_t)iaLimits.maxPrio; ++ iaInfo->ia_mode = IA_NOCHANGE; ++ } else if (new_class == tsLimits.schedPolicy) { ++ tsparms_t* tsInfo = (tsparms_t*)ParmInfo.pc_clparms; ++ int maxClamped = MIN2(tsLimits.maxPrio, ++ cur_class == new_class ++ ? (int)tsInfo->ts_uprilim : tsLimits.maxPrio); ++ tsInfo->ts_upri = scale ? scale_to_lwp_priority(tsLimits.minPrio, ++ maxClamped, newPrio) ++ : newPrio; ++ tsInfo->ts_uprilim = cur_class == new_class ++ ? TS_NOCHANGE : (pri_t)tsLimits.maxPrio; ++ } else if (new_class == fxLimits.schedPolicy) { ++ fxparms_t* fxInfo = (fxparms_t*)ParmInfo.pc_clparms; ++ int maxClamped = MIN2(fxLimits.maxPrio, ++ cur_class == new_class ++ ? (int)fxInfo->fx_uprilim : fxLimits.maxPrio); ++ fxInfo->fx_upri = scale ? scale_to_lwp_priority(fxLimits.minPrio, ++ maxClamped, newPrio) ++ : newPrio; ++ fxInfo->fx_uprilim = cur_class == new_class ++ ? FX_NOCHANGE : (pri_t)fxLimits.maxPrio; ++ fxInfo->fx_tqsecs = FX_NOCHANGE; ++ fxInfo->fx_tqnsecs = FX_NOCHANGE; ++ } else { ++ return EINVAL; // no clue, punt ++ } ++ ++ rslt = priocntl(P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo); ++ if (rslt < 0) return errno; ++ ++#ifdef ASSERT ++ // Sanity check: read back what we just attempted to set. ++ // In theory it could have changed in the interim ... ++ // ++ // The priocntl system call is tricky. ++ // Sometimes it'll validate the priority value argument and ++ // return EINVAL if unhappy. At other times it fails silently. ++ // Readbacks are prudent. ++ ++ if (!ReadBackValidate) return 0; ++ ++ memset(&ReadBack, 0, sizeof(pcparms_t)); ++ ReadBack.pc_cid = PC_CLNULL; ++ rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack); ++ assert(rslt >= 0, "priocntl failed"); ++ Actual = Expected = 0xBAD; ++ assert(ParmInfo.pc_cid == ReadBack.pc_cid, "cid's don't match"); ++ if (ParmInfo.pc_cid == rtLimits.schedPolicy) { ++ Actual = RTPRI(ReadBack)->rt_pri; ++ Expected = RTPRI(ParmInfo)->rt_pri; ++ } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) { ++ Actual = IAPRI(ReadBack)->ia_upri; ++ Expected = IAPRI(ParmInfo)->ia_upri; ++ } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) { ++ Actual = TSPRI(ReadBack)->ts_upri; ++ Expected = TSPRI(ParmInfo)->ts_upri; ++ } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) { ++ Actual = FXPRI(ReadBack)->fx_upri; ++ Expected = FXPRI(ParmInfo)->fx_upri; ++ } ++#endif ++ ++ return 0; ++} ++ ++// Solaris only gives access to 128 real priorities at a time, ++// so we expand Java's ten to fill this range. This would be better ++// if we dynamically adjusted relative priorities. ++// ++// The ThreadPriorityPolicy option allows us to select 2 different ++// priority scales. ++// ++// ThreadPriorityPolicy=0 ++// Since the Solaris' default priority is MaximumPriority, we do not ++// set a priority lower than Max unless a priority lower than ++// NormPriority is requested. ++// ++// ThreadPriorityPolicy=1 ++// This mode causes the priority table to get filled with ++// linear values. NormPriority gets mapped to 50% of the ++// Maximum priority and so on. This will cause VM threads ++// to get unfair treatment against other Solaris processes ++// which do not explicitly alter their thread priorities. ++ ++int os::java_to_os_priority[CriticalPriority + 1] = { ++ -99999, // 0 Entry should never be used ++ ++ 0, // 1 MinPriority ++ 32, // 2 ++ 64, // 3 ++ ++ 96, // 4 ++ 127, // 5 NormPriority ++ 127, // 6 ++ ++ 127, // 7 ++ 127, // 8 ++ 127, // 9 NearMaxPriority ++ ++ 127, // 10 MaxPriority ++ ++ -criticalPrio // 11 CriticalPriority ++}; ++ ++OSReturn os::set_native_priority(Thread* thread, int newpri) { ++ OSThread* osthread = thread->osthread(); ++ ++ // Save requested priority in case the thread hasn't been started ++ osthread->set_native_priority(newpri); ++ ++ // Check for critical priority request ++ bool fxcritical = false; ++ if (newpri == -criticalPrio) { ++ fxcritical = true; ++ newpri = criticalPrio; ++ } ++ ++ assert(newpri >= MinimumPriority && newpri <= MaximumPriority, "bad priority mapping"); ++ if (!UseThreadPriorities) return OS_OK; ++ ++ int status = 0; ++ ++ if (!fxcritical) { ++ // Use thr_setprio only if we have a priority that thr_setprio understands ++ status = thr_setprio(thread->osthread()->thread_id(), newpri); ++ } ++ ++ int lwp_status = ++ set_lwp_class_and_priority(osthread->thread_id(), ++ osthread->lwp_id(), ++ newpri, ++ fxcritical ? fxLimits.schedPolicy : myClass, ++ !fxcritical); ++ if (lwp_status != 0 && fxcritical) { ++ // Try again, this time without changing the scheduling class ++ newpri = java_MaxPriority_to_os_priority; ++ lwp_status = set_lwp_class_and_priority(osthread->thread_id(), ++ osthread->lwp_id(), ++ newpri, myClass, false); ++ } ++ status |= lwp_status; ++ return (status == 0) ? OS_OK : OS_ERR; ++} ++ ++ ++OSReturn os::get_native_priority(const Thread* const thread, ++ int *priority_ptr) { ++ int p; ++ if (!UseThreadPriorities) { ++ *priority_ptr = NormalPriority; ++ return OS_OK; ++ } ++ int status = thr_getprio(thread->osthread()->thread_id(), &p); ++ if (status != 0) { ++ return OS_ERR; ++ } ++ *priority_ptr = p; ++ return OS_OK; ++} ++ ++//////////////////////////////////////////////////////////////////////////////// ++ ++// This does not do anything on Solaris. This is basically a hook for being ++// able to use structured exception handling (thread-local exception filters) on, e.g., Win32. ++void os::os_exception_wrapper(java_call_t f, JavaValue* value, ++ const methodHandle& method, JavaCallArguments* args, ++ JavaThread* thread) { ++ f(value, method, args, thread); ++} ++ ++void report_error(const char* file_name, int line_no, const char* title, ++ const char* format, ...); ++ ++// (Static) wrappers for the liblgrp API ++os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home; ++os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init; ++os::Solaris::lgrp_fini_func_t os::Solaris::_lgrp_fini; ++os::Solaris::lgrp_root_func_t os::Solaris::_lgrp_root; ++os::Solaris::lgrp_children_func_t os::Solaris::_lgrp_children; ++os::Solaris::lgrp_resources_func_t os::Solaris::_lgrp_resources; ++os::Solaris::lgrp_nlgrps_func_t os::Solaris::_lgrp_nlgrps; ++os::Solaris::lgrp_cookie_stale_func_t os::Solaris::_lgrp_cookie_stale; ++os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0; ++ ++static address resolve_symbol_lazy(const char* name) { ++ address addr = (address) dlsym(RTLD_DEFAULT, name); ++ if (addr == NULL) { ++ // RTLD_DEFAULT was not defined on some early versions of 2.5.1 ++ addr = (address) dlsym(RTLD_NEXT, name); ++ } ++ return addr; ++} ++ ++static address resolve_symbol(const char* name) { ++ address addr = resolve_symbol_lazy(name); ++ if (addr == NULL) { ++ fatal("resolve_symbol failed (%s)", dlerror()); ++ } ++ return addr; ++} ++ ++void os::Solaris::libthread_init() { ++ address func = (address)dlsym(RTLD_DEFAULT, "_thr_suspend_allmutators"); ++ ++ lwp_priocntl_init(); ++ ++ // RTLD_DEFAULT was not defined on some early versions of 5.5.1 ++ if (func == NULL) { ++ func = (address) dlsym(RTLD_NEXT, "_thr_suspend_allmutators"); ++ // Guarantee that this VM is running on an new enough OS (5.6 or ++ // later) that it will have a new enough libthread.so. ++ guarantee(func != NULL, "libthread.so is too old."); ++ } ++ ++ int size; ++ void (*handler_info_func)(address *, int *); ++ handler_info_func = CAST_TO_FN_PTR(void (*)(address *, int *), resolve_symbol("thr_sighndlrinfo")); ++ handler_info_func(&handler_start, &size); ++ handler_end = handler_start + size; ++} ++ ++ ++bool os::Solaris::_synchronization_initialized; ++ ++void os::Solaris::synchronization_init() { ++ _synchronization_initialized = true; ++} ++ ++bool os::Solaris::liblgrp_init() { ++ void *handle = dlopen("liblgrp.so.1", RTLD_LAZY); ++ if (handle != NULL) { ++ os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home"))); ++ os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init"))); ++ os::Solaris::set_lgrp_fini(CAST_TO_FN_PTR(lgrp_fini_func_t, dlsym(handle, "lgrp_fini"))); ++ os::Solaris::set_lgrp_root(CAST_TO_FN_PTR(lgrp_root_func_t, dlsym(handle, "lgrp_root"))); ++ os::Solaris::set_lgrp_children(CAST_TO_FN_PTR(lgrp_children_func_t, dlsym(handle, "lgrp_children"))); ++ os::Solaris::set_lgrp_resources(CAST_TO_FN_PTR(lgrp_resources_func_t, dlsym(handle, "lgrp_resources"))); ++ os::Solaris::set_lgrp_nlgrps(CAST_TO_FN_PTR(lgrp_nlgrps_func_t, dlsym(handle, "lgrp_nlgrps"))); ++ os::Solaris::set_lgrp_cookie_stale(CAST_TO_FN_PTR(lgrp_cookie_stale_func_t, ++ dlsym(handle, "lgrp_cookie_stale"))); ++ ++ lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER); ++ set_lgrp_cookie(c); ++ return true; ++ } ++ return false; ++} ++ ++// int pset_getloadavg(psetid_t pset, double loadavg[], int nelem); ++typedef long (*pset_getloadavg_type)(psetid_t pset, double loadavg[], int nelem); ++static pset_getloadavg_type pset_getloadavg_ptr = NULL; ++ ++void init_pset_getloadavg_ptr(void) { ++ pset_getloadavg_ptr = ++ (pset_getloadavg_type)dlsym(RTLD_DEFAULT, "pset_getloadavg"); ++ if (pset_getloadavg_ptr == NULL) { ++ log_warning(os)("pset_getloadavg function not found"); ++ } ++} ++ ++int os::Solaris::_dev_zero_fd = -1; ++ ++// this is called _before_ the global arguments have been parsed ++void os::init(void) { ++ _initial_pid = getpid(); ++ ++ max_hrtime = first_hrtime = gethrtime(); ++ ++ init_random(1234567); ++ ++ int page_size = sysconf(_SC_PAGESIZE); ++ OSInfo::set_vm_page_size(page_size); ++ OSInfo::set_vm_allocation_granularity(page_size); ++ if (os::vm_page_size() <= 0) { ++ fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno)); ++ } ++ _page_sizes.add(os::vm_page_size()); ++ ++ Solaris::initialize_system_info(); ++ ++ int fd = ::open("/dev/zero", O_RDWR); ++ if (fd < 0) { ++ fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno)); ++ } else { ++ Solaris::set_dev_zero_fd(fd); ++ ++ // Close on exec, child won't inherit. ++ fcntl(fd, F_SETFD, FD_CLOEXEC); ++ } ++ ++ clock_tics_per_sec = CLK_TCK; ++ ++ // check if dladdr1() exists; dladdr1 can provide more information than ++ // dladdr for os::dll_address_to_function_name. It comes with SunOS 5.9 ++ // and is available on linker patches for 5.7 and 5.8. ++ // libdl.so must have been loaded, this call is just an entry lookup ++ void * hdl = dlopen("libdl.so", RTLD_NOW); ++ if (hdl) { ++ dladdr1_func = CAST_TO_FN_PTR(dladdr1_func_type, dlsym(hdl, "dladdr1")); ++ } ++ ++ // main_thread points to the thread that created/loaded the JVM. ++ main_thread = thr_self(); ++ ++ // dynamic lookup of functions that may not be available in our lowest ++ // supported Solaris release ++ void * handle = dlopen("libc.so.1", RTLD_LAZY); ++ if (handle != NULL) { ++ Solaris::_pthread_setname_np = // from 11.3 ++ (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np"); ++ } ++ ++ // Shared Posix initialization ++ os::Posix::init(); ++} ++ ++// To install functions for atexit system call ++extern "C" { ++ static void perfMemory_exit_helper() { ++ perfMemory_exit(); ++ } ++} ++ ++// this is called _after_ the global arguments have been parsed ++jint os::init_2(void) { ++ Solaris::libthread_init(); ++ ++ if (UseNUMA) { ++ if (!Solaris::liblgrp_init()) { ++ FLAG_SET_ERGO(UseNUMA, false); ++ } else { ++ size_t lgrp_limit = os::numa_get_groups_num(); ++ int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit, mtInternal); ++ size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit); ++ FREE_C_HEAP_ARRAY(int, lgrp_ids); ++ if (lgrp_num < 2) { ++ // There's only one locality group, disable NUMA ++ UseNUMA = false; ++ } ++ } ++ } ++ ++ // When NUMA requested, not-NUMA-aware allocations default to interleaving. ++ if (UseNUMA && !UseNUMAInterleaving) { ++ FLAG_SET_ERGO_IF_DEFAULT(UseNUMAInterleaving, true); ++ } ++ ++ if (PosixSignals::init() == JNI_ERR) { ++ return JNI_ERR; ++ } ++ ++ // initialize synchronization primitives ++ Solaris::synchronization_init(); ++ DEBUG_ONLY(os::set_mutex_init_done();) ++ ++ if (MaxFDLimit) { ++ // set the number of file descriptors to max. print out error ++ // if getrlimit/setrlimit fails but continue regardless. ++ struct rlimit nbr_files; ++ int status = getrlimit(RLIMIT_NOFILE, &nbr_files); ++ if (status != 0) { ++ log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno)); ++ } else { ++ nbr_files.rlim_cur = nbr_files.rlim_max; ++ status = setrlimit(RLIMIT_NOFILE, &nbr_files); ++ if (status != 0) { ++ log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno)); ++ } ++ } ++ } ++ ++ // Calculate theoretical max. size of Threads to guard gainst ++ // artificial out-of-memory situations, where all available address- ++ // space has been reserved by thread stacks. Default stack size is 1Mb. ++ size_t pre_thread_stack_size = (JavaThread::stack_size_at_create()) ? ++ JavaThread::stack_size_at_create() : (1*K*K); ++ assert(pre_thread_stack_size != 0, "Must have a stack"); ++ // Solaris has a maximum of 4Gb of user programs. Calculate the thread limit when ++ // we should start doing Virtual Memory banging. Currently when the threads will ++ // have used all but 200Mb of space. ++ size_t max_address_space = ((unsigned int)4 * K * K * K) - (200 * K * K); ++ Solaris::_os_thread_limit = max_address_space / pre_thread_stack_size; ++ ++ // at-exit methods are called in the reverse order of their registration. ++ // In Solaris 7 and earlier, atexit functions are called on return from ++ // main or as a result of a call to exit(3C). There can be only 32 of ++ // these functions registered and atexit() does not set errno. In Solaris ++ // 8 and later, there is no limit to the number of functions registered ++ // and atexit() sets errno. In addition, in Solaris 8 and later, atexit ++ // functions are called upon dlclose(3DL) in addition to return from main ++ // and exit(3C). ++ ++ if (PerfAllowAtExitRegistration) { ++ // only register atexit functions if PerfAllowAtExitRegistration is set. ++ // atexit functions can be delayed until process exit time, which ++ // can be problematic for embedded VM situations. Embedded VMs should ++ // call DestroyJavaVM() to assure that VM resources are released. ++ ++ // note: perfMemory_exit_helper atexit function may be removed in ++ // the future if the appropriate cleanup code can be added to the ++ // VM_Exit VMOperation's doit method. ++ if (atexit(perfMemory_exit_helper) != 0) { ++ warning("os::init2 atexit(perfMemory_exit_helper) failed"); ++ } ++ } ++ ++ // Init pset_loadavg function pointer ++ init_pset_getloadavg_ptr(); ++ ++ // Shared Posix initialization ++ os::Posix::init_2(); ++ ++ return JNI_OK; ++} ++ ++// This code originates from JDK's sysOpen and open64_w ++// from src/solaris/hpi/src/system_md.c ++ ++int os::open(const char *path, int oflag, int mode) { ++ if (strlen(path) > MAX_PATH - 1) { ++ errno = ENAMETOOLONG; ++ return -1; ++ } ++ int fd; ++ ++ fd = ::open64(path, oflag, mode); ++ if (fd == -1) return -1; ++ ++ // If the open succeeded, the file might still be a directory ++ { ++ struct stat64 buf64; ++ int ret = ::fstat64(fd, &buf64); ++ int st_mode = buf64.st_mode; ++ ++ if (ret != -1) { ++ if ((st_mode & S_IFMT) == S_IFDIR) { ++ errno = EISDIR; ++ ::close(fd); ++ return -1; ++ } ++ } else { ++ ::close(fd); ++ return -1; ++ } ++ } ++ ++ // All file descriptors that are opened in the JVM and not ++ // specifically destined for a subprocess should have the ++ // close-on-exec flag set. If we don't set it, then careless 3rd ++ // party native code might fork and exec without closing all ++ // appropriate file descriptors (e.g. as we do in closeDescriptors in ++ // UNIXProcess.c), and this in turn might: ++ // ++ // - cause end-of-file to fail to be detected on some file ++ // descriptors, resulting in mysterious hangs, or ++ // ++ // - might cause an fopen in the subprocess to fail on a system ++ // suffering from bug 1085341. ++ // ++ // (Yes, the default setting of the close-on-exec flag is a Unix ++ // design flaw) ++ // ++ // See: ++ // 1085341: 32-bit stdio routines should support file descriptors >255 ++ // 4843136: (process) pipe file descriptor from Runtime.exec not being closed ++ // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9 ++ // ++#ifdef FD_CLOEXEC ++ { ++ int flags = ::fcntl(fd, F_GETFD); ++ if (flags != -1) { ++ ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC); ++ } ++ } ++#endif ++ ++ return fd; ++} ++ ++// create binary file, rewriting existing file if required ++int os::create_binary_file(const char* path, bool rewrite_existing) { ++ int oflags = O_WRONLY | O_CREAT; ++ if (!rewrite_existing) { ++ oflags |= O_EXCL; ++ } ++ return ::open64(path, oflags, S_IREAD | S_IWRITE); ++} ++ ++// return current position of file pointer ++jlong os::current_file_offset(int fd) { ++ return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR); ++} ++ ++// move file pointer to the specified offset ++jlong os::seek_to_file_offset(int fd, jlong offset) { ++ return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET); ++} ++ ++// Map a block of memory. ++char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset, ++ char *addr, size_t bytes, bool read_only, ++ bool allow_exec) { ++ int prot; ++ int flags; ++ ++ if (read_only) { ++ prot = PROT_READ; ++ flags = MAP_SHARED; ++ } else { ++ prot = PROT_READ | PROT_WRITE; ++ flags = MAP_PRIVATE; ++ } ++ ++ if (allow_exec) { ++ prot |= PROT_EXEC; ++ } ++ ++ if (addr != NULL) { ++ flags |= MAP_FIXED; ++ } ++ ++ char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags, ++ fd, file_offset); ++ if (mapped_address == MAP_FAILED) { ++ return NULL; ++ } ++ return mapped_address; ++} ++ ++ ++// Remap a block of memory. ++char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset, ++ char *addr, size_t bytes, bool read_only, ++ bool allow_exec) { ++ // same as map_memory() on this OS ++ return os::map_memory(fd, file_name, file_offset, addr, bytes, read_only, ++ allow_exec); ++} ++ ++ ++// Unmap a block of memory. ++bool os::pd_unmap_memory(char* addr, size_t bytes) { ++ return munmap(addr, bytes) == 0; ++} ++ ++const intptr_t thr_time_off = (intptr_t)(&((prusage_t *)(NULL))->pr_utime); ++const intptr_t thr_time_size = (intptr_t)(&((prusage_t *)(NULL))->pr_ttime) - ++ (intptr_t)(&((prusage_t *)(NULL))->pr_utime); ++ ++ ++// JVMTI & JVM monitoring and management support ++// The thread_cpu_time() and current_thread_cpu_time() are only ++// supported if is_thread_cpu_time_supported() returns true. ++// They are not supported on Solaris T1. ++ ++// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool) ++// are used by JVM M&M and JVMTI to get user+sys or user CPU time ++// of a thread. ++// ++// current_thread_cpu_time() and thread_cpu_time(Thread *) ++// returns the fast estimate available on the platform. ++ ++// hrtime_t gethrvtime() return value includes ++// user time but does not include system time ++jlong os::current_thread_cpu_time() { ++ return (jlong) gethrvtime(); ++} ++ ++jlong os::thread_cpu_time(Thread *thread) { ++ // return user level CPU time only to be consistent with ++ // what current_thread_cpu_time returns. ++ // thread_cpu_time_info() must be changed if this changes ++ return os::thread_cpu_time(thread, false /* user time only */); ++} ++ ++jlong os::current_thread_cpu_time(bool user_sys_cpu_time) { ++ if (user_sys_cpu_time) { ++ return os::thread_cpu_time(Thread::current(), user_sys_cpu_time); ++ } else { ++ return os::current_thread_cpu_time(); ++ } ++} ++ ++jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) { ++ char proc_name[64]; ++ int count; ++ prusage_t prusage; ++ jlong lwp_time; ++ int fd; ++ ++ sprintf(proc_name, "/proc/%d/lwp/%d/lwpusage", ++ getpid(), ++ thread->osthread()->lwp_id()); ++ fd = ::open(proc_name, O_RDONLY); ++ if (fd == -1) return -1; ++ ++ do { ++ count = ::pread(fd, ++ (void *)&prusage.pr_utime, ++ thr_time_size, ++ thr_time_off); ++ } while (count < 0 && errno == EINTR); ++ ::close(fd); ++ if (count < 0) return -1; ++ ++ if (user_sys_cpu_time) { ++ // user + system CPU time ++ lwp_time = (((jlong)prusage.pr_stime.tv_sec + ++ (jlong)prusage.pr_utime.tv_sec) * (jlong)1000000000) + ++ (jlong)prusage.pr_stime.tv_nsec + ++ (jlong)prusage.pr_utime.tv_nsec; ++ } else { ++ // user level CPU time only ++ lwp_time = ((jlong)prusage.pr_utime.tv_sec * (jlong)1000000000) + ++ (jlong)prusage.pr_utime.tv_nsec; ++ } ++ ++ return (lwp_time); ++} ++ ++void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { ++ info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits ++ info_ptr->may_skip_backward = false; // elapsed time not wall time ++ info_ptr->may_skip_forward = false; // elapsed time not wall time ++ info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned ++} ++ ++void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) { ++ info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits ++ info_ptr->may_skip_backward = false; // elapsed time not wall time ++ info_ptr->may_skip_forward = false; // elapsed time not wall time ++ info_ptr->kind = JVMTI_TIMER_USER_CPU; // only user time is returned ++} ++ ++bool os::is_thread_cpu_time_supported() { ++ return true; ++} ++ ++// System loadavg support. Returns -1 if load average cannot be obtained. ++// Return the load average for our processor set if the primitive exists ++// (Solaris 9 and later). Otherwise just return system wide loadavg. ++int os::loadavg(double loadavg[], int nelem) { ++ if (pset_getloadavg_ptr != NULL) { ++ return (*pset_getloadavg_ptr)(PS_MYID, loadavg, nelem); ++ } else { ++ return ::getloadavg(loadavg, nelem); ++ } ++} ++ ++//--------------------------------------------------------------------------------- ++ ++bool os::find(address addr, outputStream* st) { ++ Dl_info dlinfo; ++ memset(&dlinfo, 0, sizeof(dlinfo)); ++ if (dladdr(addr, &dlinfo) != 0) { ++ st->print(PTR_FORMAT ": ", p2i(addr)); ++ if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) { ++ st->print("%s+" PTR_FORMAT, dlinfo.dli_sname, ++ p2i(addr) - p2i(dlinfo.dli_saddr)); ++ } else if (dlinfo.dli_fbase != NULL) { ++ st->print("", p2i(addr) - p2i(dlinfo.dli_fbase)); ++ } else { ++ st->print(""); ++ } ++ if (dlinfo.dli_fname != NULL) { ++ st->print(" in %s", dlinfo.dli_fname); ++ } ++ if (dlinfo.dli_fbase != NULL) { ++ st->print(" at " PTR_FORMAT, p2i(dlinfo.dli_fbase)); ++ } ++ st->cr(); ++ ++ if (Verbose) { ++ // decode some bytes around the PC ++ address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size()); ++ address end = clamp_address_in_page(addr+40, addr, os::vm_page_size()); ++ address lowest = (address) dlinfo.dli_sname; ++ if (!lowest) lowest = (address) dlinfo.dli_fbase; ++ if (begin < lowest) begin = lowest; ++ Dl_info dlinfo2; ++ if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr ++ && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) { ++ end = (address) dlinfo2.dli_saddr; ++ } ++ Disassembler::decode(begin, end, st); ++ } ++ return true; ++ } ++ return false; ++} ++ ++// Following function has been added to support HotSparc's libjvm.so running ++// under Solaris production JDK 1.2.2 / 1.3.0. These came from ++// src/solaris/hpi/native_threads in the EVM codebase. ++// ++// NOTE: This is no longer needed in the 1.3.1 and 1.4 production release ++// libraries and should thus be removed. We will leave it behind for a while ++// until we no longer want to able to run on top of 1.3.0 Solaris production ++// JDK. See 4341971. ++ ++#define STACK_SLACK 0x800 ++ ++extern "C" { ++ intptr_t sysThreadAvailableStackWithSlack() { ++ stack_t st; ++ intptr_t retval, stack_top; ++ retval = thr_stksegment(&st); ++ assert(retval == 0, "incorrect return value from thr_stksegment"); ++ assert((address)&st < (address)st.ss_sp, "Invalid stack base returned"); ++ assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned"); ++ stack_top=(intptr_t)st.ss_sp-st.ss_size; ++ return ((intptr_t)&stack_top - stack_top - STACK_SLACK); ++ } ++} ++ ++// ObjectMonitor park-unpark infrastructure ... ++// ++// We implement Solaris and Linux PlatformEvents with the ++// obvious condvar-mutex-flag triple. ++// Another alternative that works quite well is pipes: ++// Each PlatformEvent consists of a pipe-pair. ++// The thread associated with the PlatformEvent ++// calls park(), which reads from the input end of the pipe. ++// Unpark() writes into the other end of the pipe. ++// The write-side of the pipe must be set NDELAY. ++// Unfortunately pipes consume a large # of handles. ++// Native solaris lwp_park() and lwp_unpark() work nicely, too. ++// Using pipes for the 1st few threads might be workable, however. ++// ++// park() is permitted to return spuriously. ++// Callers of park() should wrap the call to park() in ++// an appropriate loop. A litmus test for the correct ++// usage of park is the following: if park() were modified ++// to immediately return 0 your code should still work, ++// albeit degenerating to a spin loop. ++// ++// In a sense, park()-unpark() just provides more polite spinning ++// and polling with the key difference over naive spinning being ++// that a parked thread needs to be explicitly unparked() in order ++// to wake up and to poll the underlying condition. ++// ++// Assumption: ++// Only one parker can exist on an event, which is why we allocate ++// them per-thread. Multiple unparkers can coexist. ++// ++// _event transitions in park() ++// -1 => -1 : illegal ++// 1 => 0 : pass - return immediately ++// 0 => -1 : block; then set _event to 0 before returning ++// ++// _event transitions in unpark() ++// 0 => 1 : just return ++// 1 => 1 : just return ++// -1 => either 0 or 1; must signal target thread ++// That is, we can safely transition _event from -1 to either ++// 0 or 1. ++// ++// _event serves as a restricted-range semaphore. ++// -1 : thread is blocked, i.e. there is a waiter ++// 0 : neutral: thread is running or ready, ++// could have been signaled after a wait started ++// 1 : signaled - thread is running or ready ++// ++// Another possible encoding of _event would be with ++// explicit "PARKED" == 01b and "SIGNALED" == 10b bits. ++// ++// TODO-FIXME: add DTRACE probes for: ++// 1. Tx parks ++// 2. Ty unparks Tx ++// 3. Tx resumes from park ++ ++// JSR166 ++// ------------------------------------------------------- ++ ++// The solaris and linux implementations of park/unpark are fairly ++// conservative for now, but can be improved. They currently use a ++// mutex/condvar pair, plus _counter. ++// Park decrements _counter if > 0, else does a condvar wait. Unpark ++// sets count to 1 and signals condvar. Only one thread ever waits ++// on the condvar. Contention seen when trying to park implies that someone ++// is unparking you, so don't wait. And spurious returns are fine, so there ++// is no need to track notifications. ++ ++// Get the default path to the core file ++// Returns the length of the string ++int os::get_core_path(char* buffer, size_t bufferSize) { ++ const char* p = get_current_directory(buffer, bufferSize); ++ ++ if (p == NULL) { ++ assert(p != NULL, "failed to get current directory"); ++ return 0; ++ } ++ ++ jio_snprintf(buffer, bufferSize, "%s/core or core.%d", ++ p, current_process_id()); ++ ++ return strlen(buffer); ++} ++ ++bool os::supports_map_sync() { ++ return false; ++} ++ ++#ifndef PRODUCT ++void TestReserveMemorySpecial_test() { ++ // No tests available for this platform ++} ++#endif ++ ++bool os::start_debugging(char *buf, int buflen) { ++ int len = (int)strlen(buf); ++ char *p = &buf[len]; ++ ++ jio_snprintf(p, buflen-len, ++ "\n\n" ++ "Do you want to debug the problem?\n\n" ++ "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n" ++ "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n" ++ "Otherwise, press RETURN to abort...", ++ os::current_process_id(), os::current_thread_id()); ++ ++ bool yes = os::message_box("Unexpected Error", buf); ++ ++ if (yes) { ++ // yes, user asked VM to launch debugger ++ jio_snprintf(buf, sizeof(buf), "dbx - %d", os::current_process_id()); ++ ++ os::fork_and_exec(buf); ++ yes = false; ++ } ++ return yes; ++} ++ ++void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} ++ ++#if INCLUDE_JFR ++ ++void os::jfr_report_memory_info() {} ++ ++#endif // INCLUDE_JFR ++ ++bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { ++ ++ if (ebuf && ebuflen > 0) { ++ ebuf[0] = '\0'; ++ ebuf[ebuflen - 1] = '\0'; ++ } ++ ++ bool res = (0 == ::dlclose(libhandle)); ++ if (!res) { ++ // error analysis when dlopen fails ++ const char* error_report = ::dlerror(); ++ if (error_report == nullptr) { ++ error_report = "dlerror returned no error description"; ++ } ++ if (ebuf != nullptr && ebuflen > 0) { ++ snprintf(ebuf, ebuflen - 1, "%s", error_report); ++ } ++ } ++ ++ return res; ++} // end: os::pd_dll_unload() +diff -urN /tmp/a/os_solaris.hpp b/src/hotspot/os/solaris/os_solaris.hpp +--- /tmp/a/os_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/os_solaris.hpp 2024-10-15 14:59:36.867931458 +0100 +@@ -0,0 +1,198 @@ ++/* ++ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_SOLARIS_OS_SOLARIS_HPP ++#define OS_SOLARIS_OS_SOLARIS_HPP ++ ++#include "runtime/os.hpp" ++ ++// Solaris_OS defines the interface to Solaris operating systems ++ ++// see thr_setprio(3T) for the basis of these numbers ++#define MinimumPriority 0 ++#define NormalPriority 64 ++#define MaximumPriority 127 ++ ++// FX/60 is critical thread class/priority on T4 ++#define FXCriticalPriority 60 ++ ++class os::Solaris { ++ friend class os; ++ ++ private: ++ ++ static bool _synchronization_initialized; ++ ++ typedef uintptr_t lgrp_cookie_t; ++ typedef id_t lgrp_id_t; ++ typedef int lgrp_rsrc_t; ++ typedef enum lgrp_view { ++ LGRP_VIEW_CALLER, // what's available to the caller ++ LGRP_VIEW_OS // what's available to operating system ++ } lgrp_view_t; ++ ++ typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id); ++ typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view); ++ typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie); ++ typedef lgrp_id_t (*lgrp_root_func_t)(lgrp_cookie_t cookie); ++ typedef int (*lgrp_children_func_t)(lgrp_cookie_t cookie, lgrp_id_t parent, ++ lgrp_id_t *lgrp_array, uint_t lgrp_array_size); ++ typedef int (*lgrp_resources_func_t)(lgrp_cookie_t cookie, lgrp_id_t lgrp, ++ lgrp_id_t *lgrp_array, uint_t lgrp_array_size, ++ lgrp_rsrc_t type); ++ typedef int (*lgrp_nlgrps_func_t)(lgrp_cookie_t cookie); ++ typedef int (*lgrp_cookie_stale_func_t)(lgrp_cookie_t cookie); ++ ++ static lgrp_home_func_t _lgrp_home; ++ static lgrp_init_func_t _lgrp_init; ++ static lgrp_fini_func_t _lgrp_fini; ++ static lgrp_root_func_t _lgrp_root; ++ static lgrp_children_func_t _lgrp_children; ++ static lgrp_resources_func_t _lgrp_resources; ++ static lgrp_nlgrps_func_t _lgrp_nlgrps; ++ static lgrp_cookie_stale_func_t _lgrp_cookie_stale; ++ static lgrp_cookie_t _lgrp_cookie; ++ ++ // Large Page Support ++ static bool is_valid_page_size(size_t bytes); ++ static size_t page_size_for_alignment(size_t alignment); ++ static bool setup_large_pages(caddr_t start, size_t bytes, size_t align); ++ ++ typedef int (*pthread_setname_np_func_t)(pthread_t, const char*); ++ static pthread_setname_np_func_t _pthread_setname_np; ++ ++ public: ++ // Large Page Support--ISM. ++ static bool largepage_range(char* addr, size_t size); ++ ++ static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo ++ ++ static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect); ++ static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread, ++ const ucontext_t* uc); ++ ++ static intptr_t* ucontext_get_sp(const ucontext_t* uc); ++ // ucontext_get_fp() is only used by Solaris X86 (see note below) ++ static intptr_t* ucontext_get_fp(const ucontext_t* uc); ++ ++ static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr); ++ ++ static void init_thread_fpu_state(void); ++ ++ protected: ++ // Solaris-specific interface goes here ++ static julong available_memory(); ++ static julong free_memory(); ++ static julong physical_memory() { return _physical_memory; } ++ static julong _physical_memory; ++ static void initialize_system_info(); ++ static int _dev_zero_fd; ++ static int get_dev_zero_fd() { return _dev_zero_fd; } ++ static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; } ++ static int commit_memory_impl(char* addr, size_t bytes, bool exec); ++ static int commit_memory_impl(char* addr, size_t bytes, ++ size_t alignment_hint, bool exec); ++ static char* mmap_chunk(char *addr, size_t size, int flags, int prot); ++ static char* anon_mmap(char* requested_addr, size_t bytes); ++ static bool mpss_sanity_check(bool warn, size_t * page_size); ++ ++ // Workaround for 4352906. thr_stksegment sometimes returns ++ // a bad value for the primordial thread's stack base when ++ // it is called more than one time. ++ // Workaround is to cache the initial value to avoid further ++ // calls to thr_stksegment. ++ // It appears that someone (Hotspot?) is trashing the user's ++ // proc_t structure (note that this is a system struct). ++ static address _main_stack_base; ++ ++ static void print_distro_info(outputStream* st); ++ static void print_libversion_info(outputStream* st); ++ ++ public: ++ static void libthread_init(); ++ static void synchronization_init(); ++ static bool liblgrp_init(); ++ ++ // alignment with os_posix means we use pthreads ++ static int mutex_lock(pthread_mutex_t *mx) { return pthread_mutex_lock(mx); } ++ static int mutex_trylock(pthread_mutex_t *mx) { return pthread_mutex_trylock(mx); } ++ static int mutex_unlock(pthread_mutex_t *mx) { return pthread_mutex_unlock(mx); } ++ static int mutex_init(pthread_mutex_t *mx) { return pthread_mutex_init(mx, NULL); } ++ static int mutex_destroy(pthread_mutex_t *mx) { return pthread_mutex_destroy(mx); } ++ ++ static int cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mx, timestruc_t *abst) { return pthread_cond_timedwait(cv, mx, abst); } ++ static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mx) { return pthread_cond_wait(cv, mx); } ++ static int cond_signal(pthread_cond_t *cv) { return pthread_cond_signal(cv); } ++ static int cond_broadcast(pthread_cond_t *cv) { return pthread_cond_broadcast(cv); } ++ static int cond_init(pthread_cond_t *cv) { return pthread_cond_init(cv, NULL); } ++ static int cond_destroy(pthread_cond_t *cv) { return pthread_cond_destroy(cv); } ++ ++ static bool synchronization_initialized() { return _synchronization_initialized; } ++ ++ static void set_lgrp_home(lgrp_home_func_t func) { _lgrp_home = func; } ++ static void set_lgrp_init(lgrp_init_func_t func) { _lgrp_init = func; } ++ static void set_lgrp_fini(lgrp_fini_func_t func) { _lgrp_fini = func; } ++ static void set_lgrp_root(lgrp_root_func_t func) { _lgrp_root = func; } ++ static void set_lgrp_children(lgrp_children_func_t func) { _lgrp_children = func; } ++ static void set_lgrp_resources(lgrp_resources_func_t func) { _lgrp_resources = func; } ++ static void set_lgrp_nlgrps(lgrp_nlgrps_func_t func) { _lgrp_nlgrps = func; } ++ static void set_lgrp_cookie_stale(lgrp_cookie_stale_func_t func) { _lgrp_cookie_stale = func; } ++ static void set_lgrp_cookie(lgrp_cookie_t cookie) { _lgrp_cookie = cookie; } ++ ++ static id_t lgrp_home(idtype_t type, id_t id) { return _lgrp_home != NULL ? _lgrp_home(type, id) : -1; } ++ static lgrp_cookie_t lgrp_init(lgrp_view_t view) { return _lgrp_init != NULL ? _lgrp_init(view) : 0; } ++ static int lgrp_fini(lgrp_cookie_t cookie) { return _lgrp_fini != NULL ? _lgrp_fini(cookie) : -1; } ++ static lgrp_id_t lgrp_root(lgrp_cookie_t cookie) { return _lgrp_root != NULL ? _lgrp_root(cookie) : -1; } ++ static int lgrp_children(lgrp_cookie_t cookie, lgrp_id_t parent, ++ lgrp_id_t *lgrp_array, uint_t lgrp_array_size) { ++ return _lgrp_children != NULL ? _lgrp_children(cookie, parent, lgrp_array, lgrp_array_size) : -1; ++ } ++ static int lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp, ++ lgrp_id_t *lgrp_array, uint_t lgrp_array_size, ++ lgrp_rsrc_t type) { ++ return _lgrp_resources != NULL ? _lgrp_resources(cookie, lgrp, lgrp_array, lgrp_array_size, type) : -1; ++ } ++ ++ static int lgrp_nlgrps(lgrp_cookie_t cookie) { return _lgrp_nlgrps != NULL ? _lgrp_nlgrps(cookie) : -1; } ++ static int lgrp_cookie_stale(lgrp_cookie_t cookie) { ++ return _lgrp_cookie_stale != NULL ? _lgrp_cookie_stale(cookie) : -1; ++ } ++ static lgrp_cookie_t lgrp_cookie() { return _lgrp_cookie; } ++ ++ static sigset_t* unblocked_signals(); ++ static sigset_t* vm_signals(); ++ ++ // %%% Following should be promoted to os.hpp: ++ // Trace number of created threads ++ static jint _os_thread_limit; ++ static volatile jint _os_thread_count; ++ ++ static void correct_stack_boundaries_for_primordial_thread(Thread* thr); ++ ++ // Stack repair handling ++ ++ // none present ++ ++}; ++#endif // OS_SOLARIS_OS_SOLARIS_HPP +diff -urN /tmp/a/os_solaris.inline.hpp b/src/hotspot/os/solaris/os_solaris.inline.hpp +--- /tmp/a/os_solaris.inline.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/os_solaris.inline.hpp 2024-10-15 14:59:36.868029490 +0100 +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_SOLARIS_OS_SOLARIS_INLINE_HPP ++#define OS_SOLARIS_OS_SOLARIS_INLINE_HPP ++ ++#include "os_solaris.hpp" ++ ++#include "runtime/os.hpp" ++#include "os_posix.inline.hpp" ++ ++// System includes ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++inline bool os::zero_page_read_protected() { ++ return true; ++} ++ ++inline bool os::uses_stack_guard_pages() { ++ return true; ++} ++ ++inline bool os::must_commit_stack_guard_pages() { ++ assert(uses_stack_guard_pages(), "sanity check"); ++ int r = thr_main() ; ++ guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ; ++ return r; ++} ++ ++ ++// Bang the shadow pages if they need to be touched to be mapped. ++inline void os::map_stack_shadow_pages(address sp) { ++} ++ ++// Trim-native support, stubbed out for now, may be enabled later ++inline bool os::can_trim_native_heap() { return false; } ++inline bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } ++ ++////////////////////////////////////////////////////////////////////////////// ++//////////////////////////////////////////////////////////////////////////////// ++ ++inline bool os::numa_has_group_homing() { return true; } ++ ++#endif // OS_SOLARIS_OS_SOLARIS_INLINE_HPP +diff -urN /tmp/a/vmStructs_solaris.hpp b/src/hotspot/os/solaris/vmStructs_solaris.hpp +--- /tmp/a/vmStructs_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 ++++ b/src/hotspot/os/solaris/vmStructs_solaris.hpp 2024-10-15 14:59:36.868118211 +0100 +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. 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. ++ * ++ */ ++ ++#ifndef OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP ++#define OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP ++ ++// These are the OS-specific fields, types and integer ++// constants required by the Serviceability Agent. This file is ++// referenced by vmStructs.cpp. ++ ++#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \ ++ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) ++ ++#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \ ++ declare_unsigned_integer_type(OSThread::thread_id_t) ++ ++#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) ++ ++#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) ++ ++#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function) ++ ++#endif // OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP diff --git a/build/openjdk21/patches/series b/build/openjdk21/patches/series index 371017efc7..41ce1a1d98 100644 --- a/build/openjdk21/patches/series +++ b/build/openjdk21/patches/series @@ -1,5 +1,6 @@ java-solaris-sparc.patch -R -illumos-cpu_microcode_revision.patch +restore_os_solaris.patch +restore_os_cpu_solaris_x86.patch illumos-jline.patch illumos-pollerprovider.patch illumos-port-2.patch @@ -7,11 +8,9 @@ illumos-port-3.patch illumos-port-5.patch illumos-port-6.patch illumos-port-7.patch -illumos-port-9.patch illumos-port-10.patch illumos-port-11.patch illumos-port-12.patch -illumos-port-15.patch illumos-port-16.patch illumos-port-17.patch illumos-port-18.patch @@ -24,7 +23,6 @@ illumos-port-24.patch illumos-port-25.patch illumos-port-26.patch illumos-port-27.patch -illumos-safefetch.patch illumos-signal-1.patch patch-make_autoconf_flags-cflags.m4 -p0 patch-make_autoconf_jdk-options.m4 -p0 @@ -32,8 +30,6 @@ patch-make_GenerateLinkOptData.gmk -p0 patch-make_launcher_LauncherCommon.gmk -p0 patch-make_lib_LibCommon.gmk -p0 patch-src_hotspot_share_gc_g1_g1Analytics.cpp -p0 -patch-src_java.desktop_share_native_libsplashscreen_libpng_pngpriv.h -p0 -tribblix-demangle1.patch -p0 tribblix-flags-cflags.patch -p0 tribblix-flags-ldflags.patch -p0 tribblix-flags-ldflags3.patch -p0 diff --git a/build/openjdk21/patches/tribblix-demangle1.patch b/build/openjdk21/patches/tribblix-demangle1.patch deleted file mode 100644 index eb7e1dfb18..0000000000 --- a/build/openjdk21/patches/tribblix-demangle1.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- src/hotspot/os/solaris/decoder_solaris.cpp.orig Tue Apr 14 19:31:07 2020 -+++ src/hotspot/os/solaris/decoder_solaris.cpp Tue Apr 14 20:07:38 2020 -@@ -22,11 +22,24 @@ - * - */ - -+#include "jvm.h" - #include "utilities/decoder_elf.hpp" - --#include -+#include - - bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { -- return !cplus_demangle(symbol, buf, (size_t)buflen); -+ int status; -+ char* result; -+ size_t size = (size_t)buflen; -+ // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small, -+ // __cxa_demangle will call system "realloc" for additional memory, which -+ // may use different malloc/realloc mechanism that allocates 'buf'. -+ if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) { -+ jio_snprintf(buf, buflen, "%s", result); -+ // call c library's free -+ ::free(result); -+ return true; -+ } -+ return false; - } - From 075e280fab93182cf75c9c43f2897f9e68017cc6 Mon Sep 17 00:00:00 2001 From: Dominik Hassler Date: Sat, 16 Nov 2024 14:17:22 +0000 Subject: [PATCH 4/4] openjdk8: update to 1.8.432-06 --- build/openjdk8/build.sh | 5 ++- ...mmon_autoconf_generated-configure.sh.patch | 43 ++++++++----------- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/build/openjdk8/build.sh b/build/openjdk8/build.sh index ca890f2230..914869a363 100755 --- a/build/openjdk8/build.sh +++ b/build/openjdk8/build.sh @@ -18,8 +18,8 @@ PROG=openjdk VER=1.8 -UPDATE=422 -BUILD=05 +UPDATE=432 +BUILD=06 PKG=openjdk ##IGNORE## - filled in later SUMMARY="tbc"; DESC="tbc" @@ -104,6 +104,7 @@ MAKE_ARGS=" FULL_DEBUG_SYMBOLS=0 ENABLE_FULL_DEBUG_SYMBOLS=0 NO_DOCS=1 + X_CFLAGS=-I$OOCEPREFIX/include " export PATH=$GNUBIN:$PATH diff --git a/build/openjdk8/patches/patch-common_autoconf_generated-configure.sh.patch b/build/openjdk8/patches/patch-common_autoconf_generated-configure.sh.patch index 8f218a21fc..deecfc6575 100644 --- a/build/openjdk8/patches/patch-common_autoconf_generated-configure.sh.patch +++ b/build/openjdk8/patches/patch-common_autoconf_generated-configure.sh.patch @@ -1,7 +1,7 @@ -diff -wpruN --no-dereference '--exclude=*.orig' a~/common/autoconf/generated-configure.sh a/common/autoconf/generated-configure.sh +diff -wpruN '--exclude=*.orig' a~/common/autoconf/generated-configure.sh a/common/autoconf/generated-configure.sh --- a~/common/autoconf/generated-configure.sh 1970-01-01 00:00:00 +++ a/common/autoconf/generated-configure.sh 1970-01-01 00:00:00 -@@ -4183,7 +4183,7 @@ VALID_TOOLCHAINS_all="gcc clang solstudi +@@ -4187,7 +4187,7 @@ VALID_TOOLCHAINS_all="gcc clang solstudi # These toolchains are valid on different platforms VALID_TOOLCHAINS_linux="gcc clang" @@ -10,15 +10,7 @@ diff -wpruN --no-dereference '--exclude=*.orig' a~/common/autoconf/generated-con VALID_TOOLCHAINS_macosx="gcc clang" VALID_TOOLCHAINS_aix="xlc" VALID_TOOLCHAINS_windows="microsoft" -@@ -25617,6 +25617,7 @@ $as_echo_n "checking flags for boot jdk - JVM_MAX_HEAP=1600M - STACK_SIZE=1536 - fi -+ JVM_MAX_HEAP=800M - - $ECHO "Check if jvm arg is ok: -Xmx$JVM_MAX_HEAP" >&5 - $ECHO "Command: $JAVA -Xmx$JVM_MAX_HEAP -version" >&5 -@@ -42432,6 +42433,14 @@ $as_echo "$ac_cv_c_bigendian" >&6; } +@@ -42442,6 +42442,14 @@ $as_echo "$ac_cv_c_bigendian" >&6; } SET_SHARED_LIBRARY_ORIGIN="$SET_EXECUTABLE_ORIGIN" SET_SHARED_LIBRARY_NAME='-Xlinker -install_name -Xlinker @rpath/$1' SET_SHARED_LIBRARY_MAPFILE='' @@ -33,7 +25,7 @@ diff -wpruN --no-dereference '--exclude=*.orig' a~/common/autoconf/generated-con else # Default works for linux, might work on other platforms as well. SHARED_LIBRARY_FLAGS='-shared' -@@ -42500,11 +42509,6 @@ $as_echo "$ac_cv_c_bigendian" >&6; } +@@ -42510,11 +42518,6 @@ $as_echo "$ac_cv_c_bigendian" >&6; } @@ -45,7 +37,7 @@ diff -wpruN --no-dereference '--exclude=*.orig' a~/common/autoconf/generated-con # The (cross) compiler is now configured, we can now test capabilities # of the target platform. -@@ -42603,6 +42607,11 @@ $as_echo "$ac_cv_c_bigendian" >&6; } +@@ -42613,6 +42616,11 @@ $as_echo "$ac_cv_c_bigendian" >&6; } C_O_FLAG_HI="-Os" C_O_FLAG_NORM="-Os" C_O_FLAG_NONE="" @@ -57,20 +49,25 @@ diff -wpruN --no-dereference '--exclude=*.orig' a~/common/autoconf/generated-con else C_O_FLAG_HIGHEST="-O3" C_O_FLAG_HI="-O3" -@@ -42661,9 +42670,9 @@ $as_echo "$ac_cv_c_bigendian" >&6; } +@@ -42671,12 +42679,12 @@ $as_echo "$ac_cv_c_bigendian" >&6; } CFLAGS_JDK="${CFLAGS_JDK} -qchars=signed -q64 -qfullpath -qsaveopt" CXXFLAGS_JDK="${CXXFLAGS_JDK} -qchars=signed -q64 -qfullpath -qsaveopt" elif test "x$TOOLCHAIN_TYPE" = xgcc; then -- LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS -fstack-protector" -- LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS -fstack-protector" +- LEGACY_HOST_CFLAGS="$LEGACY_HOST_CFLAGS -fstack-protector" +- LEGACY_TARGET_CFLAGS="$LEGACY_TARGET_CFLAGS -fstack-protector" +- LEGACY_HOST_CXXFLAGS="$LEGACY_HOST_CXXFLAGS -fstack-protector" +- LEGACY_TARGET_CXXFLAGS="$LEGACY_TARGET_CXXFLAGS -fstack-protector" - if test "x$OPENJDK_TARGET_OS" != xmacosx; then -+ #LEGACY_EXTRA_CFLAGS="$LEGACY_EXTRA_CFLAGS -fstack-protector" -+ #LEGACY_EXTRA_CXXFLAGS="$LEGACY_EXTRA_CXXFLAGS -fstack-protector" ++ #LEGACY_HOST_CFLAGS="$LEGACY_HOST_CFLAGS -fstack-protector" ++ #LEGACY_TARGET_CFLAGS="$LEGACY_TARGET_CFLAGS -fstack-protector" ++ #LEGACY_HOST_CXXFLAGS="$LEGACY_HOST_CXXFLAGS -fstack-protector" ++ #LEGACY_TARGET_CXXFLAGS="$LEGACY_TARGET_CXXFLAGS -fstack-protector" + if test "x$OPENJDK_TARGET_OS" != xsolaris; then LDFLAGS_JDK="$LDFLAGS_JDK -Wl,-z,relro" - LEGACY_EXTRA_LDFLAGS="$LEGACY_EXTRA_LDFLAGS -Wl,-z,relro" + LEGACY_HOST_LDFLAGS="$LEGACY_HOST_LDFLAGS -Wl,-z,relro" + LEGACY_TARGET_LDFLAGS="$LEGACY_TARGET_LDFLAGS -Wl,-z,relro" fi -@@ -42788,7 +42797,7 @@ fi +@@ -42809,7 +42817,7 @@ fi if test "x$TOOLCHAIN_TYPE" = xgcc; then # these options are used for both C and C++ compiles CCXXFLAGS_JDK="$CCXXFLAGS $CCXXFLAGS_JDK -Wall -Wno-parentheses -Wextra -Wno-unused -Wno-unused-parameter -Wformat=2 \ @@ -79,7 +76,7 @@ diff -wpruN --no-dereference '--exclude=*.orig' a~/common/autoconf/generated-con case $OPENJDK_TARGET_CPU_ARCH in arm ) # on arm we don't prevent gcc to omit frame pointer but do prevent strict aliasing -@@ -44789,11 +44798,8 @@ fi +@@ -44810,11 +44818,6 @@ fi if test "x$OPENJDK_TARGET_OS" = xsolaris; then OPENWIN_HOME="/usr/openwin" @@ -88,12 +85,10 @@ diff -wpruN --no-dereference '--exclude=*.orig' a~/common/autoconf/generated-con - -L$SYSROOT$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR \ - -R$OPENWIN_HOME/sfw/lib$OPENJDK_TARGET_CPU_ISADIR \ - -R$OPENWIN_HOME/lib$OPENJDK_TARGET_CPU_ISADIR" -+ X_CFLAGS="-I$x_includes" -+ X_LIBS="-L$x_libraries -R$x_libraries" fi # -@@ -49120,7 +49126,7 @@ $as_echo "$as_me: The path of FREETYPE_L +@@ -49141,7 +49144,7 @@ $as_echo "$as_me: The path of FREETYPE_L if test "x$OPENJDK_TARGET_OS" = xwindows; then FREETYPE_LIBS="$FREETYPE_LIB_PATH/freetype.lib" else