diff -Nru jdk21u-jdk-21.0.2-ga.orig/bin/unshuffle_list.txt jdk21u-jdk-21.0.2-ga/bin/unshuffle_list.txt --- jdk21u-jdk-21.0.2-ga.orig/bin/unshuffle_list.txt 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/bin/unshuffle_list.txt 2024-01-27 14:37:30.220616758 +0100 @@ -100,6 +100,7 @@ src/langtools/sample : langtools/src/sample src/linux : jdk/src/linux src/sample : jdk/src/sample +src/solaris : jdk/src/solaris src/hotspot/share : hotspot/src/share/vm src/hotspot/cpu/aarch64 : hotspot/src/cpu/aarch64/vm src/hotspot/cpu/arm : hotspot/src/cpu/arm/vm @@ -112,6 +113,7 @@ src/hotspot/os/linux : hotspot/src/os/linux/vm src/hotspot/os/posix/dtrace : hotspot/src/os/posix/dtrace src/hotspot/os/posix : hotspot/src/os/posix/vm +src/hotspot/os/solaris : hotspot/src/os/solaris/vm src/hotspot/os/windows : hotspot/src/os/windows/vm src/hotspot/os_cpu/aix_ppc : hotspot/src/os_cpu/aix_ppc/vm src/hotspot/os_cpu/bsd_x86 : hotspot/src/os_cpu/bsd_x86/vm @@ -122,6 +124,7 @@ src/hotspot/os_cpu/linux_s390 : hotspot/src/os_cpu/linux_s390/vm src/hotspot/os_cpu/linux_x86 : hotspot/src/os_cpu/linux_x86/vm src/hotspot/os_cpu/linux_zero : hotspot/src/os_cpu/linux_zero/vm +src/hotspot/os_cpu/solaris_x86 : hotspot/src/os_cpu/solaris_x86/vm src/hotspot/os_cpu/windows_x86 : hotspot/src/os_cpu/windows_x86/vm src/hotspot : hotspot/src src/utils/IdealGraphVisualizer : hotspot/src/share/tools/IdealGraphVisualizer diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/basic_tools.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/basic_tools.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/basic_tools.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/basic_tools.m4 2024-01-27 14:37:30.222138510 +0100 @@ -289,6 +289,8 @@ TAR_TYPE="bsd" elif test "x$($TAR --version | $GREP "busybox")" != "x"; then TAR_TYPE="busybox" + elif test "x$OPENJDK_BUILD_OS" = "xsolaris"; then + TAR_TYPE="solaris" elif test "x$OPENJDK_BUILD_OS" = "xaix"; then TAR_TYPE="aix" fi diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/build-aux/config.guess jdk21u-jdk-21.0.2-ga/make/autoconf/build-aux/config.guess --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/build-aux/config.guess 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/build-aux/config.guess 2024-01-27 14:37:30.222508121 +0100 @@ -53,6 +53,14 @@ fi fi +# Test and fix solaris on x86_64 +echo $OUT | grep i386-pc-solaris > /dev/null 2> /dev/null +if test $? = 0; then + # isainfo -n returns either i386 or amd64 + REAL_CPU=`isainfo -n` + OUT=$REAL_CPU`echo $OUT | sed -e 's/[^-]*//'` +fi + # Test and fix cygwin on x86_64 echo $OUT | grep 86-pc-cygwin > /dev/null 2> /dev/null if test $? != 0; then diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/build-performance.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/build-performance.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/build-performance.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/build-performance.m4 2024-01-27 14:37:30.222923689 +0100 @@ -33,6 +33,9 @@ if test "$NUM_CORES" -eq "0"; then NUM_CORES=`cat /proc/cpuinfo | grep -c ^CPU` fi + elif test -x /usr/sbin/psrinfo; then + # Looks like a Solaris system + NUM_CORES=`/usr/sbin/psrinfo -v | grep -c on-line` elif test -x /usr/sbin/sysctl; then # Looks like a MacOSX system NUM_CORES=`/usr/sbin/sysctl -n hw.ncpu` @@ -65,7 +68,7 @@ MEMORY_SIZE=`expr $MEMORY_SIZE / 1024` FOUND_MEM=yes elif test -x /usr/sbin/prtconf; then - # Looks like an AIX system + # Looks like a Solaris or AIX system MEMORY_SIZE=`/usr/sbin/prtconf 2> /dev/null | grep "^Memory [[Ss]]ize" | awk '{ print [$]3 }'` FOUND_MEM=yes elif test -x /usr/sbin/sysctl; then diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/flags-cflags.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/flags-cflags.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/flags-cflags.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/flags-cflags.m4 2024-01-27 14:37:30.223496092 +0100 @@ -427,6 +427,9 @@ if test "x$OPENJDK_TARGET_OS" = xlinux; then CFLAGS_OS_DEF_JVM="-DLINUX" 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" + CFLAGS_OS_DEF_JDK="-D__solaris__" elif test "x$OPENJDK_TARGET_OS" = xmacosx; then CFLAGS_OS_DEF_JVM="-D_ALLBSD_SOURCE -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" CFLAGS_OS_DEF_JDK="-D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT" diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/jdk-options.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/jdk-options.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/jdk-options.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/jdk-options.m4 2024-01-27 14:37:30.224003107 +0100 @@ -274,7 +274,7 @@ ZIP_EXTERNAL_DEBUG_SYMBOLS=false elif test "x$with_native_debug_symbols" = xexternal; then - if test "x$OPENJDK_TARGET_OS" = xlinux; then + if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then if test "x$OBJCOPY" = x; then # enabling of enable-debug-symbols and can't find objcopy # this is an error @@ -287,7 +287,7 @@ ZIP_EXTERNAL_DEBUG_SYMBOLS=false elif test "x$with_native_debug_symbols" = xzipped; then - if test "x$OPENJDK_TARGET_OS" = xlinux; then + if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then if test "x$OBJCOPY" = x; then # enabling of enable-debug-symbols and can't find objcopy # this is an error diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/lib-freetype.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/lib-freetype.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/lib-freetype.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/lib-freetype.m4 2024-01-27 14:37:30.224422276 +0100 @@ -53,6 +53,13 @@ if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then AC_MSG_NOTICE([Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location.]) FOUND_FREETYPE=no + else + if test "x$OPENJDK_TARGET_OS" = "xsolaris" \ + && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then + # Found lib in isa dir, use that instead. + POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR" + AC_MSG_NOTICE([Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead]) + fi fi fi @@ -160,6 +167,15 @@ if test "x$PKG_CONFIG" != "x" ; then PKG_CHECK_MODULES(FREETYPE, freetype2, [FOUND_FREETYPE=yes], [FOUND_FREETYPE=no]) if test "x$FOUND_FREETYPE" = "xyes" ; then + # On solaris, pkg_check adds -lz to freetype libs, which isn't + # necessary for us. + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'` + # 64-bit libs for Solaris x86 are installed in the amd64 + # subdirectory, change lib to lib/amd64 + if test "x$OPENJDK_TARGET_OS" = "xsolaris" && \ + test "x$OPENJDK_TARGET_CPU" = "xx86_64" ; then + FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'` + fi AC_MSG_CHECKING([for freetype]) AC_MSG_RESULT([yes (using pkg-config)]) fi diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/libraries.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/libraries.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/libraries.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/libraries.m4 2024-01-27 14:37:30.224823216 +0100 @@ -139,13 +139,15 @@ BASIC_JVM_LIBS="$LIBM" # Dynamic loading library - if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xaix; then + if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBDL" fi # Threading library if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xaix; then BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lpthread" + elif test "x$OPENJDK_TARGET_OS" = xsolaris; then + BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lthread" fi # librt for legacy clock_gettime @@ -162,6 +164,12 @@ BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lperfstat" fi + if test "x$OPENJDK_TARGET_OS" = xsolaris; then + BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -lnsl \ + -lrt -lkstat" + BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM" + fi + if test "x$OPENJDK_TARGET_OS" = xwindows; then BASIC_JVM_LIBS="$BASIC_JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \ comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib powrprof.lib uuid.lib \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/platform.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/platform.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/platform.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/platform.m4 2024-01-27 14:37:30.225338337 +0100 @@ -202,6 +202,10 @@ VAR_OS=linux VAR_OS_TYPE=unix ;; + *solaris*) + VAR_OS=solaris + VAR_OS_TYPE=unix + ;; *darwin*) VAR_OS=macosx VAR_OS_TYPE=unix @@ -472,6 +476,17 @@ fi AC_SUBST(OPENJDK_$1_CPU_LEGACY_LIB) + # OPENJDK_$1_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to + # /amd64 or /sparcv9. This string is appended to some library paths, like this: + # /usr/lib${OPENJDK_$1_CPU_ISADIR}/libexample.so + OPENJDK_$1_CPU_ISADIR="" + if test "x$OPENJDK_$1_OS" = xsolaris; then + if test "x$OPENJDK_$1_CPU" = xx86_64; then + OPENJDK_$1_CPU_ISADIR="/amd64" + fi + fi + AC_SUBST(OPENJDK_$1_CPU_ISADIR) + # Setup OPENJDK_$1_CPU_OSARCH, which is used to set the os.arch Java system property OPENJDK_$1_CPU_OSARCH="$OPENJDK_$1_CPU" if test "x$OPENJDK_$1_OS" = xlinux && test "x$OPENJDK_$1_CPU" = xx86; then @@ -603,6 +618,9 @@ AC_DEFUN([PLATFORM_SET_RELEASE_FILE_OS_VALUES], [ + if test "x$OPENJDK_TARGET_OS" = "xsolaris"; then + RELEASE_FILE_OS_NAME=SunOS + fi if test "x$OPENJDK_TARGET_OS" = "xlinux"; then RELEASE_FILE_OS_NAME=Linux fi diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/spec.gmk.in jdk21u-jdk-21.0.2-ga/make/autoconf/spec.gmk.in --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/spec.gmk.in 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/spec.gmk.in 2024-01-27 14:37:30.225806432 +0100 @@ -93,6 +93,7 @@ COMPILE_TYPE:=@COMPILE_TYPE@ # Legacy support +OPENJDK_TARGET_CPU_ISADIR:=@OPENJDK_TARGET_CPU_ISADIR@ OPENJDK_TARGET_CPU_LEGACY:=@OPENJDK_TARGET_CPU_LEGACY@ OPENJDK_TARGET_CPU_LEGACY_LIB:=@OPENJDK_TARGET_CPU_LEGACY_LIB@ OPENJDK_TARGET_CPU_OSARCH:=@OPENJDK_TARGET_CPU_OSARCH@ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/autoconf/toolchain.m4 jdk21u-jdk-21.0.2-ga/make/autoconf/toolchain.m4 --- jdk21u-jdk-21.0.2-ga.orig/make/autoconf/toolchain.m4 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/autoconf/toolchain.m4 2024-01-27 14:37:30.226309467 +0100 @@ -39,6 +39,7 @@ # These toolchains are valid on different platforms VALID_TOOLCHAINS_linux="gcc clang" +VALID_TOOLCHAINS_solaris="gcc" VALID_TOOLCHAINS_macosx="clang" VALID_TOOLCHAINS_aix="xlc clang" VALID_TOOLCHAINS_windows="microsoft" diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/common/MakeBase.gmk jdk21u-jdk-21.0.2-ga/make/common/MakeBase.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/common/MakeBase.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/common/MakeBase.gmk 2024-01-27 14:37:30.226823111 +0100 @@ -263,7 +263,33 @@ ################################################################################ # All install-file and related macros automatically call DecodeSpace when needed. -ifeq ($(call isTargetOs, macosx), true) +ifeq ($(call isTargetOs, solaris), true) + # On Solaris, if the target is a symlink and exists, cp won't overwrite. + # Cp has to operate in recursive mode to allow for -P flag, to preserve soft links. If the + # name of the target file differs from the source file, rename after copy. + # If the source and target parent directories are the same, recursive copy doesn't work + # so we fall back on regular copy, which isn't preserving symlinks. + define install-file + $(call MakeTargetDir) + $(RM) '$(call DecodeSpace, $@)' + if [ '$(call DecodeSpace, $(dir $(call EncodeSpace, $@)))' != \ + '$(call DecodeSpace, $(dir $(call EncodeSpace, $<)))' ]; then \ + $(CP) -f -r -P '$(call DecodeSpace, $<)' \ + '$(call DecodeSpace, $(dir $(call EncodeSpace, $@)))'; \ + if [ '$(call DecodeSpace, $(notdir $(call EncodeSpace, $@)))' != \ + '$(call DecodeSpace, $(notdir $(call EncodeSpace, $(<))))' ]; then \ + $(MV) '$(call DecodeSpace, $(dir $(call EncodeSpace, $@))/$(notdir $(call EncodeSpace, $<)))' \ + '$(call DecodeSpace, $@)'; \ + fi; \ + else \ + if [ -L '$(call DecodeSpace, $<)' ]; then \ + $(ECHO) "Source file is a symlink and target is in the same directory: $< $@" ; \ + exit 1; \ + fi; \ + $(CP) -f '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'; \ + fi + endef +else ifeq ($(call isTargetOs, macosx), true) # On mac, extended attributes sometimes creep into the source files, which may later # cause the creation of ._* files which confuses testing. Clear these with xattr if # set. Some files get their write permissions removed after being copied to the diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/common/modules/LauncherCommon.gmk jdk21u-jdk-21.0.2-ga/make/common/modules/LauncherCommon.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/common/modules/LauncherCommon.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/common/modules/LauncherCommon.gmk 2024-01-27 14:37:30.227915467 +0100 @@ -163,6 +163,7 @@ -DLAUNCHER_NAME='"$$(LAUNCHER_NAME)"' \ -DPROGNAME='"$1"' \ $$($1_CFLAGS), \ + CFLAGS_solaris := -fPIC, \ CFLAGS_windows := $$($1_CFLAGS_windows), \ DISABLED_WARNINGS_gcc := unused-function, \ LDFLAGS := $$(LDFLAGS_JDKEXE) \ @@ -172,11 +173,14 @@ -L$(call FindLibDirForModule, java.base), \ LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \ -L$(call FindLibDirForModule, java.base), \ + LDFLAGS_solaris := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \ + -L$(call FindLibDirForModule, java.base), \ LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \ LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \ LIBS_linux := -ljli -lpthread $(LIBDL), \ LIBS_macosx := -ljli -framework Cocoa -framework Security \ -framework ApplicationServices, \ + LIBS_solaris := -ljli -lthread $(LIBDL), \ LIBS_aix := -ljli_static, \ LIBS_windows := $$($1_WINDOWS_JLI_LIB) \ $(SUPPORT_OUTPUTDIR)/native/java.base/libjava/java.lib, \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/common/NativeCompilation.gmk jdk21u-jdk-21.0.2-ga/make/common/NativeCompilation.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/common/NativeCompilation.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/common/NativeCompilation.gmk 2024-01-27 14:37:30.227475865 +0100 @@ -1058,7 +1058,7 @@ $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_BASENAME).pdb \ $$($1_SYMBOLS_DIR)/$$($1_BASENAME).map - else ifeq ($(call isTargetOs, linux), true) + else ifeq ($(call isTargetOs, linux solaris), true) $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).debuginfo # Setup the command line creating debuginfo files, to be run after linking. # It cannot be run separately since it updates the original target file diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/gensrc/GensrcAdlc.gmk jdk21u-jdk-21.0.2-ga/make/hotspot/gensrc/GensrcAdlc.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/gensrc/GensrcAdlc.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/gensrc/GensrcAdlc.gmk 2024-01-27 14:37:30.228332662 +0100 @@ -36,6 +36,9 @@ # NOTE: No optimization or debug flags set here ifeq ($(call isBuildOs, linux), true) ADLC_CFLAGS := -fno-exceptions -DLINUX + else ifeq ($(call isBuildOs, solaris), true) + ADLC_LDFLAGS := -m64 + ADLC_CFLAGS := -m64 -fpermissive else ifeq ($(call isBuildOs, aix), true) ifeq ($(TOOLCHAIN_TYPE), clang) ADLC_LDFLAGS += -m64 @@ -95,6 +98,8 @@ # ADLC flags depending on target OS ifeq ($(call isTargetOs, linux), true) ADLCFLAGS += -DLINUX=1 -D_GNU_SOURCE=1 + else ifeq ($(call isTargetOs, solaris), true) + ADLCFLAGS += -DSOLARIS=1 else ifeq ($(call isTargetOs, aix), true) ADLCFLAGS += -DAIX=1 else ifeq ($(call isTargetOs, macosx), true) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/gensrc/GensrcDtrace.gmk jdk21u-jdk-21.0.2-ga/make/hotspot/gensrc/GensrcDtrace.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/gensrc/GensrcDtrace.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/gensrc/GensrcDtrace.gmk 2024-01-27 14:37:30.228709178 +0100 @@ -28,7 +28,10 @@ ifeq ($(call check-jvm-feature, dtrace), true) - ifeq ($(call isTargetOs, macosx), true) + ifeq ($(call isTargetOs, solaris), true) + DTRACE_FLAGS := -64 + DTRACE_CPP_FLAGS := -D_LP64 -x c + else ifeq ($(call isTargetOs, macosx), true) DTRACE_CPP_FLAGS := -D_LP64 -x c else ifeq ($(call isTargetOs, linux), true) DTRACE_CPP_FLAGS := -x c @@ -51,4 +54,59 @@ TARGETS += $(patsubst $(DTRACE_SOURCE_DIR)/%.d, \ $(DTRACE_GENSRC_DIR)/%.h, $(wildcard $(DTRACE_SOURCE_DIR)/*.d)) + ifeq ($(call isTargetOs, solaris), true) + ############################################################################ + # First we need to generate the dtraceGenOffsets tool. When run, this will + # produce two header files and a C++ file. Note that generateJvmOffsets.cpp + # is using the same JVM_CFLAGS as libjvm.so. + + # Include support files that will setup JVM compiler flags. + include lib/JvmFeatures.gmk + include lib/JvmFlags.gmk + + # We cannot compile until the JVMTI and JFR gensrc has finished. + # JFR_FILES is defined in GensrcJfr.gmk. + JVMTI_H := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h + + $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \ + NAME := dtraceGenOffsets, \ + TYPE := EXECUTABLE, \ + SRC := $(TOPDIR)/make/hotspot/src/native/dtrace, \ + TOOLCHAIN := $(TOOLCHAIN_BUILD), \ + LDFLAGS := -m64, \ + CFLAGS := -m64 $(JVM_CFLAGS), \ + EXTRA_DEPS := $(JVMTI_H) $(JFR_FILES), \ + OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \ + OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \ + )) + + DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET) + + # Argument 1: Output filename + # Argument 2: dtrace-gen-offset tool command line option + define SetupDtraceOffsetsGeneration + $$(eval $$(call SetupExecute, dtrace_offset_$$(strip $2), \ + INFO := Generating dtrace $2 file, \ + DEPS := $$(BUILD_DTRACE_GEN_OFFSETS), \ + OUTPUT_FILE := $1, \ + COMMAND := ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $1 ), \ + )) + + TARGETS += $$(dtrace_offset_$$(strip $2)_TARGET) + endef + + JVM_OFFSETS_H := $(DTRACE_GENSRC_DIR)/JvmOffsets.h + JVM_OFFSETS_CPP := $(DTRACE_GENSRC_DIR)/JvmOffsets.cpp + JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h + + ############################################################################ + # Run the dtrace-gen-offset tool to generate these three files. + # The generated JvmOffsets.cpp is compiled with the rest of libjvm. + # The header files are used by libjvm_db and jhelper.d, respectively. + + $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header)) + $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index)) + $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table)) + endif + endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/CompileDtraceLibraries.gmk jdk21u-jdk-21.0.2-ga/make/hotspot/lib/CompileDtraceLibraries.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/CompileDtraceLibraries.gmk 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/lib/CompileDtraceLibraries.gmk 2024-01-27 14:37:30.282759982 +0100 @@ -0,0 +1,62 @@ +# +# Copyright (c) 2013, 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# + +ifeq ($(call check-jvm-feature, dtrace), true) + ifeq ($(call isTargetOs, solaris), true) + JNI_INCLUDE_FLAGS := \ + -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base \ + -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base/$(OPENJDK_TARGET_OS_INCLUDE_SUBDIR) \ + # + + ############################################################################ + # Build the stand-alone dtrace libraries. + + LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace + $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \ + NAME := jvm_dtrace, \ + OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \ + SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_dtrace, \ + CFLAGS := $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \ + LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \ + LIBS := $(LIBDL) -lthread -ldoor, \ + OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \ + )) + + # Note that libjvm_db.c has tests for COMPILER2, but this was never set by + # the old build. + LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db + $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \ + NAME := jvm_db, \ + OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \ + SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_db, \ + CFLAGS := -I$(DTRACE_GENSRC_DIR) $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \ + LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \ + OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \ + )) + + TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB) + + endif +endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/CompileJvm.gmk jdk21u-jdk-21.0.2-ga/make/hotspot/lib/CompileJvm.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/CompileJvm.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/lib/CompileJvm.gmk 2024-01-27 14:37:30.229133636 +0100 @@ -29,6 +29,9 @@ include lib/JvmOverrideFiles.gmk include lib/JvmFlags.gmk +# Include support files that will setup DTRACE_EXTRA_OBJECT_FILES. +include lib/JvmDtraceObjects.gmk + ################################################################################ # Setup compilation of the main Hotspot native library (libjvm). @@ -150,6 +153,7 @@ EXCLUDES := $(JVM_EXCLUDES), \ EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \ EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \ + EXTRA_OBJECT_FILES := $(DTRACE_EXTRA_OBJECT_FILES), \ CFLAGS := $(JVM_CFLAGS), \ abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/CompileLibraries.gmk jdk21u-jdk-21.0.2-ga/make/hotspot/lib/CompileLibraries.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/CompileLibraries.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/lib/CompileLibraries.gmk 2024-01-27 14:37:30.229452284 +0100 @@ -32,6 +32,7 @@ include HotspotCommon.gmk include lib/CompileJvm.gmk +include lib/CompileDtraceLibraries.gmk ifneq ($(GTEST_FRAMEWORK_SRC), ) ifneq ($(CREATING_BUILDJDK), true) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/JvmDtraceObjects.gmk jdk21u-jdk-21.0.2-ga/make/hotspot/lib/JvmDtraceObjects.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/JvmDtraceObjects.gmk 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/lib/JvmDtraceObjects.gmk 2024-01-27 14:37:30.283030985 +0100 @@ -0,0 +1,122 @@ +# +# Copyright (c) 2013, 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# + +ifeq ($(call check-jvm-feature, dtrace), true) + ifeq ($(call isTargetOs, solaris), true) + + ############################################################################ + # Integrate with libjvm. Here we generate two object files which are + # linked with libjvm.so. This step is complicated from a dependency + # perspective. We add these two files to the linking of libjvm using + # EXTRA_OBJECT_FILES, but they need to be created outside the call to + # SetupNativeCompilation. Also, one of the files is dependent on compiled + # object files from the libjvm compilation, so this generation must happen + # as a part of the libjvm compilation. + + DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o + DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o + + DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ) + + ############################################################################ + # Generate DTRACE_OBJ which is linked with libjvm.so. It depends on a set of + # object files from the compilation. + + # Concatenate all *.d files into a single file + DTRACE_SOURCE_FILES := $(addprefix $(TOPDIR)/src/hotspot/os/posix/dtrace/, \ + hotspot_jni.d \ + hotspot.d \ + hs_private.d \ + ) + + # *.d in the objs dir is used for generated make dependency files, so use + # *.dt for dtrace files to avoid clashes. + $(JVM_OUTPUTDIR)/objs/dtrace.dt: $(DTRACE_SOURCE_FILES) + $(call LogInfo, Generating $(@F)) + $(call MakeDir, $(@D)) + $(CAT) $^ > $@ + + DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \ + ciEnv.o \ + classLoadingService.o \ + compileBroker.o \ + gcVMOperations.o \ + hashtable.o \ + instanceKlass.o \ + java.o \ + jni.o \ + jvm.o \ + memoryManager.o \ + nmethod.o \ + objectMonitor.o \ + runtimeService.o \ + sharedRuntime.o \ + synchronizer.o \ + thread.o \ + unsafe.o \ + vmThread.o \ + ) + + ifeq ($(call check-jvm-feature, parallelgc), true) + DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \ + psVMOperations.o \ + ) + endif + + DTRACE_FLAGS := -64 -G + DTRACE_CPP_FLAGS := -D_LP64 + + # Make sure we run our selected compiler for preprocessing instead of letting + # the dtrace tool pick it on it's own. + $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.dt $(DTRACE_INSTRUMENTED_OBJS) + $(call LogInfo, Generating $(@F) from $( $(DTRACE_SUPPORT_DIR)/$(@F).dt)) + $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \ + -s $(DTRACE_SUPPORT_DIR)/$(@F).dt $(sort $(DTRACE_INSTRUMENTED_OBJS))) + + ############################################################################ + # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so. + + JHELPER_DTRACE_SRC := $(TOPDIR)/src/hotspot/os/solaris/dtrace/jhelper.d + + # jhelper.d includes JvmOffsetsIndex.h which was created by the gensrc step. + DTRACE_GENSRC_DIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/dtracefiles + JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h + + # Make sure we run our selected compiler for preprocessing instead of letting + # the dtrace tool pick it on it's own. + $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H) + $(call LogInfo, Running dtrace for $( $(DTRACE_SUPPORT_DIR)/$(@F).dt)) + $(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \ + -s $(DTRACE_SUPPORT_DIR)/$(@F).dt) + + endif +endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/JvmMapfile.gmk jdk21u-jdk-21.0.2-ga/make/hotspot/lib/JvmMapfile.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/lib/JvmMapfile.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/lib/JvmMapfile.gmk 2024-01-27 14:37:30.229875189 +0100 @@ -48,6 +48,18 @@ endif endif +ifeq ($(call isTargetOs, solaris), true) + ifeq ($(call check-jvm-feature, dtrace), true) + # Additional mapfiles that are only used when dtrace is enabled + ifeq ($(call check-jvm-feature, compiler2), true) + # This also covers the case of compiler1+compiler2. + SYMBOLS_SRC += $(TOPDIR)/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 + else ifeq ($(call check-jvm-feature, compiler1), true) + SYMBOLS_SRC += $(TOPDIR)/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 + endif + endif +endif + ################################################################################ # Create a dynamic list of symbols from the built object files. This is highly # platform dependent. @@ -64,6 +76,20 @@ if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \ }' +else ifeq ($(call isTargetOs, solaris), true) + DUMP_SYMBOLS_CMD := $(NM) -p *.o + ifneq ($(FILTER_SYMBOLS_PATTERN), ) + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)| + endif + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)^__1c.*__vtbl_$$|^gHotSpotVM + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^UseSharedSpaces$$ + FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^__1cJArgumentsRSharedArchivePath_$$ + FILTER_SYMBOLS_AWK_SCRIPT := \ + '{ \ + if ($$2 == "U") next; \ + if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \ + }' + else ifeq ($(call isTargetOs, macosx), true) # nm on macosx prints out "warning: nm: no name list" to stderr for # files without symbols. Hide this, even at the expense of hiding real errors. diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp jdk21u-jdk-21.0.2-ga/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp 2024-01-27 14:37:30.283494770 +0100 @@ -0,0 +1,316 @@ +/* + * 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. + * + */ + +/* + * This is to provide sanity check in jhelper.d which compares SCCS + * versions of generateJvmOffsets.cpp used to create and extract + * contents of __JvmOffsets[] table. + * The __JvmOffsets[] table is located in generated JvmOffsets.cpp. + * + * GENOFFS_SCCS_VER 34 + */ + +#include +#include + +/* A workaround for private and protected fields */ +#define private public +#define protected public + +#include +#include "gc/shared/collectedHeap.hpp" +#include "memory/heap.hpp" +#include "oops/compressedOops.hpp" +#include "runtime/vmStructs.hpp" + +typedef enum GEN_variant { + GEN_OFFSET = 0, + GEN_INDEX = 1, + GEN_TABLE = 2 +} GEN_variant; + +#ifdef COMPILER1 +#ifdef ASSERT + +/* + * To avoid the most part of potential link errors + * we link this program with -z nodefs . + * + * But for 'debug1' and 'fastdebug1' we still have to provide + * a particular workaround for the following symbols below. + * It will be good to find out a generic way in the future. + */ + +#pragma weak tty + +#if defined(i386) || defined(__i386) || defined(__amd64) +#pragma weak noreg +#endif /* i386 */ + +LIR_Opr LIR_OprFact::illegalOpr = (LIR_Opr) 0; + +address StubRoutines::_call_stub_return_address = NULL; + +StubQueue* AbstractInterpreter::_code = NULL; + +#endif /* ASSERT */ +#endif /* COMPILER1 */ + +#define GEN_OFFS_NAME(Type,Name,OutputType) \ + switch(gen_variant) { \ + case GEN_OFFSET: \ + printf("#define OFFSET_%-33s %ld\n", \ + #OutputType #Name, offset_of(Type, Name)); \ + break; \ + case GEN_INDEX: \ + printf("#define IDX_OFFSET_%-33s %d\n", \ + #OutputType #Name, index++); \ + break; \ + case GEN_TABLE: \ + printf("\tOFFSET_%s,\n", #OutputType #Name); \ + break; \ + } + +#define GEN_OFFS(Type,Name) \ + GEN_OFFS_NAME(Type,Name,Type) + +#define GEN_SIZE(Type) \ + switch(gen_variant) { \ + case GEN_OFFSET: \ + printf("#define SIZE_%-35s %ld\n", \ + #Type, sizeof(Type)); \ + break; \ + case GEN_INDEX: \ + printf("#define IDX_SIZE_%-35s %d\n", \ + #Type, index++); \ + break; \ + case GEN_TABLE: \ + printf("\tSIZE_%s,\n", #Type); \ + break; \ + } + +#define GEN_VALUE(String,Value) \ + switch(gen_variant) { \ + case GEN_OFFSET: \ + printf("#define %-40s %d\n", #String, Value); \ + break; \ + case GEN_INDEX: \ + printf("#define IDX_%-40s %d\n", #String, index++); \ + break; \ + case GEN_TABLE: \ + printf("\t" #String ",\n"); \ + break; \ + } + +void gen_prologue(GEN_variant gen_variant) { + const char *suffix = "Undefined-Suffix"; + + switch(gen_variant) { + case GEN_OFFSET: suffix = ".h"; break; + case GEN_INDEX: suffix = "Index.h"; break; + case GEN_TABLE: suffix = ".cpp"; break; + } + + printf("/*\n"); + printf(" * JvmOffsets%s !!!DO NOT EDIT!!! \n", suffix); + printf(" * The generateJvmOffsets program generates this file!\n"); + printf(" */\n\n"); + switch(gen_variant) { + + case GEN_OFFSET: + case GEN_INDEX: + break; + + case GEN_TABLE: + printf("#include \"JvmOffsets.h\"\n"); + printf("\n"); + printf("int __JvmOffsets[] = {\n"); + break; + } +} + +void gen_epilogue(GEN_variant gen_variant) { + if (gen_variant != GEN_TABLE) { + return; + } + printf("};\n\n"); + return; +} + +int generateJvmOffsets(GEN_variant gen_variant) { + int index = 0; /* It is used to generate JvmOffsetsIndex.h */ + int pointer_size = sizeof(void *); + int data_model = (pointer_size == 4) ? PR_MODEL_ILP32 : PR_MODEL_LP64; + + gen_prologue(gen_variant); + + GEN_VALUE(DATA_MODEL, data_model); + GEN_VALUE(POINTER_SIZE, pointer_size); +#if defined(TIERED) + GEN_VALUE(COMPILER, 3); +#elif COMPILER1 + GEN_VALUE(COMPILER, 1); +#elif COMPILER2 + GEN_VALUE(COMPILER, 2); +#else + GEN_VALUE(COMPILER, 0); +#endif // COMPILER1 && COMPILER2 + printf("\n"); + + GEN_OFFS(CollectedHeap, _reserved); + GEN_OFFS(MemRegion, _start); + GEN_OFFS(MemRegion, _word_size); + GEN_SIZE(HeapWord); + printf("\n"); + + GEN_OFFS(VMStructEntry, typeName); + GEN_OFFS(VMStructEntry, fieldName); + GEN_OFFS(VMStructEntry, address); + GEN_SIZE(VMStructEntry); + printf("\n"); + + GEN_VALUE(MAX_METHOD_CODE_SIZE, max_method_code_size); +#if defined(i386) || defined(__i386) || defined(__amd64) + GEN_VALUE(OFFSET_interpreter_frame_sender_sp, -1 * pointer_size); + GEN_VALUE(OFFSET_interpreter_frame_method, -3 * pointer_size); + GEN_VALUE(OFFSET_interpreter_frame_bcp_offset, -7 * pointer_size); +#endif + + GEN_OFFS(Klass, _name); + GEN_OFFS(ConstantPool, _pool_holder); + printf("\n"); + + GEN_VALUE(OFFSET_HeapBlockHeader_used, (int) offset_of(HeapBlock::Header, _used)); + GEN_OFFS(oopDesc, _metadata); + printf("\n"); + + GEN_VALUE(AccessFlags_NATIVE, JVM_ACC_NATIVE); + GEN_VALUE(ConstMethod_has_linenumber_table, ConstMethod::_has_linenumber_table); + GEN_OFFS(AccessFlags, _flags); + GEN_OFFS(Symbol, _length); + GEN_OFFS(Symbol, _body); + printf("\n"); + + GEN_OFFS(Method, _constMethod); + GEN_OFFS(Method, _access_flags); + printf("\n"); + + GEN_OFFS(ConstMethod, _constants); + GEN_OFFS(ConstMethod, _flags); + GEN_OFFS(ConstMethod, _code_size); + GEN_OFFS(ConstMethod, _name_index); + GEN_OFFS(ConstMethod, _signature_index); + printf("\n"); + + GEN_OFFS(CodeHeap, _memory); + GEN_OFFS(CodeHeap, _segmap); + GEN_OFFS(CodeHeap, _log2_segment_size); + printf("\n"); + + GEN_OFFS(VirtualSpace, _low_boundary); + GEN_OFFS(VirtualSpace, _high_boundary); + GEN_OFFS(VirtualSpace, _low); + GEN_OFFS(VirtualSpace, _high); + printf("\n"); + + /* We need to use different names here because of the template parameter */ + GEN_OFFS_NAME(GrowableArray, _data, GrowableArray_CodeHeap); + GEN_OFFS_NAME(GrowableArray, _len, GrowableArray_CodeHeap); + printf("\n"); + + GEN_OFFS(CodeBlob, _name); + GEN_OFFS(CodeBlob, _header_size); + GEN_OFFS(CodeBlob, _content_begin); + GEN_OFFS(CodeBlob, _code_begin); + GEN_OFFS(CodeBlob, _code_end); + GEN_OFFS(CodeBlob, _data_offset); + GEN_OFFS(CodeBlob, _frame_size); + printf("\n"); + + GEN_OFFS(nmethod, _method); + GEN_OFFS(nmethod, _dependencies_offset); + GEN_OFFS(nmethod, _metadata_offset); + GEN_OFFS(nmethod, _scopes_data_begin); + GEN_OFFS(nmethod, _scopes_pcs_offset); + GEN_OFFS(nmethod, _handler_table_offset); + GEN_OFFS(nmethod, _deopt_handler_begin); + GEN_OFFS(nmethod, _orig_pc_offset); + + GEN_OFFS(PcDesc, _pc_offset); + GEN_OFFS(PcDesc, _scope_decode_offset); + + printf("\n"); + + GEN_OFFS(NarrowPtrStruct, _base); + GEN_OFFS(NarrowPtrStruct, _shift); + printf("\n"); + + GEN_VALUE(SIZE_HeapBlockHeader, (int) sizeof(HeapBlock::Header)); + GEN_SIZE(oopDesc); + GEN_SIZE(ConstantPool); + printf("\n"); + + GEN_SIZE(PcDesc); + GEN_SIZE(Method); + GEN_SIZE(ConstMethod); + GEN_SIZE(nmethod); + GEN_SIZE(CodeBlob); + GEN_SIZE(BufferBlob); + GEN_SIZE(SingletonBlob); + GEN_SIZE(RuntimeStub); + GEN_SIZE(SafepointBlob); + + gen_epilogue(gen_variant); + printf("\n"); + + fflush(stdout); + return 0; +} + +const char *HELP = + "HELP: generateJvmOffsets {-header | -index | -table} \n"; + +int main(int argc, const char *argv[]) { + GEN_variant gen_var; + + if (argc != 2) { + printf("%s", HELP); + return 1; + } + + if (0 == strcmp(argv[1], "-header")) { + gen_var = GEN_OFFSET; + } + else if (0 == strcmp(argv[1], "-index")) { + gen_var = GEN_INDEX; + } + else if (0 == strcmp(argv[1], "-table")) { + gen_var = GEN_TABLE; + } + else { + printf("%s", HELP); + return 1; + } + return generateJvmOffsets(gen_var); +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/symbols/symbols-solaris jdk21u-jdk-21.0.2-ga/make/hotspot/symbols/symbols-solaris --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/symbols/symbols-solaris 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/symbols/symbols-solaris 2024-01-27 14:37:30.283777525 +0100 @@ -0,0 +1,25 @@ +# +# Copyright (c) 2016, 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. +# + +JVM_handle_solaris_signal +sysThreadAvailableStackWithSlack diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 jdk21u-jdk-21.0.2-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 2024-01-27 14:37:30.284006922 +0100 @@ -0,0 +1,34 @@ +# +# Copyright (c) 2016, 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. +# + +__1cGMethodG__vtbl_ +__1cHnmethodG__vtbl_ +__1cICodeBlobG__vtbl_ +__1cIUniverseO_collectedHeap_ +__1cJCodeCacheG_heaps_ +__1cKBufferBlobG__vtbl_ +__1cLRuntimeStubG__vtbl_ +__1cNSafepointBlobG__vtbl_ +__1cSDeoptimizationBlobG__vtbl_ + +__JvmOffsets diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 jdk21u-jdk-21.0.2-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 --- jdk21u-jdk-21.0.2-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 2024-01-27 14:37:30.284233384 +0100 @@ -0,0 +1,36 @@ +# +# Copyright (c) 2016, 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. +# + +__1cGMethodG__vtbl_ +__1cHnmethodG__vtbl_ +__1cICodeBlobG__vtbl_ +__1cIUniverseO_collectedHeap_ +__1cJCodeCacheG_heaps_ +__1cKBufferBlobG__vtbl_ +__1cLRuntimeStubG__vtbl_ +__1cNSafepointBlobG__vtbl_ +__1cSDeoptimizationBlobG__vtbl_ +__1cNExceptionBlobG__vtbl_ +__1cQUncommonTrapBlobG__vtbl_ + +__JvmOffsets diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/ide/visualstudio/hotspot/CreateVSProject.gmk jdk21u-jdk-21.0.2-ga/make/ide/visualstudio/hotspot/CreateVSProject.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/ide/visualstudio/hotspot/CreateVSProject.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/ide/visualstudio/hotspot/CreateVSProject.gmk 2024-01-27 14:37:30.230252674 +0100 @@ -76,6 +76,7 @@ -ignorePath linux \ -ignorePath posix \ -ignorePath ppc \ + -ignorePath solaris \ -ignorePath x86_32 \ -ignorePath zero \ # diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/langtools/build.xml jdk21u-jdk-21.0.2-ga/make/langtools/build.xml --- jdk21u-jdk-21.0.2-ga.orig/make/langtools/build.xml 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/langtools/build.xml 2024-01-27 14:37:30.230675474 +0100 @@ -100,7 +100,7 @@ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/Copy.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.base/Copy.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/Copy.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.base/Copy.gmk 2024-01-27 14:37:30.231112351 +0100 @@ -190,7 +190,7 @@ TARGETS += $(NET_PROPERTIES_DST) -ifeq ($(call isTargetOs, linux), true) +ifeq ($(call isTargetOs, solaris linux), true) $(eval $(call SetupCopyFiles, COPY_SDP_CONF, \ FILES := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/sdp/sdp.conf.template, \ DEST := $(CONF_DST_DIR)/sdp, \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/gensrc/GensrcMisc.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.base/gensrc/GensrcMisc.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/gensrc/GensrcMisc.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.base/gensrc/GensrcMisc.gmk 2024-01-27 14:37:30.232298330 +0100 @@ -136,6 +136,21 @@ endif +################################################################################ + +ifeq ($(call isTargetOs, solaris), true) + + GENSRC_SC_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/SolarisConstants.java + + $(GENSRC_SC_FILE): \ + $(TOPDIR)/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template + $(generate-preproc-src) + + TARGETS += $(GENSRC_SC_FILE) + +endif + +################################################################################ # Create the javax/crypto/JceSecurity.class, using the build default. # ifeq ($(UNLIMITED_CRYPTO), true) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/Launcher.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.base/Launcher.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/Launcher.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.base/Launcher.gmk 2024-01-27 14:37:30.231477989 +0100 @@ -64,6 +64,7 @@ CFLAGS := $(CFLAGS_JDKEXE) \ -I$(TOPDIR)/src/$(MODULE)/share/native/libjli, \ CFLAGS_linux := -fPIC, \ + CFLAGS_solaris := -KPIC, \ LDFLAGS := $(LDFLAGS_JDKEXE), \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE), \ )) @@ -73,7 +74,7 @@ ################################################################################ -ifeq ($(call isTargetOs, macosx aix linux), true) +ifeq ($(call isTargetOs, macosx solaris aix linux), true) $(eval $(call SetupJdkExecutable, BUILD_JSPAWNHELPER, \ NAME := jspawnhelper, \ SRC := $(TOPDIR)/src/$(MODULE)/unix/native/jspawnhelper, \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/lib/CoreLibraries.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.base/lib/CoreLibraries.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/lib/CoreLibraries.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.base/lib/CoreLibraries.gmk 2024-01-27 14:37:30.232765124 +0100 @@ -26,7 +26,7 @@ ########################################################################################## LIBVERIFY_OPTIMIZATION := HIGH -ifeq ($(call isTargetOs, linux), true) +ifeq ($(call isTargetOs, solaris linux), true) ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true) LIBVERIFY_OPTIMIZATION := LOW endif @@ -67,6 +67,7 @@ LDFLAGS_windows := -delayload:shell32.dll, \ LIBS_unix := -ljvm, \ LIBS_linux := $(LIBDL), \ + LIBS_solaris := -lsocket -lnsl -lscf $(LIBDL), \ LIBS_aix := $(LIBDL) $(LIBM),\ LIBS_macosx := -framework CoreFoundation \ -framework Foundation \ @@ -177,6 +178,7 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := $(LIBZ_LIBS), \ LIBS_linux := $(LIBDL) -lpthread, \ + LIBS_solaris := $(LIBDL), \ LIBS_aix := $(LIBDL),\ LIBS_macosx := -framework Cocoa -framework Security -framework ApplicationServices, \ LIBS_windows := advapi32.lib comctl32.lib user32.lib, \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.base/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.base/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.base/Lib.gmk 2024-01-27 14:37:30.231917319 +0100 @@ -55,6 +55,7 @@ LDFLAGS_windows := -delayload:secur32.dll -delayload:iphlpapi.dll, \ LIBS_unix := -ljvm -ljava, \ LIBS_linux := $(LIBDL), \ + LIBS_solaris := -lnsl -lsocket $(LIBDL), \ LIBS_aix := $(LIBDL),\ LIBS_windows := ws2_32.lib jvm.lib secur32.lib iphlpapi.lib winhttp.lib \ delayimp.lib $(WIN_JAVA_LIB) advapi32.lib, \ @@ -81,6 +82,8 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := -ljava -lnet, \ LIBS_linux := -lpthread $(LIBDL), \ + LIBS_solaris := -ljvm -lsocket -lposix4 $(LIBDL) \ + -lsendfile, \ LIBS_aix := $(LIBDL), \ LIBS_macosx := \ -framework CoreFoundation -framework CoreServices, \ @@ -133,6 +136,7 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_linux := $(LIBDL), \ + LIBS_solaris := $(LIBDL), \ LIBS_aix := $(LIBDL), \ )) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.desktop/Gensrc.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.desktop/Gensrc.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.desktop/Gensrc.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.desktop/Gensrc.gmk 2024-01-27 14:37:30.233115094 +0100 @@ -32,7 +32,7 @@ include gensrc/GensrcIcons.gmk endif -ifeq ($(call isTargetOs, linux aix), true) +ifeq ($(call isTargetOs, linux solaris aix), true) include gensrc/GensrcX11Wrappers.gmk endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.desktop/lib/Awt2dLibraries.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.desktop/lib/Awt2dLibraries.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.desktop/lib/Awt2dLibraries.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.desktop/lib/Awt2dLibraries.gmk 2024-01-27 14:37:30.234114922 +0100 @@ -77,7 +77,7 @@ # endif -ifeq ($(call isTargetOs, linux macosx aix), true) +ifeq ($(call isTargetOs, solaris linux macosx aix), true) LIBAWT_EXFILES += awt_Font.c CUPSfuncs.c fontpath.c X11Color.c endif @@ -154,6 +154,7 @@ -delayload:comctl32.dll -delayload:shlwapi.dll, \ LIBS_unix := -ljvm -ljava $(LIBM), \ LIBS_linux := $(LIBDL), \ + LIBS_solaris := $(LIBDL), \ LIBS_aix := $(LIBDL),\ LIBS_macosx := -lmlib_image \ -framework Cocoa \ @@ -395,6 +396,7 @@ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LIBS_unix := -lawt -ljvm -ljava, \ LIBS_linux := $(LIBM) $(LIBDL), \ + LIBS_solaris := $(LIBM) $(LIBDL) $(LIBCXX), \ )) $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT) @@ -454,7 +456,7 @@ -DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H \ -DHB_NO_PRAGMA_GCC_DIAGNOSTIC endif - ifeq ($(call isTargetOs, linux macosx), true) + ifeq ($(call isTargetOs, solaris linux macosx), true) HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHB_NO_VISIBILITY endif @@ -623,7 +625,10 @@ ifeq ($(call isTargetOs, macosx), true) JAWT_LIBS := -lawt_lwawt else - JAWT_LIBS := -lawt + JAWT_LIBS := + ifeq ($(call isTargetOs, solaris), false) + JAWT_LIBS += -lawt + endif ifeq ($(ENABLE_HEADLESS_ONLY), false) JAWT_LIBS += -lawt_xawt else @@ -650,6 +655,7 @@ LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \ LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \ LIBS_unix := $(JAWT_LIBS) $(JDKLIB_LIBS), \ + LIBS_solaris := $(X_LIBS) -lXrender, \ LIBS_macosx := -framework Cocoa, \ )) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.desktop/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.desktop/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.desktop/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.desktop/Lib.gmk 2024-01-27 14:37:30.233426840 +0100 @@ -47,10 +47,15 @@ -DX_PLATFORM=X_$(OPENJDK_TARGET_OS_UPPERCASE) \ -DUSE_PORTS=TRUE \ -DUSE_DAUDIO=TRUE \ - -DUSE_PLATFORM_MIDI_OUT=TRUE \ - -DUSE_PLATFORM_MIDI_IN=TRUE \ # + ifeq ($(call isTargetOs, solaris), false) + LIBJSOUND_CFLAGS += \ + -DUSE_PLATFORM_MIDI_OUT=TRUE \ + -DUSE_PLATFORM_MIDI_IN=TRUE \ + # + endif + ifeq ($(call isTargetOs, macosx), true) LIBJSOUND_TOOLCHAIN := TOOLCHAIN_LINK_CXX endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.instrument/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.instrument/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.instrument/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.instrument/Lib.gmk 2024-01-27 14:37:30.234469008 +0100 @@ -44,11 +44,13 @@ $(call SET_SHARED_LIBRARY_ORIGIN) \ $(LIBINSTRUMENT_LDFLAGS), \ LDFLAGS_linux := -L$(call FindLibDirForModule, java.base), \ + LDFLAGS_solaris := -L$(call FindLibDirForModule, java.base), \ LDFLAGS_macosx := -L$(call FindLibDirForModule, java.base), \ LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \ LIBS := $(JDKLIB_LIBS), \ LIBS_unix := -ljava -ljvm $(LIBZ_LIBS), \ LIBS_linux := -ljli $(LIBDL), \ + LIBS_solaris := -ljli $(LIBDL), \ LIBS_aix := -liconv -ljli_static $(LIBDL), \ LIBS_macosx := -ljli -liconv -framework Cocoa -framework Security \ -framework ApplicationServices, \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.management/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.management/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.management/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.management/Lib.gmk 2024-01-27 14:37:30.234878792 +0100 @@ -28,7 +28,7 @@ ################################################################################ LIBMANAGEMENT_OPTIMIZATION := HIGH -ifeq ($(call isTargetOs, linux), true) +ifeq ($(call isTargetOs, solaris linux), true) ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true) LIBMANAGEMENT_OPTIMIZATION := LOW endif @@ -41,6 +41,7 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(JDKLIB_LIBS), \ + LIBS_solaris := -lkstat, \ LIBS_aix := -lperfstat,\ LIBS_windows := jvm.lib psapi.lib $(WIN_JAVA_LIB) advapi32.lib, \ )) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/java.prefs/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/java.prefs/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/java.prefs/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/java.prefs/Lib.gmk 2024-01-27 14:37:30.235254942 +0100 @@ -41,6 +41,7 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := -ljvm, \ LIBS_linux := -ljava, \ + LIBS_solaris := -ljava, \ LIBS_aix := -ljava, \ LIBS_macosx := -framework CoreFoundation -framework Foundation, \ LIBS_windows := advapi32.lib jvm.lib $(WIN_JAVA_LIB), \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.attach/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/jdk.attach/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.attach/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/jdk.attach/Lib.gmk 2024-01-27 14:37:30.235597729 +0100 @@ -42,6 +42,7 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(JDKLIB_LIBS), \ + LIBS_solaris := -ldoor, \ LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib psapi.lib, \ )) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.crypto.cryptoki/Copy.gmk jdk21u-jdk-21.0.2-ga/make/modules/jdk.crypto.cryptoki/Copy.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.crypto.cryptoki/Copy.gmk 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/jdk.crypto.cryptoki/Copy.gmk 2024-01-27 14:37:30.284522116 +0100 @@ -0,0 +1,45 @@ +# +# Copyright (c) 2014, 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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 CopyCommon.gmk + +################################################################################ + +ifeq ($(call isTargetOs, solaris), true) + + SUNPKCS11_CFG_SRC := \ + $(TOPDIR)/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg + SUNPKCS11_CFG_DST := $(CONF_DST_DIR)/security/sunpkcs11-solaris.cfg + + $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC) + $(call install-file) + + SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST) + + TARGETS := $(SUNPKCS11_CFG_DST) + +endif + +################################################################################ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.hotspot.agent/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/jdk.hotspot.agent/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.hotspot.agent/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/jdk.hotspot.agent/Lib.gmk 2024-01-27 14:37:30.235984694 +0100 @@ -67,10 +67,11 @@ CFLAGS := $(CFLAGS_JDKLIB) $(SA_CFLAGS), \ CXXFLAGS := $(CXXFLAGS_JDKLIB) $(SA_CFLAGS) $(SA_CXXFLAGS), \ EXTRA_SRC := $(LIBSA_EXTRA_SRC), \ - LDFLAGS := $(LDFLAGS_JDKLIB) $(call SET_SHARED_LIBRARY_ORIGIN), \ + LDFLAGS := $(LDFLAGS_JDKLIB) $(SA_LDFLAGS) $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(LIBCXX), \ LIBS_unix := -ljava, \ LIBS_linux := $(LIBDL), \ + LIBS_solaris := -ldl -lstdc++ -lthread -lproc, \ LIBS_macosx := -framework Foundation \ -framework JavaRuntimeSupport -framework Security -framework CoreFoundation, \ LIBS_windows := dbgeng.lib $(WIN_JAVA_LIB), \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.jdwp.agent/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/jdk.jdwp.agent/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.jdwp.agent/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/jdk.jdwp.agent/Lib.gmk 2024-01-27 14:37:30.236387365 +0100 @@ -38,6 +38,7 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_linux := -lpthread, \ + LIBS_solaris := -lnsl -lsocket, \ LIBS_windows := $(JDKLIB_LIBS) ws2_32.lib iphlpapi.lib, \ )) @@ -65,6 +66,7 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(JDKLIB_LIBS), \ LIBS_linux := $(LIBDL), \ + LIBS_solaris := $(LIBDL), \ LIBS_macosx := -liconv, \ LIBS_aix := -liconv, \ )) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.management/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/jdk.management/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.management/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/jdk.management/Lib.gmk 2024-01-27 14:37:30.236788170 +0100 @@ -35,7 +35,7 @@ endif LIBMANAGEMENT_EXT_OPTIMIZATION := HIGH -ifeq ($(call isTargetOs, linux), true) +ifeq ($(call isTargetOs, solaris linux), true) ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true) LIBMANAGEMENT_EXT_OPTIMIZATION := LOW endif @@ -48,6 +48,7 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS := $(JDKLIB_LIBS), \ + LIBS_solaris := -lkstat, \ LIBS_aix := -lperfstat,\ LIBS_windows := jvm.lib psapi.lib $(WIN_JAVA_LIB) advapi32.lib, \ )) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.net/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/jdk.net/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.net/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/jdk.net/Lib.gmk 2024-01-27 14:37:30.237143671 +0100 @@ -36,6 +36,7 @@ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := -ljava, \ + LIBS_solaris := -lsocket, \ LIBS_linux := -ljvm, \ LIBS_windows := jvm.lib ws2_32.lib $(WIN_JAVA_LIB), \ )) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.sctp/Lib.gmk jdk21u-jdk-21.0.2-ga/make/modules/jdk.sctp/Lib.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/modules/jdk.sctp/Lib.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/modules/jdk.sctp/Lib.gmk 2024-01-27 14:37:30.237487238 +0100 @@ -42,6 +42,7 @@ $(call SET_SHARED_LIBRARY_ORIGIN), \ LIBS_unix := -lnio -lnet -ljava -ljvm, \ LIBS_linux := -lpthread $(LIBDL), \ + LIBS_solaris := -lsocket, \ )) TARGETS += $(BUILD_LIBSCTP) diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/RunTestsPrebuilt.gmk jdk21u-jdk-21.0.2-ga/make/RunTestsPrebuilt.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/RunTestsPrebuilt.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/RunTestsPrebuilt.gmk 2024-01-27 14:37:30.221277013 +0100 @@ -168,6 +168,8 @@ OPENJDK_TARGET_OS := linux else ifeq ($(UNAME_OS), Darwin) OPENJDK_TARGET_OS := macosx + else ifeq ($(UNAME_OS), SunOS) + OPENJDK_TARGET_OS := solaris else OPENJDK_TARGET_OS := $(UNAME_OS) endif @@ -180,15 +182,28 @@ # Assume little endian unless otherwise specified OPENJDK_TARGET_CPU_ENDIAN := little -UNAME_CPU := $(shell $(UNAME) -m) -ifeq ($(UNAME_CPU), i686) - OPENJDK_TARGET_CPU := x86 - OPENJDK_TARGET_CPU_BITS := 32 -else - # Assume all others are 64-bit. We use the same CPU name as uname for - # at least x86_64 and aarch64. - OPENJDK_TARGET_CPU := $(UNAME_CPU) +ifeq ($(OPENJDK_TARGET_OS), solaris) + # On solaris, use uname -p + UNAME_CPU := $(shell $(UNAME) -p) + # Assume 64-bit platform OPENJDK_TARGET_CPU_BITS := 64 + ifeq ($(UNAME_CPU), i386) + OPENJDK_TARGET_CPU := x86_64 + else + OPENJDK_TARGET_CPU := $(UNAME_CPU) + endif +else + # ... all others use uname -m + UNAME_CPU := $(shell $(UNAME) -m) + ifeq ($(UNAME_CPU), i686) + OPENJDK_TARGET_CPU := x86 + OPENJDK_TARGET_CPU_BITS := 32 + else + # Assume all others are 64-bit. We use the same CPU name as uname for + # at least x86_64 and aarch64. + OPENJDK_TARGET_CPU := $(UNAME_CPU) + OPENJDK_TARGET_CPU_BITS := 64 + endif endif OPENJDK_TARGET_CPU_ARCH := $(OPENJDK_TARGET_CPU) @@ -213,6 +228,11 @@ else ifeq ($(OPENJDK_TARGET_OS), macosx) NUM_CORES := $(shell /usr/sbin/sysctl -n hw.ncpu) MEMORY_SIZE := $(shell $(EXPR) `/usr/sbin/sysctl -n hw.memsize` / 1024 / 1024) +else ifeq ($(OPENJDK_TARGET_OS), solaris) + NUM_CORES := $(shell /usr/sbin/psrinfo -v | $(GREP) -c on-line) + MEMORY_SIZE := $(shell \ + /usr/sbin/prtconf 2> /dev/null | $(GREP) "^Memory [Ss]ize" | $(AWK) '{print $$3}' \ + ) else ifeq ($(OPENJDK_TARGET_OS), windows) NUM_CORES := $(NUMBER_OF_PROCESSORS) MEMORY_SIZE := $(shell \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/RunTestsPrebuiltSpec.gmk jdk21u-jdk-21.0.2-ga/make/RunTestsPrebuiltSpec.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/RunTestsPrebuiltSpec.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/RunTestsPrebuiltSpec.gmk 2024-01-27 14:37:30.221632849 +0100 @@ -173,6 +173,16 @@ FILE := file ULIMIT := ulimit +# On Solaris gnu versions of some tools are required. +ifeq ($(OPENJDK_BUILD_OS), solaris) + AWK := gawk + GREP := ggrep + EGREP := ggrep -E + FGREP := grep -F + SED := gsed + TAR := gtar +endif + ifeq ($(OPENJDK_BUILD_OS), windows) PATHTOOL := cygpath endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/scripts/compare_exceptions.sh.incl jdk21u-jdk-21.0.2-ga/make/scripts/compare_exceptions.sh.incl --- jdk21u-jdk-21.0.2-ga.orig/make/scripts/compare_exceptions.sh.incl 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/scripts/compare_exceptions.sh.incl 2024-01-27 14:37:30.238540848 +0100 @@ -45,6 +45,20 @@ ./hotspot/gtest/server/libjvm.so " fi +elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then + SKIP_BIN_DIFF="true" + SKIP_FULLDUMP_DIFF="true" + MAX_KNOWN_DIS_DIFF_SIZE="3000" + SORT_SYMBOLS=" + ./lib/libfontmanager.so + ./lib/libjimage.so + ./lib/server/libjvm.so + ./hotspot/gtest/server/libjvm.so + " + KNOWN_DIS_DIFF=" + ./lib/libfontmanager.so + " + STRIP_TESTS_BEFORE_COMPARE="true" elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then SKIP_BIN_DIFF="true" SKIP_FULLDUMP_DIFF="true" diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/scripts/compare.sh jdk21u-jdk-21.0.2-ga/make/scripts/compare.sh --- jdk21u-jdk-21.0.2-ga.orig/make/scripts/compare.sh 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/scripts/compare.sh 2024-01-27 14:37:30.238228566 +0100 @@ -73,7 +73,14 @@ # Disassembly diff filters. These filters try to filter out ephemeral parts of the # disassembly, such as hard-coded addresses, to be able to catch "actual" differences. -if [ "$OPENJDK_TARGET_OS" = "windows" ]; then +if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then + if [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then + # Random strings looking like this differ: <.XAKoKoPIac2W0OA. + DIS_DIFF_FILTER="$SED \ + -e 's/<\.[A-Za-z0-9]\{\15}\./<.SYM./' \ + " + fi +elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then if [ "$OPENJDK_TARGET_CPU" = "x86" ]; then DIS_DIFF_FILTER="$SED -r \ -e 's/^ [0-9A-F]{16}: //' \ @@ -440,7 +447,14 @@ fi CONTENTS_DIFF_FILE=$WORK_DIR/$ZIP_FILE.diff - $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE + # On solaris, there is no -q option. + if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then + $DIFF -r $OTHER_UNZIPDIR $THIS_UNZIPDIR \ + | $GREP -v -e "^<" -e "^>" -e "^Common subdirectories:" \ + > $CONTENTS_DIFF_FILE + else + $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE + fi ONLY_OTHER=$($GREP "^Only in $OTHER_UNZIPDIR" $CONTENTS_DIFF_FILE) ONLY_THIS=$($GREP "^Only in $THIS_UNZIPDIR" $CONTENTS_DIFF_FILE) @@ -460,8 +474,14 @@ fi if [ "$CMP_ZIPS_CONTENTS" = "true" ]; then - DIFFING_FILES=$($GREP -e "differ$" $CONTENTS_DIFF_FILE \ - | $CUT -f 2 -d ' ' | $SED "s|$OTHER_UNZIPDIR/||g") + if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then + DIFFING_FILES=$($GREP -e 'differ$' -e '^diff ' $CONTENTS_DIFF_FILE \ + | $SED -e 's/^Files //g' -e 's/diff -r //g' | $CUT -f 1 -d ' ' \ + | $SED "s|$OTHER_UNZIPDIR/||g") + else + DIFFING_FILES=$($GREP -e "differ$" $CONTENTS_DIFF_FILE \ + | $CUT -f 2 -d ' ' | $SED "s|$OTHER_UNZIPDIR/||g") + fi # Separate executable/library files from other files in zip. DIFFING_TEXT_FILES= @@ -806,6 +826,10 @@ # to filter out that extra information. $DUMPBIN -exports $OTHER_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other $DUMPBIN -exports $THIS_FILE | $GREP -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this + elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then + # Some symbols get seemingly random 15 character prefixes. Filter them out. + $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other + $NM -a $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this elif [ "$OPENJDK_TARGET_OS" = "aix" ]; then $OBJDUMP -T $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other $OBJDUMP -T $ORIG_THIS_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/scripts/hide_important_warnings_from_javac.sh jdk21u-jdk-21.0.2-ga/make/scripts/hide_important_warnings_from_javac.sh --- jdk21u-jdk-21.0.2-ga.orig/make/scripts/hide_important_warnings_from_javac.sh 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/scripts/hide_important_warnings_from_javac.sh 2024-01-27 14:37:30.238853586 +0100 @@ -22,8 +22,13 @@ # questions. # -GREP=grep - +if [ -x /usr/bin/ggrep ] ; then + # Gnu grep on Solaris + # (reference configure and build/solaris-i586-clientANDserver-release/spec.gmk + GREP=/usr/bin/ggrep +else + GREP=grep +fi # EXP="Note: Some input files use or override a deprecated API." EXP="${EXP}|Note: Recompile with -Xlint:deprecation for details." diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/test/JtregNativeHotspot.gmk jdk21u-jdk-21.0.2-ga/make/test/JtregNativeHotspot.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/test/JtregNativeHotspot.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/test/JtregNativeHotspot.gmk 2024-01-27 14:37:30.239563753 +0100 @@ -865,6 +865,10 @@ BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exesigtest := -ljvm +ifeq ($(call isTargetOs, solaris), true) + BUILD_HOTSPOT_JTREG_EXCLUDE += libterminatedThread.c +endif + ifeq ($(call isTargetOs, windows), true) BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c libCompleteExit.c libTestPsig.c libnativeStack.c exeGetCreatedJavaVMs.c diff -Nru jdk21u-jdk-21.0.2-ga.orig/make/test/JtregNativeJdk.gmk jdk21u-jdk-21.0.2-ga/make/test/JtregNativeJdk.gmk --- jdk21u-jdk-21.0.2-ga.orig/make/test/JtregNativeJdk.gmk 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/make/test/JtregNativeJdk.gmk 2024-01-27 14:37:30.239894654 +0100 @@ -107,6 +107,9 @@ ifeq ($(call isTargetOs, linux), true) BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -ldl + else ifeq ($(call isTargetOs, solaris), true) + BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava -lsocket -lnsl + BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -lthread -ldl endif BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := -ljli BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := -ljvm diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/cpu/x86/globalDefinitions_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/cpu/x86/globalDefinitions_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/cpu/x86/globalDefinitions_x86.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/cpu/x86/globalDefinitions_x86.hpp 2024-01-27 14:37:30.240355653 +0100 @@ -67,7 +67,7 @@ #define INCLUDE_RTM_OPT 1 #endif -#if defined(LINUX) || defined(__APPLE__) +#if defined(LINUX) || defined(SOLARIS) || defined(__APPLE__) #define SUPPORT_RESERVED_STACK_AREA #endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/include/jvm_md.h jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/include/jvm_md.h --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/include/jvm_md.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/include/jvm_md.h 2024-01-27 14:37:30.240764929 +0100 @@ -54,7 +54,7 @@ #endif #define JNI_LIB_NAME(NAME) JNI_LIB_PREFIX NAME JNI_LIB_SUFFIX -#if defined(AIX) +#if defined(AIX) || defined(SOLARIS) #define JVM_MAXPATHLEN MAXPATHLEN #else // Hack: MAXPATHLEN is 4095 on some Linux and 4096 on others. This may @@ -87,8 +87,14 @@ #define JVM_SIGTERM SIGTERM #define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */ +#ifdef SOLARIS +#define ASYNC_SIGNAL SIGJVM2 /* Event-based suspend/resume support */ +#endif // SOLARIS #define SHUTDOWN1_SIGNAL SIGHUP /* Shutdown Hooks support. */ #define SHUTDOWN2_SIGNAL SIGINT #define SHUTDOWN3_SIGNAL SIGTERM +/* With 1.4.1 libjsig added versioning: used in os_solaris.cpp and jsig.c */ +#define JSIG_VERSION_1_4_1 0x30140100 + #endif /* !_JAVASOFT_JVM_MD_H_ */ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/os_posix.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/os_posix.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/os_posix.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/os_posix.cpp 2024-01-27 14:37:30.241453453 +0100 @@ -504,7 +504,7 @@ st->print("%d", sysconf(_SC_CHILD_MAX)); print_rlimit(st, ", THREADS", RLIMIT_THREADS); -#else +#elif !defined(SOLARIS) print_rlimit(st, ", NPROC", RLIMIT_NPROC); #endif @@ -522,6 +522,12 @@ print_rlimit(st, ", MEMLOCK", RLIMIT_MEMLOCK, true); #endif +#if defined(SOLARIS) + // maximum size of mapped address space of a process in bytes; + // if the limit is exceeded, mmap and brk fail + print_rlimit(st, ", VMEM", RLIMIT_VMEM, true); +#endif + // 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); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/os_posix.inline.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/os_posix.inline.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/os_posix.inline.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/os_posix.inline.hpp 2024-01-27 14:37:30.241763862 +0100 @@ -34,8 +34,10 @@ #include #include +#ifndef SOLARIS // Aix does not have NUMA support but need these for compilation. inline bool os::numa_has_group_homing() { AIX_ONLY(ShouldNotReachHere();) return false; } +#endif // !SOLARIS // Platform Mutex/Monitor implementation diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/vmError_posix.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/vmError_posix.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/posix/vmError_posix.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/posix/vmError_posix.cpp 2024-01-27 14:37:30.242073659 +0100 @@ -40,6 +40,9 @@ #include #include #endif +#ifdef SOLARIS +#include +#endif #ifdef AIX #include #endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/attachListener_solaris.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/attachListener_solaris.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/attachListener_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/attachListener_solaris.cpp 2024-01-27 14:37:30.285119239 +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 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)", 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(); +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/c1_globals_solaris.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/c1_globals_solaris.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/c1_globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/c1_globals_solaris.hpp 2024-01-27 14:37:30.285353720 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/c2_globals_solaris.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/c2_globals_solaris.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/c2_globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/c2_globals_solaris.hpp 2024-01-27 14:37:30.285584537 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/decoder_solaris.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/decoder_solaris.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/decoder_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/decoder_solaris.cpp 2024-01-27 14:37:30.285817665 +0100 @@ -0,0 +1,32 @@ +/* + * 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); +} + diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/dtrace/jhelper.d jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/dtrace/jhelper.d --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/dtrace/jhelper.d 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/dtrace/jhelper.d 2024-01-27 14:37:30.286643311 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/globals_solaris.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/globals_solaris.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/globals_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/globals_solaris.hpp 2024-01-27 14:37:30.286893903 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_perf_solaris.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_perf_solaris.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_perf_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_perf_solaris.cpp 2024-01-27 14:37:30.287919862 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_solaris.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_solaris.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_solaris.cpp 2024-01-27 14:37:30.289827857 +0100 @@ -0,0 +1,3129 @@ +/* + * 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; + +// Track if we have called enable_extended_FILE_stdio (on Solaris 10u4+) +static bool enabled_extended_FILE_stdio = false; + +// 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 accomodate 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 +} + +void os::breakpoint() { + BREAKPOINT; +} + +extern "C" void breakpoint() { + // use debugger to set breakpoint here +} + +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 started (tid: " UINTX_FORMAT ", attributes: %s). ", + (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags)); + } else { + log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.", + 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; +} + +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; +} + +// Used to convert frequent JVM_Yield() to nops +bool os::dont_yield() { + if (DontYieldALot) { + static hrtime_t last_time = 0; + hrtime_t diff = getTimeNanos() - last_time; + + if (diff < DontYieldALotInterval * 1000000) { + return true; + } + + last_time += diff; + + return false; + } else { + return false; + } +} + +// Note that yield semantics are defined by the scheduling class to which +// the thread currently belongs. Typically, yield will _not yield to +// other equal or higher priority threads that reside on the dispatch queues +// of other CPUs. + +void os::naked_yield() { + thr_yield(); +} + +// 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 priotities +// 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 in 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(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; + } + } + + // 32-bit Solaris systems suffer from: + // + // - an historical default soft limit of 256 per-process file + // descriptors that is too low for many Java programs. + // + // - a design flaw where file descriptors created using stdio + // fopen must be less than 256, _even_ when the first limit above + // has been raised. This can cause calls to fopen (but not calls to + // open, for example) to fail mysteriously, perhaps in 3rd party + // native code (although the JDK itself uses fopen). One can hardly + // criticize them for using this most standard of all functions. + // + // We attempt to make everything work anyways by: + // + // - raising the soft limit on per-process file descriptors beyond + // 256 + // + // - As of Solaris 10u4, we can request that Solaris raise the 256 + // stdio fopen limit by calling function enable_extended_FILE_stdio. + // This is done in init_2 and recorded in enabled_extended_FILE_stdio + // + // - If we are stuck on an old (pre 10u4) Solaris system, we can + // workaround the bug by remapping non-stdio file descriptors below + // 256 to ones beyond 256, which is done below. + // + // See: + // 1085341: 32-bit stdio routines should support file descriptors >255 + // 6533291: Work around 32-bit Solaris stdio limit of 256 open files + // 6431278: Netbeans crash on 32 bit Solaris: need to call + // enable_extended_FILE_stdio() in VM initialisation + // Giri Mandalika's blog + // http://technopark02.blogspot.com/2005_05_01_archive.html + // +#ifndef _LP64 + if ((!enabled_extended_FILE_stdio) && fd < 256) { + int newfd = ::fcntl(fd, F_DUPFD, 256); + if (newfd != -1) { + ::close(fd); + fd = newfd; + } + } +#endif // 32-bit Solaris + + // 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 diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_solaris.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_solaris.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_solaris.hpp 2024-01-27 14:37:30.290167827 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_solaris.inline.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_solaris.inline.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/os_solaris.inline.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/os_solaris.inline.hpp 2024-01-27 14:37:30.290462647 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/osThread_solaris.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/osThread_solaris.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/osThread_solaris.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/osThread_solaris.cpp 2024-01-27 14:37:30.287133736 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/osThread_solaris.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/osThread_solaris.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/osThread_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/osThread_solaris.hpp 2024-01-27 14:37:30.287397750 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/vmStructs_solaris.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/vmStructs_solaris.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os/solaris/vmStructs_solaris.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os/solaris/vmStructs_solaris.hpp 2024-01-27 14:37:30.290708195 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp 2024-01-27 14:37:30.291028282 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp 2024-01-27 14:37:30.291339980 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp 2024-01-27 14:37:30.291582989 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp 2024-01-27 14:37:30.291811352 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp 2024-01-27 14:37:30.292060423 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.cpp 2024-01-27 14:37:30.294246303 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/javaThread_solaris_x86.hpp 2024-01-27 14:37:30.294488725 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp 2024-01-27 14:37:30.292309763 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp 2024-01-27 14:37:30.292862580 +0100 @@ -0,0 +1,662 @@ +/* + * 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(); +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp 2024-01-27 14:37:30.293110184 +0100 @@ -0,0 +1,55 @@ +/* + * 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 diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp 2024-01-27 14:37:30.293342346 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp 2024-01-27 14:37:30.293580195 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S 2024-01-27 14:37:30.293987160 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp 2024-01-27 14:37:30.294960795 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp 2024-01-27 14:37:30.294730223 +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 -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/c1/c1_LIR.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/c1/c1_LIR.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/c1/c1_LIR.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/c1/c1_LIR.cpp 2024-01-27 14:37:30.242841158 +0100 @@ -446,6 +446,8 @@ case lir_monaddr: // input and result always valid, info always invalid case lir_null_check: // input and info always valid, result always invalid case lir_move: // input and result always valid, may have info + case lir_pack64: // input and result always valid + case lir_unpack64: // input and result always valid { assert(op->as_Op1() != nullptr, "must be"); LIR_Op1* op1 = (LIR_Op1*)op; @@ -1726,6 +1728,8 @@ case lir_convert: s = "convert"; break; case lir_alloc_object: s = "alloc_obj"; break; case lir_monaddr: s = "mon_addr"; break; + case lir_pack64: s = "pack64"; break; + case lir_unpack64: s = "unpack64"; break; // LIR_Op2 case lir_cmp: s = "cmp"; break; case lir_cmp_l2i: s = "cmp_l2i"; break; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/c1/c1_LIR.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/c1/c1_LIR.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/c1/c1_LIR.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/c1/c1_LIR.hpp 2024-01-27 14:37:30.243630237 +0100 @@ -939,6 +939,8 @@ , lir_monaddr , lir_roundfp , lir_safepoint + , lir_pack64 + , lir_unpack64 , lir_unwind , lir_load_klass , end_op1 @@ -2234,6 +2236,9 @@ void logical_or (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_or, left, right, dst)); } void logical_xor (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_xor, left, right, dst)); } + void pack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_pack64, src, dst, T_LONG, lir_patch_none, NULL)); } + void unpack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_unpack64, src, dst, T_LONG, lir_patch_none, NULL)); } + void null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null = false); void throw_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) { append(new LIR_Op2(lir_throw, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info)); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/cds/classListParser.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/cds/classListParser.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/cds/classListParser.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/cds/classListParser.cpp 2024-01-27 14:37:30.244115606 +0100 @@ -452,7 +452,7 @@ // This function is used for loading classes for customized class loaders // during archive dumping. InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS) { -#if !(defined(_LP64) && (defined(LINUX) || defined(__APPLE__) || defined(_WINDOWS))) +#if !(defined(_LP64) && (defined(LINUX)|| defined(SOLARIS) || defined(__APPLE__) || defined(_WINDOWS))) // The only supported platforms are: (1) Linux/64-bit and (2) Solaris/64-bit and // (3) MacOSX/64-bit and (4) Windowss/64-bit // This #if condition should be in sync with the areCustomLoadersSupportedForCDS diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/runtime/abstract_vm_version.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/runtime/abstract_vm_version.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/runtime/abstract_vm_version.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/runtime/abstract_vm_version.cpp 2024-01-27 14:37:30.244655390 +0100 @@ -167,6 +167,7 @@ #define OS LINUX_ONLY("linux") \ WINDOWS_ONLY("windows") \ + SOLARIS_ONLY("solaris") \ AIX_ONLY("aix") \ BSD_ONLY("bsd") diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/runtime/globals.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/runtime/globals.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/runtime/globals.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/runtime/globals.hpp 2024-01-27 14:37:30.245770044 +0100 @@ -1589,8 +1589,10 @@ product(int, ThreadPriorityPolicy, 0, \ "0 : Normal. "\ " VM chooses priorities that are appropriate for normal "\ - " applications. "\ - " On Windows applications are allowed to use higher native "\ + " applications. On Solaris NORM_PRIORITY and above are mapped "\ + " to normal native priority. Java priorities below " \ + " NORM_PRIORITY map to lower native priority values. On "\ + " Windows applications are allowed to use higher native "\ " priorities. However, with ThreadPriorityPolicy=0, VM will "\ " not use the highest possible native priority, "\ " THREAD_PRIORITY_TIME_CRITICAL, as it may interfere with "\ @@ -1872,7 +1874,8 @@ product(bool, WhiteBoxAPI, false, DIAGNOSTIC, \ "Enable internal testing APIs") \ \ - product(size_t, ArrayAllocatorMallocLimit, SIZE_MAX, EXPERIMENTAL, \ + product(size_t, ArrayAllocatorMallocLimit, \ + SOLARIS_ONLY(64*K) NOT_SOLARIS(SIZE_MAX), EXPERIMENTAL, \ "Allocation less than this value will be allocated " \ "using malloc. Larger allocations will use mmap.") \ \ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/runtime/semaphore.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/runtime/semaphore.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/runtime/semaphore.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/runtime/semaphore.hpp 2024-01-27 14:37:30.246111744 +0100 @@ -28,7 +28,7 @@ #include "memory/allocation.hpp" #include "utilities/globalDefinitions.hpp" -#if defined(LINUX) || defined(AIX) +#if defined(LINUX) || defined(SOLARIS) || defined(AIX) # include "semaphore_posix.hpp" #else # include OS_HEADER(semaphore) diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/services/dtraceAttacher.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/services/dtraceAttacher.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/services/dtraceAttacher.cpp 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/services/dtraceAttacher.cpp 2024-01-27 14:37:30.295233484 +0100 @@ -0,0 +1,99 @@ +/* + * 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 "code/codeCache.hpp" +#include "memory/resourceArea.hpp" +#include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" +#include "runtime/vmThread.hpp" +#include "runtime/vmOperations.hpp" +#include "services/dtraceAttacher.hpp" +#include "runtime/flags/jvmFlagAccess.hpp" + +#ifdef SOLARIS + +static void set_bool_flag(const char* name, bool value) { + JVMFlag* flag = JVMFlag::find_flag(name); + JVMFlagAccess::set_bool(flag, &value, JVMFlagOrigin::ATTACH_ON_DEMAND); +} + +// Enable the "fine grained" flags. +void DTrace::enable_dprobes(int probes) { + bool changed = false; + if (!DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) { + set_bool_flag("DTraceAllocProbes", true); + changed = true; + } + if (!DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) { + set_bool_flag("DTraceMethodProbes", true); + changed = true; + } + if (!DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) { + set_bool_flag("DTraceMonitorProbes", true); + changed = true; + } + + if (changed) { + // one or more flags changed, need to deoptimize + DeoptimizationScope deopt_scope; + CodeCache::mark_all_nmethods_for_deoptimization(&deopt_scope); + deopt_scope.deoptimize_marked(); + } +} + +// Disable the "fine grained" flags. +void DTrace::disable_dprobes(int probes) { + bool changed = false; + if (DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) { + set_bool_flag("DTraceAllocProbes", false); + changed = true; + } + if (DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) { + set_bool_flag("DTraceMethodProbes", false); + changed = true; + } + if (DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) { + set_bool_flag("DTraceMonitorProbes", false); + changed = true; + } + if (changed) { + // one or more flags changed, need to deoptimize + DeoptimizationScope deopt_scope; + CodeCache::mark_all_nmethods_for_deoptimization(&deopt_scope); + deopt_scope.deoptimize_marked(); + } +} + +// Do clean-up on "all door clients detached" event. +void DTrace::detach_all_clients() { + disable_dprobes(DTRACE_ALL_PROBES); +} + +void DTrace::set_monitor_dprobes(bool flag) { + // explicit setting of DTraceMonitorProbes flag + set_bool_flag("DTraceMonitorProbes", flag); +} + +#endif /* SOLARIS */ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/services/memTracker.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/services/memTracker.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/services/memTracker.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/services/memTracker.cpp 2024-01-27 14:37:30.246500011 +0100 @@ -48,6 +48,12 @@ #include #endif +#ifdef SOLARIS + volatile bool NMT_stack_walkable = false; +#else + volatile bool NMT_stack_walkable = true; +#endif + NMT_TrackingLevel MemTracker::_tracking_level = NMT_unknown; MemBaseline MemTracker::_baseline; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/services/memTracker.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/services/memTracker.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/services/memTracker.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/services/memTracker.hpp 2024-01-27 14:37:30.246851915 +0100 @@ -34,9 +34,11 @@ #include "utilities/debug.hpp" #include "utilities/nativeCallStack.hpp" -#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail) ? \ +extern volatile bool NMT_stack_walkable; + +#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \ NativeCallStack(0) : FAKE_CALLSTACK) -#define CALLER_PC ((MemTracker::tracking_level() == NMT_detail) ? \ +#define CALLER_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \ NativeCallStack(1) : FAKE_CALLSTACK) class MemBaseline; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/debug.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/debug.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/debug.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/debug.cpp 2024-01-27 14:37:30.247391425 +0100 @@ -612,11 +612,12 @@ tty->print_cr(" findm(intptr_t pc) - finds Method*"); tty->print_cr(" find(intptr_t x) - finds & prints nmethod/stub/bytecode/oop based on pointer into it"); tty->print_cr(" pns(void* sp, void* fp, void* pc) - print native (i.e. mixed) stack trace. E.g."); - tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 or"); + tty->print_cr(" pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or"); tty->print_cr(" pns($sp, $ebp, $pc) on Linux/x86 or"); tty->print_cr(" pns($sp, $fp, $pc) on Linux/AArch64 or"); tty->print_cr(" pns($sp, 0, $pc) on Linux/ppc64 or"); tty->print_cr(" pns($sp, $s8, $pc) on Linux/mips or"); + tty->print_cr(" pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC"); tty->print_cr(" - in gdb do 'set overload-resolution off' before calling pns()"); tty->print_cr(" - in dbx do 'frame 1' before calling pns()"); tty->print_cr("class metadata."); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/globalDefinitions_gcc.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/globalDefinitions_gcc.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/globalDefinitions_gcc.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/globalDefinitions_gcc.hpp 2024-01-27 14:37:30.247888940 +0100 @@ -39,15 +39,36 @@ #include #include +#ifdef SOLARIS +#include +#endif // SOLARIS + #include #include #include #include #include +#ifdef SOLARIS +#include +#endif // SOLARIS + #include #include +#ifdef SOLARIS +#include +#include +#include +#include +#include +#include +#endif // SOLARIS + +# ifdef SOLARIS_MUTATOR_LIBTHREAD +# include +# endif + #if defined(LINUX) || defined(_ALLBSD_SOURCE) #include #include @@ -61,6 +82,34 @@ #include #endif // LINUX || _ALLBSD_SOURCE +// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures +// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in +// system header files. On 32-bit architectures, there is no problem. +// On 64-bit architectures, defining NULL as a 32-bit constant can cause +// problems with varargs functions: C++ integral promotion rules say for +// varargs, we pass the argument 0 as an int. So, if NULL was passed to a +// varargs function it will remain 32-bits. Depending on the calling +// convention of the machine, if the argument is passed on the stack then +// only 32-bits of the "NULL" pointer may be initialized to zero. The +// other 32-bits will be garbage. If the varargs function is expecting a +// pointer when it extracts the argument, then we have a problem. +// +// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0. +// +// Note: this fix doesn't work well on Linux because NULL will be overwritten +// whenever a system header file is included. Linux handles NULL correctly +// through a special type '__null'. +#ifdef SOLARIS + #ifdef _LP64 + #undef NULL + #define NULL 0L + #else + #ifndef NULL + #define NULL 0 + #endif + #endif +#endif + // NULL vs NULL_WORD: // On Linux NULL is defined as a special type '__null'. Assigning __null to // integer variable will cause gcc warning. Use NULL_WORD in places where a @@ -101,8 +150,52 @@ #endif // !LINUX && !_ALLBSD_SOURCE + +#ifdef SOLARIS +// ANSI C++ fixes +// NOTE:In the ANSI committee's continuing attempt to make each version +// of C++ incompatible with the previous version, you can no longer cast +// pointers to functions without specifying linkage unless you want to get +// warnings. +// +// This also means that pointers to functions can no longer be "hidden" +// in opaque types like void * because at the invokation point warnings +// will be generated. While this makes perfect sense from a type safety +// point of view it causes a lot of warnings on old code using C header +// files. Here are some typedefs to make the job of silencing warnings +// a bit easier. +// +// The final kick in the teeth is that you can only have extern "C" linkage +// specified at file scope. So these typedefs are here rather than in the +// .hpp for the class (os:Solaris usually) that needs them. + +extern "C" { + typedef int (*int_fnP_thread_t_iP_uP_stack_tP_gregset_t)(thread_t, int*, unsigned *, stack_t*, gregset_t); + typedef int (*int_fnP_thread_t_i_gregset_t)(thread_t, int, gregset_t); + typedef int (*int_fnP_thread_t_i)(thread_t, int); + typedef int (*int_fnP_thread_t)(thread_t); + + typedef int (*int_fnP_cond_tP_mutex_tP_timestruc_tP)(cond_t *cv, mutex_t *mx, timestruc_t *abst); + typedef int (*int_fnP_cond_tP_mutex_tP)(cond_t *cv, mutex_t *mx); + + // typedef for missing API in libc + typedef int (*int_fnP_mutex_tP_i_vP)(mutex_t *, int, void *); + typedef int (*int_fnP_mutex_tP)(mutex_t *); + typedef int (*int_fnP_cond_tP_i_vP)(cond_t *cv, int scope, void *arg); + typedef int (*int_fnP_cond_tP)(cond_t *cv); +}; +#endif // SOLARIS + // checking for nanness -#if defined(__APPLE__) +#ifdef SOLARIS +#ifdef SPARC +inline int g_isnan(float f) { return isnanf(f); } +#else +// isnanf() broken on Intel Solaris use isnand() +inline int g_isnan(float f) { return isnand(f); } +#endif +inline int g_isnan(double f) { return isnand(f); } +#elif defined(__APPLE__) inline int g_isnan(double f) { return isnan(f); } #elif defined(LINUX) || defined(_ALLBSD_SOURCE) inline int g_isnan(float f) { return isnan(f); } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/macros.hpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/macros.hpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/macros.hpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/macros.hpp 2024-01-27 14:37:30.248271340 +0100 @@ -401,6 +401,14 @@ #define NOT_AIX(code) code #endif +#ifdef SOLARIS +#define SOLARIS_ONLY(code) code +#define NOT_SOLARIS(code) +#else +#define SOLARIS_ONLY(code) +#define NOT_SOLARIS(code) code +#endif + #ifdef _WINDOWS #define WINDOWS_ONLY(code) code #define NOT_WINDOWS(code) diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/ostream.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/ostream.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/ostream.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/ostream.cpp 2024-01-27 14:37:30.248745539 +0100 @@ -1082,7 +1082,7 @@ #ifndef PRODUCT -#if defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE) +#if defined(SOLARIS) || defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE) #include #include #include diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/vmError.cpp jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/vmError.cpp --- jdk21u-jdk-21.0.2-ga.orig/src/hotspot/share/utilities/vmError.cpp 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/hotspot/share/utilities/vmError.cpp 2024-01-27 14:37:30.249427159 +0100 @@ -1888,6 +1888,8 @@ out.print_raw ("# Executing "); #if defined(LINUX) || defined(_ALLBSD_SOURCE) out.print_raw ("/bin/sh -c "); +#elif defined(SOLARIS) + out.print_raw ("/usr/bin/sh -c "); #elif defined(_WINDOWS) out.print_raw ("cmd /C "); #endif @@ -1952,6 +1954,8 @@ tty->print("# Executing "); #if defined(LINUX) tty->print ("/bin/sh -c "); +#elif defined(SOLARIS) + tty->print ("/usr/bin/sh -c "); #endif tty->print_cr("\"%s\"...", cmd); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/classes/sun/net/sdp/SdpSupport.java jdk21u-jdk-21.0.2-ga/src/java.base/share/classes/sun/net/sdp/SdpSupport.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/classes/sun/net/sdp/SdpSupport.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/share/classes/sun/net/sdp/SdpSupport.java 2024-01-27 14:37:30.249795290 +0100 @@ -39,7 +39,7 @@ */ public final class SdpSupport { - private static final boolean isSupported = OperatingSystem.isLinux(); + private static final boolean isSupported = (OperatingSystem.isSolaris() || OperatingSystem.isLinux()); private static final JavaIOFileDescriptorAccess fdAccess = SharedSecrets.getJavaIOFileDescriptorAccess(); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/classes/sun/nio/ch/Net.java jdk21u-jdk-21.0.2-ga/src/java.base/share/classes/sun/nio/ch/Net.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/classes/sun/nio/ch/Net.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/share/classes/sun/nio/ch/Net.java 2024-01-27 14:37:30.250279871 +0100 @@ -512,7 +512,7 @@ private static native boolean isReusePortAvailable0(); /* - * Returns 1 for Windows and -1 for Linux/Mac OS + * Returns 1 for Windows and -1 for Solaris/Linux/Mac OS */ private static native int isExclusiveBindAvailable(); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template jdk21u-jdk-21.0.2-ga/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template 2024-01-27 14:37:30.250690953 +0100 @@ -43,6 +43,8 @@ #define SO_REUSEPORT 0 #elif defined(__linux__) #define SO_REUSEPORT 15 +#elif defined(__solaris__) +#define SO_REUSEPORT 0x100e #elif defined(AIX) || defined(MACOSX) #define SO_REUSEPORT 0x0200 #else @@ -50,6 +52,10 @@ #endif #endif +/* On Solaris, "sun" is defined as a macro. Undefine to make package + declaration valid */ +#undef sun + /* To be able to name the Java constants the same as the C constants without having the preprocessor rewrite those identifiers, add PREFIX_ to all identifiers matching a C constant. The PREFIX_ is filtered out in the diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/conf/security/java.security jdk21u-jdk-21.0.2-ga/src/java.base/share/conf/security/java.security --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/conf/security/java.security 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/share/conf/security/java.security 2024-01-27 14:37:30.251346073 +0100 @@ -66,6 +66,9 @@ # # List of providers and their preference orders (see above): # +#ifdef solaris +security.provider.tbd=SunPKCS11 ${java.home}/conf/security/sunpkcs11-solaris.cfg +#endif security.provider.tbd=SUN security.provider.tbd=SunRsaSign security.provider.tbd=SunEC @@ -83,7 +86,9 @@ #ifdef macosx security.provider.tbd=Apple #endif +#ifndef solaris security.provider.tbd=SunPKCS11 +#endif # # A list of preferred providers for specific algorithms. These providers will diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/native/libjli/jli_util.h jdk21u-jdk-21.0.2-ga/src/java.base/share/native/libjli/jli_util.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/native/libjli/jli_util.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/share/native/libjli/jli_util.h 2024-01-27 14:37:30.251714179 +0100 @@ -100,6 +100,9 @@ #define JLI_StrCaseCmp(p1, p2) strcasecmp((p1), (p2)) #define JLI_StrNCaseCmp(p1, p2, p3) strncasecmp((p1), (p2), (p3)) #define JLI_Open open +#ifdef __solaris__ +#define JLI_Lseek llseek +#endif #ifdef __linux__ #define _LARGFILE64_SOURCE #define JLI_Lseek lseek64 diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/native/libnet/net_util.c jdk21u-jdk-21.0.2-ga/src/java.base/share/native/libnet/net_util.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/native/libnet/net_util.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/share/native/libnet/net_util.c 2024-01-27 14:37:30.252105372 +0100 @@ -81,6 +81,7 @@ /* check if SO_REUSEPORT is supported on this platform */ REUSEPORT_available = reuseport_supported(IPv6_available); + parseExclusiveBindProperty(env); return JNI_VERSION_1_2; } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/native/libnet/net_util.h jdk21u-jdk-21.0.2-ga/src/java.base/share/native/libnet/net_util.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/share/native/libnet/net_util.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/share/native/libnet/net_util.h 2024-01-27 14:37:30.252441788 +0100 @@ -142,6 +142,8 @@ JNIEXPORT jobject JNICALL NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port); +void parseExclusiveBindProperty(JNIEnv *env); + JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(SOCKETADDRESS *sa); JNIEXPORT jboolean JNICALL diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java 2024-01-27 14:37:30.295677731 +0100 @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; + +/** + * Creates this platform's default AsynchronousChannelProvider + */ + +public class DefaultAsynchronousChannelProvider { + + /** + * Prevent instantiation. + */ + private DefaultAsynchronousChannelProvider() { } + + /** + * Returns the default AsynchronousChannelProvider. + */ + public static AsynchronousChannelProvider create() { + return new SolarisAsynchronousChannelProvider(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java 2024-01-27 14:37:30.295939064 +0100 @@ -0,0 +1,54 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.ch; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * Creates this platform's default SelectorProvider + */ + +@SuppressWarnings("removal") +public class DefaultSelectorProvider { + private static final SelectorProviderImpl INSTANCE; + static { + PrivilegedAction pa = DevPollSelectorProvider::new; + INSTANCE = AccessController.doPrivileged(pa); + } + + /** + * Prevent instantiation. + */ + private DefaultSelectorProvider() { } + + /** + * Returns the default SelectorProvider implementation. + */ + public static SelectorProviderImpl get() { + return INSTANCE; + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java 2024-01-27 14:37:30.296221915 +0100 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2001, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.ch; + +import java.io.IOException; + +/** + * Manipulates a native array of pollfd structs on Solaris: + * + * typedef struct pollfd { + * int fd; + * short events; + * short revents; + * } pollfd_t; + * + * @author Mike McCloskey + * @since 1.4 + */ + +class DevPollArrayWrapper { + + // special event to remove a file descriptor from the driver + static final short POLLREMOVE = 0x0800; + + // struct pollfd constants + static final short SIZE_POLLFD = 8; + static final short FD_OFFSET = 0; + static final short EVENT_OFFSET = 4; + static final short REVENT_OFFSET = 6; + + // maximum number of pollfd structure to poll or update at a time + // dpwrite/ioctl(DP_POLL) allows up to file descriptor limit minus 1 + static final int NUM_POLLFDS = Math.min(IOUtil.fdLimit()-1, 1024); + + // The pollfd array for results from devpoll driver + private final AllocatedNativeObject pollArray; + + // Base address of the native pollArray + private final long pollArrayAddress; + + // The fd of the devpoll driver + private int wfd; + + DevPollArrayWrapper() throws IOException { + this.wfd = init(); + + int allocationSize = NUM_POLLFDS * SIZE_POLLFD; + this.pollArray = new AllocatedNativeObject(allocationSize, true); + this.pollArrayAddress = pollArray.address(); + } + + void close() throws IOException { + FileDispatcherImpl.closeIntFD(wfd); + pollArray.free(); + } + + void register(int fd, int ops) throws IOException { + register(wfd, fd, ops); + } + + void registerMultiple(int numfds) throws IOException { + registerMultiple(wfd, pollArrayAddress, numfds); + } + + int poll(long timeout) throws IOException { + return poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd); + } + + int getDescriptor(int i) { + int offset = SIZE_POLLFD * i + FD_OFFSET; + return pollArray.getInt(offset); + } + + short getEventOps(int i) { + int offset = SIZE_POLLFD * i + EVENT_OFFSET; + return pollArray.getShort(offset); + } + + short getReventOps(int i) { + int offset = SIZE_POLLFD * i + REVENT_OFFSET; + return pollArray.getShort(offset); + } + + /** + * Updates the pollfd structure at the given index + */ + void putPollFD(int index, int fd, short event) { + int structIndex = SIZE_POLLFD * index; + pollArray.putInt(structIndex + FD_OFFSET, fd); + pollArray.putShort(structIndex + EVENT_OFFSET, event); + pollArray.putShort(structIndex + REVENT_OFFSET, (short)0); + } + + private native int init() throws IOException; + private native void register(int wfd, int fd, int mask) throws IOException; + private native void registerMultiple(int wfd, long address, int len) + throws IOException; + private native int poll0(long pollAddress, int numfds, long timeout, int wfd) + throws IOException; + + static { + IOUtil.load(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java 2024-01-27 14:37:30.296558857 +0100 @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2001, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.ch; + +import java.io.IOException; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.SelectorProvider; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import static sun.nio.ch.DevPollArrayWrapper.NUM_POLLFDS; +import static sun.nio.ch.DevPollArrayWrapper.POLLREMOVE; + +/** + * Solaris /dev/poll based Selector implementation + */ + +class DevPollSelectorImpl + extends SelectorImpl +{ + // provides access to /dev/poll driver + private final DevPollArrayWrapper pollWrapper; + + // file descriptors used for interrupt + private final int fd0; + private final int fd1; + + // maps file descriptor to selection key, synchronize on selector + private final Map fdToKey = new HashMap<>(); + + // pending new registrations/updates, queued by setEventOps + private final Object updateLock = new Object(); + private final Deque updateKeys = new ArrayDeque<>(); + + // interrupt triggering and clearing + private final Object interruptLock = new Object(); + private boolean interruptTriggered; + + DevPollSelectorImpl(SelectorProvider sp) throws IOException { + super(sp); + this.pollWrapper = new DevPollArrayWrapper(); + try { + long fds = IOUtil.makePipe(false); + this.fd0 = (int) (fds >>> 32); + this.fd1 = (int) fds; + } catch (IOException ioe) { + pollWrapper.close(); + throw ioe; + } + + // register one end of the socket pair for wakeups + pollWrapper.register(fd0, Net.POLLIN); + } + + private void ensureOpen() { + if (!isOpen()) + throw new ClosedSelectorException(); + } + + @Override + protected int doSelect(Consumer action, long timeout) + throws IOException + { + assert Thread.holdsLock(this); + + long to = timeout; + boolean blocking = (to != 0); + boolean timedPoll = (to > 0); + + int numEntries; + processUpdateQueue(); + processDeregisterQueue(); + try { + begin(blocking); + + do { + long startTime = timedPoll ? System.nanoTime() : 0; + numEntries = pollWrapper.poll(to); + if (numEntries == IOStatus.INTERRUPTED && timedPoll) { + // timed poll interrupted so need to adjust timeout + long adjust = System.nanoTime() - startTime; + to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS); + if (to <= 0) { + // timeout expired so no retry + numEntries = 0; + } + } + } while (numEntries == IOStatus.INTERRUPTED); + assert IOStatus.check(numEntries); + + } finally { + end(blocking); + } + processDeregisterQueue(); + return processEvents(numEntries, action); + } + + /** + * Process changes to the interest ops. + */ + private void processUpdateQueue() throws IOException { + assert Thread.holdsLock(this); + + synchronized (updateLock) { + SelectionKeyImpl ski; + + // Translate the queued updates to changes to the set of monitored + // file descriptors. The changes are written to the /dev/poll driver + // in bulk. + int index = 0; + while ((ski = updateKeys.pollFirst()) != null) { + if (ski.isValid()) { + int fd = ski.getFDVal(); + // add to fdToKey if needed + SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski); + assert (previous == null) || (previous == ski); + + int newEvents = ski.translateInterestOps(); + int registeredEvents = ski.registeredEvents(); + if (newEvents != registeredEvents) { + if (registeredEvents != 0) + pollWrapper.putPollFD(index++, fd, POLLREMOVE); + if (newEvents != 0) + pollWrapper.putPollFD(index++, fd, (short)newEvents); + ski.registeredEvents(newEvents); + + // write to /dev/poll + if (index > (NUM_POLLFDS-2)) { + pollWrapper.registerMultiple(index); + index = 0; + } + } + } + } + + // write any remaining changes + if (index > 0) + pollWrapper.registerMultiple(index); + } + } + + /** + * Process the polled events. + * If the interrupt fd has been selected, drain it and clear the interrupt. + */ + private int processEvents(int numEntries, Consumer action) + throws IOException + { + assert Thread.holdsLock(this); + + boolean interrupted = false; + int numKeysUpdated = 0; + for (int i=0; i fdToKey = new HashMap<>(); + + // the last update operation, incremented by processUpdateQueue + private int lastUpdate; + + // pending new registrations/updates, queued by setEventOps and + // updateSelectedKeys + private final Object updateLock = new Object(); + private final Deque updateKeys = new ArrayDeque<>(); + + // interrupt triggering and clearing + private final Object interruptLock = new Object(); + private boolean interruptTriggered; + + EventPortSelectorImpl(SelectorProvider sp) throws IOException { + super(sp); + + this.pfd = port_create(); + + int allocationSize = MAX_EVENTS * SIZEOF_PORT_EVENT; + this.pollArray = new AllocatedNativeObject(allocationSize, false); + this.pollArrayAddress = pollArray.address(); + } + + private void ensureOpen() { + if (!isOpen()) + throw new ClosedSelectorException(); + } + + @Override + protected int doSelect(Consumer action, long timeout) + throws IOException + { + assert Thread.holdsLock(this); + + long to = timeout; + boolean blocking = (to != 0); + boolean timedPoll = (to > 0); + + int numEvents; + processUpdateQueue(); + processDeregisterQueue(); + try { + begin(blocking); + + do { + long startTime = timedPoll ? System.nanoTime() : 0; + numEvents = port_getn(pfd, pollArrayAddress, MAX_EVENTS, to); + if (numEvents == IOStatus.INTERRUPTED && timedPoll) { + // timed poll interrupted so need to adjust timeout + long adjust = System.nanoTime() - startTime; + to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS); + if (to <= 0) { + // timeout also expired so no retry + numEvents = 0; + } + } + } while (numEvents == IOStatus.INTERRUPTED); + assert IOStatus.check(numEvents); + + } finally { + end(blocking); + } + processDeregisterQueue(); + return processPortEvents(numEvents, action); + } + + /** + * Process new registrations and changes to the interest ops. + */ + private void processUpdateQueue() throws IOException { + assert Thread.holdsLock(this); + + // bump lastUpdate to ensure that the interest ops are changed at most + // once per bulk update + lastUpdate++; + + synchronized (updateLock) { + SelectionKeyImpl ski; + while ((ski = updateKeys.pollFirst()) != null) { + if (ski.isValid()) { + int fd = ski.getFDVal(); + // add to fdToKey if needed + SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski); + assert (previous == null) || (previous == ski); + + int newEvents = ski.translateInterestOps(); + if (newEvents != ski.registeredEvents()) { + if (newEvents == 0) { + port_dissociate(pfd, PORT_SOURCE_FD, fd); + } else { + port_associate(pfd, PORT_SOURCE_FD, fd, newEvents); + } + ski.registeredEvents(newEvents); + } + } + } + } + } + + /** + * Process the polled events and re-queue the selected keys so the file + * descriptors are re-associated at the next select operation. + */ + private int processPortEvents(int numEvents, Consumer action) + throws IOException + { + assert Thread.holdsLock(this); + + int numKeysUpdated = 0; + boolean interrupted = false; + + // Process the polled events while holding the update lock. This allows + // keys to be queued for ready file descriptors so they can be + // re-associated at the next select. The selected-key can be updated + // in this pass. + synchronized (updateLock) { + for (int i = 0; i < numEvents; i++) { + short source = getSource(i); + if (source == PORT_SOURCE_FD) { + int fd = getDescriptor(i); + SelectionKeyImpl ski = fdToKey.get(fd); + if (ski != null) { + ski.registeredEvents(0); + updateKeys.addLast(ski); + + // update selected-key set if no action specified + if (action == null) { + int rOps = getEventOps(i); + numKeysUpdated += processReadyEvents(rOps, ski, null); + } + + } + } else if (source == PORT_SOURCE_USER) { + interrupted = true; + } else { + assert false; + } + } + } + + // if an action specified then iterate over the polled events again so + // that the action is performed without holding the update lock. + if (action != null) { + for (int i = 0; i < numEvents; i++) { + short source = getSource(i); + if (source == PORT_SOURCE_FD) { + int fd = getDescriptor(i); + SelectionKeyImpl ski = fdToKey.get(fd); + if (ski != null) { + int rOps = getEventOps(i); + numKeysUpdated += processReadyEvents(rOps, ski, action); + } + } + } + } + + if (interrupted) { + clearInterrupt(); + } + return numKeysUpdated; + } + + @Override + protected void implClose() throws IOException { + assert !isOpen(); + assert Thread.holdsLock(this); + + // prevent further wakeup + synchronized (interruptLock) { + interruptTriggered = true; + } + + port_close(pfd); + pollArray.free(); + } + + @Override + protected void implDereg(SelectionKeyImpl ski) throws IOException { + assert !ski.isValid(); + assert Thread.holdsLock(this); + + int fd = ski.getFDVal(); + if (fdToKey.remove(fd) != null) { + if (ski.registeredEvents() != 0) { + port_dissociate(pfd, PORT_SOURCE_FD, fd); + ski.registeredEvents(0); + } + } else { + assert ski.registeredEvents() == 0; + } + } + + @Override + public void setEventOps(SelectionKeyImpl ski) { + ensureOpen(); + synchronized (updateLock) { + updateKeys.addLast(ski); + } + } + + @Override + public Selector wakeup() { + synchronized (interruptLock) { + if (!interruptTriggered) { + try { + port_send(pfd, 0); + } catch (IOException ioe) { + throw new InternalError(ioe); + } + interruptTriggered = true; + } + } + return this; + } + + private void clearInterrupt() throws IOException { + synchronized (interruptLock) { + interruptTriggered = false; + } + } + + private short getSource(int i) { + int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE; + return pollArray.getShort(offset); + } + + private int getEventOps(int i) { + int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS; + return pollArray.getInt(offset); + } + + private int getDescriptor(int i) { + //assert Unsafe.getUnsafe().addressSize() == 8; + int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT; + return (int) pollArray.getLong(offset); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java 2024-01-27 14:37:30.297600057 +0100 @@ -0,0 +1,42 @@ +/* + * Copyright (c) 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.ch; + +import java.io.IOException; +import java.nio.channels.*; +import java.nio.channels.spi.*; + +public class EventPortSelectorProvider + extends SelectorProviderImpl +{ + public AbstractSelector openSelector() throws IOException { + return new EventPortSelectorImpl(this); + } + + public Channel inheritedChannel() throws IOException { + return InheritedChannel.getChannel(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java 2024-01-27 14:37:30.297888807 +0100 @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2008, 2010, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.ch; + +import java.nio.channels.*; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.io.IOException; + +public class SolarisAsynchronousChannelProvider + extends AsynchronousChannelProvider +{ + private static volatile SolarisEventPort defaultEventPort; + + private SolarisEventPort defaultEventPort() throws IOException { + if (defaultEventPort == null) { + synchronized (SolarisAsynchronousChannelProvider.class) { + if (defaultEventPort == null) { + defaultEventPort = + new SolarisEventPort(this, ThreadPool.getDefault()).start(); + } + } + } + return defaultEventPort; + } + + public SolarisAsynchronousChannelProvider() { + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory) + throws IOException + { + return new SolarisEventPort(this, ThreadPool.create(nThreads, factory)).start(); + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) + throws IOException + { + return new SolarisEventPort(this, ThreadPool.wrap(executor, initialSize)).start(); + } + + private SolarisEventPort toEventPort(AsynchronousChannelGroup group) + throws IOException + { + if (group == null) { + return defaultEventPort(); + } else { + if (!(group instanceof SolarisEventPort)) + throw new IllegalChannelGroupException(); + return (SolarisEventPort)group; + } + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousServerSocketChannelImpl(toEventPort(group)); + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousSocketChannelImpl(toEventPort(group)); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java 2024-01-27 14:37:30.298263681 +0100 @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.util.concurrent.RejectedExecutionException; +import java.io.IOException; +import jdk.internal.misc.Unsafe; + +/** + * Provides an AsynchronousChannelGroup implementation based on the Solaris 10 + * event port framework and also provides direct access to that framework. + */ + +class SolarisEventPort + extends Port +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static final int addressSize = unsafe.addressSize(); + + private static int dependsArch(int value32, int value64) { + return (addressSize == 4) ? value32 : value64; + } + + /* + * typedef struct port_event { + * int portev_events; + * ushort_t portev_source; + * ushort_t portev_pad; + * uintptr_t portev_object; + * void *portev_user; + * } port_event_t; + */ + static final int SIZEOF_PORT_EVENT = dependsArch(16, 24); + static final int OFFSETOF_EVENTS = 0; + static final int OFFSETOF_SOURCE = 4; + static final int OFFSETOF_OBJECT = 8; + + // port sources + static final short PORT_SOURCE_USER = 3; + static final short PORT_SOURCE_FD = 4; + + // file descriptor to event port. + private final int port; + + // true when port is closed + private boolean closed; + + SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool) + throws IOException + { + super(provider, pool); + + // create event port + this.port = port_create(); + } + + SolarisEventPort start() { + startThreads(new EventHandlerTask()); + return this; + } + + // releass resources + private void implClose() { + synchronized (this) { + if (closed) + return; + closed = true; + } + port_close(port); + } + + private void wakeup() { + try { + port_send(port, 0); + } catch (IOException x) { + throw new AssertionError(x); + } + } + + @Override + void executeOnHandlerTask(Runnable task) { + synchronized (this) { + if (closed) + throw new RejectedExecutionException(); + offerTask(task); + wakeup(); + } + } + + @Override + void shutdownHandlerTasks() { + /* + * If no tasks are running then just release resources; otherwise + * write to the one end of the socketpair to wakeup any polling threads.. + */ + int nThreads = threadCount(); + if (nThreads == 0) { + implClose(); + } else { + // send user event to wakeup each thread + while (nThreads-- > 0) { + try { + port_send(port, 0); + } catch (IOException x) { + throw new AssertionError(x); + } + } + } + } + + @Override + void startPoll(int fd, int events) { + // (re-)associate file descriptor + // no need to translate events + try { + port_associate(port, PORT_SOURCE_FD, fd, events); + } catch (IOException x) { + throw new AssertionError(); // should not happen + } + } + + /* + * Task to read a single event from the port and dispatch it to the + * channel's onEvent handler. + */ + private class EventHandlerTask implements Runnable { + public void run() { + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = + Invoker.getGroupAndInvokeCount(); + final boolean isPooledThread = (myGroupAndInvokeCount != null); + boolean replaceMe = false; + long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT); + try { + for (;;) { + // reset invoke count + if (isPooledThread) + myGroupAndInvokeCount.resetInvokeCount(); + + // wait for I/O completion event + // A error here is fatal (thread will not be replaced) + replaceMe = false; + try { + int n; + do { + n = port_get(port, address); + } while (n == IOStatus.INTERRUPTED); + } catch (IOException x) { + x.printStackTrace(); + return; + } + + // event source + short source = unsafe.getShort(address + OFFSETOF_SOURCE); + if (source != PORT_SOURCE_FD) { + // user event is trigger to invoke task or shutdown + if (source == PORT_SOURCE_USER) { + Runnable task = pollTask(); + if (task == null) { + // shutdown request + return; + } + // run task (may throw error/exception) + replaceMe = true; + task.run(); + } + // ignore + continue; + } + + // pe->portev_object is file descriptor + int fd = (int)unsafe.getAddress(address + OFFSETOF_OBJECT); + // pe->portev_events + int events = unsafe.getInt(address + OFFSETOF_EVENTS); + + // lookup channel + PollableChannel ch; + fdToChannelLock.readLock().lock(); + try { + ch = fdToChannel.get(fd); + } finally { + fdToChannelLock.readLock().unlock(); + } + + // notify channel + if (ch != null) { + replaceMe = true; + // no need to translate events + ch.onEvent(events, isPooledThread); + } + } + } finally { + // free per-thread resources + unsafe.freeMemory(address); + // last task to exit when shutdown release resources + int remaining = threadExit(this, replaceMe); + if (remaining == 0 && isShutdown()) + implClose(); + } + } + } + + /** + * Creates an event port + */ + static native int port_create() throws IOException; + + /** + * Associates specific events of a given object with a port + */ + static native boolean port_associate(int port, int source, long object, int events) + throws IOException; + + /** + * Removes the association of an object with a port. + */ + static native boolean port_dissociate(int port, int source, long object) + throws IOException; + + /** + * Retrieves a single event from a port + */ + static native int port_get(int port, long address) throws IOException; + + /** + * Retrieves at most {@code max} events from a port. + */ + static native int port_getn(int port, long address, int max, long timeout) + throws IOException; + + /** + * Sends a user-defined eventto a specified port. + */ + static native void port_send(int port, int events) throws IOException; + + /** + * Closes a port. + */ + static native void port_close(int port); + + + static { + IOUtil.load(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java 2024-01-27 14:37:30.298589379 +0100 @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +import java.nio.file.FileSystem; + +/** + * Creates this platform's default FileSystemProvider. + */ + +public class DefaultFileSystemProvider { + private static final SolarisFileSystemProvider INSTANCE + = new SolarisFileSystemProvider(); + + private DefaultFileSystemProvider() { } + + /** + * Returns the platform's default file system provider. + */ + public static SolarisFileSystemProvider instance() { + return INSTANCE; + } + + /** + * Returns the platform's default file system. + */ + public static FileSystem theFileSystem() { + return INSTANCE.theFileSystem(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java 2024-01-27 14:37:30.299013273 +0100 @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.util.*; +import java.io.IOException; +import jdk.internal.misc.Unsafe; + +import static sun.nio.fs.UnixConstants.*; +import static sun.nio.fs.SolarisConstants.*; +import static sun.nio.fs.SolarisNativeDispatcher.*; + + +/** + * Solaris implementation of AclFileAttributeView with native support for + * NFSv4 ACLs on ZFS. + */ + +class SolarisAclFileAttributeView + extends AbstractAclFileAttributeView +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + // Maximum number of entries allowed in an ACL + private static final int MAX_ACL_ENTRIES = 1024; + + /** + * typedef struct ace { + * uid_t a_who; + * uint32_t a_access_mask; + * uint16_t a_flags; + * uint16_t a_type; + * } ace_t; + */ + private static final short SIZEOF_ACE_T = 12; + private static final short OFFSETOF_UID = 0; + private static final short OFFSETOF_MASK = 4; + private static final short OFFSETOF_FLAGS = 8; + private static final short OFFSETOF_TYPE = 10; + + private final UnixPath file; + private final boolean followLinks; + + SolarisAclFileAttributeView(UnixPath file, boolean followLinks) { + this.file = file; + this.followLinks = followLinks; + } + + /** + * Permission checks to access file + */ + private void checkAccess(UnixPath file, + boolean checkRead, + boolean checkWrite) + { + @SuppressWarnings("removal") + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (checkRead) + file.checkRead(); + if (checkWrite) + file.checkWrite(); + sm.checkPermission(new RuntimePermission("accessUserInformation")); + } + } + + /** + * Encode the ACL to the given buffer + */ + private static void encode(List acl, long address) { + long offset = address; + for (AclEntry ace: acl) { + int flags = 0; + + // map UserPrincipal to uid and flags + UserPrincipal who = ace.principal(); + if (!(who instanceof UnixUserPrincipals.User)) + throw new ProviderMismatchException(); + UnixUserPrincipals.User user = (UnixUserPrincipals.User)who; + int uid; + if (user.isSpecial()) { + uid = -1; + if (who == UnixUserPrincipals.SPECIAL_OWNER) + flags |= ACE_OWNER; + else if (who == UnixUserPrincipals.SPECIAL_GROUP) + flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP); + else if (who == UnixUserPrincipals.SPECIAL_EVERYONE) + flags |= ACE_EVERYONE; + else + throw new AssertionError("Unable to map special identifier"); + } else { + if (user instanceof UnixUserPrincipals.Group) { + uid = user.gid(); + flags |= ACE_IDENTIFIER_GROUP; + } else { + uid = user.uid(); + } + } + + // map ACE type + int type; + switch (ace.type()) { + case ALLOW: + type = ACE_ACCESS_ALLOWED_ACE_TYPE; + break; + case DENY: + type = ACE_ACCESS_DENIED_ACE_TYPE; + break; + case AUDIT: + type = ACE_SYSTEM_AUDIT_ACE_TYPE; + break; + case ALARM: + type = ACE_SYSTEM_ALARM_ACE_TYPE; + break; + default: + throw new AssertionError("Unable to map ACE type"); + } + + // map permissions + Set aceMask = ace.permissions(); + int mask = 0; + if (aceMask.contains(AclEntryPermission.READ_DATA)) + mask |= ACE_READ_DATA; + if (aceMask.contains(AclEntryPermission.WRITE_DATA)) + mask |= ACE_WRITE_DATA; + if (aceMask.contains(AclEntryPermission.APPEND_DATA)) + mask |= ACE_APPEND_DATA; + if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS)) + mask |= ACE_READ_NAMED_ATTRS; + if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS)) + mask |= ACE_WRITE_NAMED_ATTRS; + if (aceMask.contains(AclEntryPermission.EXECUTE)) + mask |= ACE_EXECUTE; + if (aceMask.contains(AclEntryPermission.DELETE_CHILD)) + mask |= ACE_DELETE_CHILD; + if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES)) + mask |= ACE_READ_ATTRIBUTES; + if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES)) + mask |= ACE_WRITE_ATTRIBUTES; + if (aceMask.contains(AclEntryPermission.DELETE)) + mask |= ACE_DELETE; + if (aceMask.contains(AclEntryPermission.READ_ACL)) + mask |= ACE_READ_ACL; + if (aceMask.contains(AclEntryPermission.WRITE_ACL)) + mask |= ACE_WRITE_ACL; + if (aceMask.contains(AclEntryPermission.WRITE_OWNER)) + mask |= ACE_WRITE_OWNER; + if (aceMask.contains(AclEntryPermission.SYNCHRONIZE)) + mask |= ACE_SYNCHRONIZE; + + // FIXME - it would be desirable to know here if the file is a + // directory or not. Solaris returns EINVAL if an ACE has a directory + // -only flag and the file is not a directory. + Set aceFlags = ace.flags(); + if (aceFlags.contains(AclEntryFlag.FILE_INHERIT)) + flags |= ACE_FILE_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT)) + flags |= ACE_DIRECTORY_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT)) + flags |= ACE_NO_PROPAGATE_INHERIT_ACE; + if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY)) + flags |= ACE_INHERIT_ONLY_ACE; + + unsafe.putInt(offset + OFFSETOF_UID, uid); + unsafe.putInt(offset + OFFSETOF_MASK, mask); + unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags); + unsafe.putShort(offset + OFFSETOF_TYPE, (short)type); + + offset += SIZEOF_ACE_T; + } + } + + /** + * Decode the buffer, returning an ACL + */ + private static List decode(long address, int n) { + ArrayList acl = new ArrayList<>(n); + for (int i=0; i 0) { + who = UnixUserPrincipals.SPECIAL_OWNER; + } else if ((flags & ACE_GROUP) > 0) { + who = UnixUserPrincipals.SPECIAL_GROUP; + } else if ((flags & ACE_EVERYONE) > 0) { + who = UnixUserPrincipals.SPECIAL_EVERYONE; + } else if ((flags & ACE_IDENTIFIER_GROUP) > 0) { + who = UnixUserPrincipals.fromGid(uid); + } else { + who = UnixUserPrincipals.fromUid(uid); + } + + AclEntryType aceType = null; + switch (type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + aceType = AclEntryType.ALLOW; + break; + case ACE_ACCESS_DENIED_ACE_TYPE: + aceType = AclEntryType.DENY; + break; + case ACE_SYSTEM_AUDIT_ACE_TYPE: + aceType = AclEntryType.AUDIT; + break; + case ACE_SYSTEM_ALARM_ACE_TYPE: + aceType = AclEntryType.ALARM; + break; + default: + assert false; + } + + Set aceMask = EnumSet.noneOf(AclEntryPermission.class); + if ((mask & ACE_READ_DATA) > 0) + aceMask.add(AclEntryPermission.READ_DATA); + if ((mask & ACE_WRITE_DATA) > 0) + aceMask.add(AclEntryPermission.WRITE_DATA); + if ((mask & ACE_APPEND_DATA ) > 0) + aceMask.add(AclEntryPermission.APPEND_DATA); + if ((mask & ACE_READ_NAMED_ATTRS) > 0) + aceMask.add(AclEntryPermission.READ_NAMED_ATTRS); + if ((mask & ACE_WRITE_NAMED_ATTRS) > 0) + aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS); + if ((mask & ACE_EXECUTE) > 0) + aceMask.add(AclEntryPermission.EXECUTE); + if ((mask & ACE_DELETE_CHILD ) > 0) + aceMask.add(AclEntryPermission.DELETE_CHILD); + if ((mask & ACE_READ_ATTRIBUTES) > 0) + aceMask.add(AclEntryPermission.READ_ATTRIBUTES); + if ((mask & ACE_WRITE_ATTRIBUTES) > 0) + aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES); + if ((mask & ACE_DELETE) > 0) + aceMask.add(AclEntryPermission.DELETE); + if ((mask & ACE_READ_ACL) > 0) + aceMask.add(AclEntryPermission.READ_ACL); + if ((mask & ACE_WRITE_ACL) > 0) + aceMask.add(AclEntryPermission.WRITE_ACL); + if ((mask & ACE_WRITE_OWNER) > 0) + aceMask.add(AclEntryPermission.WRITE_OWNER); + if ((mask & ACE_SYNCHRONIZE) > 0) + aceMask.add(AclEntryPermission.SYNCHRONIZE); + + Set aceFlags = EnumSet.noneOf(AclEntryFlag.class); + if ((flags & ACE_FILE_INHERIT_ACE) > 0) + aceFlags.add(AclEntryFlag.FILE_INHERIT); + if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0) + aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT); + if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0) + aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT); + if ((flags & ACE_INHERIT_ONLY_ACE) > 0) + aceFlags.add(AclEntryFlag.INHERIT_ONLY); + + // build the ACL entry and add it to the list + AclEntry ace = AclEntry.newBuilder() + .setType(aceType) + .setPrincipal(who) + .setPermissions(aceMask).setFlags(aceFlags).build(); + acl.add(ace); + } + + return acl; + } + + // Returns true if NFSv4 ACLs not enabled on file system + private static boolean isAclsEnabled(int fd) { + try { + long enabled = fpathconf(fd, _PC_ACL_ENABLED); + if (enabled == _ACL_ACE_ENABLED) + return true; + } catch (UnixException x) { + } + return false; + } + + @Override + public List getAcl() + throws IOException + { + // permission check + checkAccess(file, true, false); + + // open file (will fail if file is a link and not following links) + int fd = -1; + try { + fd = file.openForAttributeAccess(followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + try { + long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES); + try { + // read ACL and decode it + int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address); + assert n >= 0; + return decode(address, n); + } catch (UnixException x) { + if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { + throw new FileSystemException(file.getPathForExceptionMessage(), + null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); + } + x.rethrowAsIOException(file); + return null; // keep compiler happy + } finally { + unsafe.freeMemory(address); + } + } finally { + close(fd, e -> null); + } + } + + @Override + public void setAcl(List acl) throws IOException { + // permission check + checkAccess(file, false, true); + + // open file (will fail if file is a link and not following links) + int fd = -1; + try { + fd = file.openForAttributeAccess(followLinks); + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + try { + // SECURITY: need to copy list as can change during processing + acl = new ArrayList(acl); + int n = acl.size(); + + long address = unsafe.allocateMemory(SIZEOF_ACE_T * n); + try { + encode(acl, address); + facl(fd, ACE_SETACL, n, address); + } catch (UnixException x) { + if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) { + throw new FileSystemException(file.getPathForExceptionMessage(), + null, x.getMessage() + " (file system does not support NFSv4 ACLs)"); + } + if (x.errno() == EINVAL && (n < 3)) + throw new IOException("ACL must contain at least 3 entries"); + x.rethrowAsIOException(file); + } finally { + unsafe.freeMemory(address); + } + } finally { + close(fd, e -> null); + } + } + + @Override + public UserPrincipal getOwner() + throws IOException + { + checkAccess(file, true, false); + + try { + UnixFileAttributes attrs = + UnixFileAttributes.get(file, followLinks); + return UnixUserPrincipals.fromUid(attrs.uid()); + } catch (UnixException x) { + x.rethrowAsIOException(file); + return null; // keep compile happy + } + } + + @Override + public void setOwner(UserPrincipal owner) throws IOException { + checkAccess(file, true, false); + + if (!(owner instanceof UnixUserPrincipals.User)) + throw new ProviderMismatchException(); + if (owner instanceof UnixUserPrincipals.Group) + throw new IOException("'owner' parameter is a group"); + int uid = ((UnixUserPrincipals.User)owner).uid(); + + try { + if (followLinks) { + lchown(file, uid, -1); + } else { + chown(file, uid, -1); + } + } catch (UnixException x) { + x.rethrowAsIOException(file); + } + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template 2024-01-27 14:37:30.299291815 +0100 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2008, 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +@@END_COPYRIGHT@@ + +#include +#include +#include +#include +#include +#include + +/* On Solaris, "sun" is defined as a macro. Undefine to make package + declaration valid */ +#undef sun + +/* To be able to name the Java constants the same as the C constants without + having the preprocessor rewrite those identifiers, add PREFIX_ to all + identifiers matching a C constant. The PREFIX_ is filtered out in the + makefile. */ + +@@START_HERE@@ + +package sun.nio.fs; +class SolarisConstants { + + private SolarisConstants() { } + + static final int PREFIX_O_XATTR = O_XATTR; + static final int PREFIX__PC_XATTR_ENABLED = _PC_XATTR_ENABLED; + static final int PREFIX__PC_ACL_ENABLED = _PC_ACL_ENABLED; + static final int PREFIX__ACL_ACE_ENABLED = _ACL_ACE_ENABLED; + static final int PREFIX_ACE_GETACL = ACE_GETACL; + static final int PREFIX_ACE_SETACL = ACE_SETACL; + static final int PREFIX_ACE_ACCESS_ALLOWED_ACE_TYPE = ACE_ACCESS_ALLOWED_ACE_TYPE; + static final int PREFIX_ACE_ACCESS_DENIED_ACE_TYPE = ACE_ACCESS_DENIED_ACE_TYPE; + static final int PREFIX_ACE_SYSTEM_AUDIT_ACE_TYPE = ACE_SYSTEM_AUDIT_ACE_TYPE; + static final int PREFIX_ACE_SYSTEM_ALARM_ACE_TYPE = ACE_SYSTEM_ALARM_ACE_TYPE; + static final int PREFIX_ACE_READ_DATA = ACE_READ_DATA; + static final int PREFIX_ACE_LIST_DIRECTORY = ACE_LIST_DIRECTORY; + static final int PREFIX_ACE_WRITE_DATA = ACE_WRITE_DATA; + static final int PREFIX_ACE_ADD_FILE = ACE_ADD_FILE; + static final int PREFIX_ACE_APPEND_DATA = ACE_APPEND_DATA; + static final int PREFIX_ACE_ADD_SUBDIRECTORY = ACE_ADD_SUBDIRECTORY; + static final int PREFIX_ACE_READ_NAMED_ATTRS = ACE_READ_NAMED_ATTRS; + static final int PREFIX_ACE_WRITE_NAMED_ATTRS = ACE_WRITE_NAMED_ATTRS; + static final int PREFIX_ACE_EXECUTE = ACE_EXECUTE; + static final int PREFIX_ACE_DELETE_CHILD = ACE_DELETE_CHILD; + static final int PREFIX_ACE_READ_ATTRIBUTES = ACE_READ_ATTRIBUTES; + static final int PREFIX_ACE_WRITE_ATTRIBUTES = ACE_WRITE_ATTRIBUTES; + static final int PREFIX_ACE_DELETE = ACE_DELETE; + static final int PREFIX_ACE_READ_ACL = ACE_READ_ACL; + static final int PREFIX_ACE_WRITE_ACL = ACE_WRITE_ACL; + static final int PREFIX_ACE_WRITE_OWNER = ACE_WRITE_OWNER; + static final int PREFIX_ACE_SYNCHRONIZE = ACE_SYNCHRONIZE; + static final int PREFIX_ACE_FILE_INHERIT_ACE = ACE_FILE_INHERIT_ACE; + static final int PREFIX_ACE_DIRECTORY_INHERIT_ACE = ACE_DIRECTORY_INHERIT_ACE; + static final int PREFIX_ACE_NO_PROPAGATE_INHERIT_ACE = ACE_NO_PROPAGATE_INHERIT_ACE; + static final int PREFIX_ACE_INHERIT_ONLY_ACE = ACE_INHERIT_ONLY_ACE; + static final int PREFIX_ACE_SUCCESSFUL_ACCESS_ACE_FLAG = ACE_SUCCESSFUL_ACCESS_ACE_FLAG; + static final int PREFIX_ACE_FAILED_ACCESS_ACE_FLAG = ACE_FAILED_ACCESS_ACE_FLAG; + static final int PREFIX_ACE_IDENTIFIER_GROUP = ACE_IDENTIFIER_GROUP; + static final int PREFIX_ACE_OWNER = ACE_OWNER; + static final int PREFIX_ACE_GROUP = ACE_GROUP; + static final int PREFIX_ACE_EVERYONE = ACE_EVERYONE; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java 2024-01-27 14:37:30.299568430 +0100 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2008, 2010, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +import java.nio.file.attribute.*; +import java.io.IOException; + +import static sun.nio.fs.UnixNativeDispatcher.*; +import static sun.nio.fs.SolarisConstants.*; + +/** + * Solaris implementation of FileStore + */ + +class SolarisFileStore + extends UnixFileStore +{ + private final boolean xattrEnabled; + + SolarisFileStore(UnixPath file) throws IOException { + super(file); + this.xattrEnabled = xattrEnabled(); + } + + SolarisFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { + super(fs, entry); + this.xattrEnabled = xattrEnabled(); + } + + // returns true if extended attributes enabled + private boolean xattrEnabled() { + long res = 0L; + try { + res = pathconf(file(), _PC_XATTR_ENABLED); + } catch (UnixException x) { + // ignore + } + return (res != 0L); + } + + @Override + UnixMountEntry findMountEntry() throws IOException { + // On Solaris iterate over the entries in the mount table to find device + for (UnixMountEntry entry: file().getFileSystem().getMountEntries()) { + if (entry.dev() == dev()) { + return entry; + } + } + throw new IOException("Device not found in mnttab"); + } + + @Override + public boolean supportsFileAttributeView(Class type) { + if (type == AclFileAttributeView.class) { + // lookup fstypes.properties + FeatureStatus status = checkIfFeaturePresent("nfsv4acl"); + switch (status) { + case PRESENT : return true; + case NOT_PRESENT : return false; + default : + // AclFileAttributeView available on ZFS + return (type().equals("zfs")); + } + } + if (type == UserDefinedFileAttributeView.class) { + // lookup fstypes.properties + FeatureStatus status = checkIfFeaturePresent("xattr"); + switch (status) { + case PRESENT : return true; + case NOT_PRESENT : return false; + default : + // UserDefinedFileAttributeView available if extended + // attributes supported + return xattrEnabled; + } + } + return super.supportsFileAttributeView(type); + } + + @Override + public boolean supportsFileAttributeView(String name) { + if (name.equals("acl")) + return supportsFileAttributeView(AclFileAttributeView.class); + if (name.equals("user")) + return supportsFileAttributeView(UserDefinedFileAttributeView.class); + return super.supportsFileAttributeView(name); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java 2024-01-27 14:37:30.299856468 +0100 @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.io.IOException; +import java.util.*; +import sun.security.action.GetPropertyAction; +import static sun.nio.fs.SolarisNativeDispatcher.*; + +/** + * Solaris implementation of FileSystem + */ + +class SolarisFileSystem extends UnixFileSystem { + private final boolean hasSolaris11Features; + + SolarisFileSystem(UnixFileSystemProvider provider, String dir) { + super(provider, dir); + + // check os.version + String osversion = GetPropertyAction.privilegedGetProperty("os.version"); + String[] vers = Util.split(osversion, '.'); + assert vers.length >= 2; + int majorVersion = Integer.parseInt(vers[0]); + int minorVersion = Integer.parseInt(vers[1]); + this.hasSolaris11Features = + (majorVersion > 5 || (majorVersion == 5 && minorVersion >= 11)); + } + + @Override + boolean isSolaris() { + return true; + } + + @Override + public WatchService newWatchService() + throws IOException + { + // FEN available since Solaris 11 + if (hasSolaris11Features) { + return new SolarisWatchService(this); + } else { + return new PollingWatchService(); + } + } + + + // lazy initialization of the list of supported attribute views + private static class SupportedFileFileAttributeViewsHolder { + static final Set supportedFileAttributeViews = + supportedFileAttributeViews(); + private static Set supportedFileAttributeViews() { + Set result = new HashSet<>(); + result.addAll(standardFileAttributeViews()); + // additional Solaris-specific views + result.add("acl"); + result.add("user"); + return Collections.unmodifiableSet(result); + } + } + + @Override + public Set supportedFileAttributeViews() { + return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews; + } + + @Override + void copyNonPosixAttributes(int ofd, int nfd) { + SolarisUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd); + // TDB: copy ACL from source to target + } + + /** + * Returns object to iterate over entries in /etc/mnttab + */ + @Override + Iterable getMountEntries() { + ArrayList entries = new ArrayList<>(); + try { + UnixPath mnttab = new UnixPath(this, "/etc/mnttab"); + long fp = fopen(mnttab, "r"); + try { + for (;;) { + UnixMountEntry entry = new UnixMountEntry(); + int res = getextmntent(fp, entry); + if (res < 0) + break; + entries.add(entry); + } + } finally { + fclose(fp); + } + } catch (UnixException x) { + // nothing we can do + } + return entries; + } + + @Override + FileStore getFileStore(UnixMountEntry entry) throws IOException { + return new SolarisFileStore(this, entry); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java 2024-01-27 14:37:30.300150586 +0100 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.nio.file.attribute.*; +import java.nio.file.spi.FileTypeDetector; +import java.io.IOException; +import jdk.internal.util.StaticProperty; +import sun.security.action.GetPropertyAction; + +/** + * Solaris implementation of FileSystemProvider + */ + +class SolarisFileSystemProvider extends UnixFileSystemProvider { + public SolarisFileSystemProvider() { + super(); + } + + @Override + SolarisFileSystem newFileSystem(String dir) { + return new SolarisFileSystem(this, dir); + } + + @Override + SolarisFileStore getFileStore(UnixPath path) throws IOException { + return new SolarisFileStore(path); + } + + + @Override + @SuppressWarnings("unchecked") + public V getFileAttributeView(Path obj, + Class type, + LinkOption... options) + { + if (type == AclFileAttributeView.class) { + return (V) new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj), + Util.followLinks(options)); + } + if (type == UserDefinedFileAttributeView.class) { + return(V) new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + Util.followLinks(options)); + } + return super.getFileAttributeView(obj, type, options); + } + + @Override + public DynamicFileAttributeView getFileAttributeView(Path obj, + String name, + LinkOption... options) + { + if (name.equals("acl")) + return new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj), + Util.followLinks(options)); + if (name.equals("user")) + return new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj), + Util.followLinks(options)); + return super.getFileAttributeView(obj, name, options); + } + + @Override + FileTypeDetector getFileTypeDetector() { + Path userMimeTypes = Path.of(StaticProperty.userHome(), ".mime.types"); + Path etcMimeTypes = Path.of("/etc/mime.types"); + + return chain(new MimeTypesFileTypeDetector(userMimeTypes), + new MimeTypesFileTypeDetector(etcMimeTypes)); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java 2024-01-27 14:37:30.300409159 +0100 @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +/** + * Solaris specific system calls. + */ + +class SolarisNativeDispatcher extends UnixNativeDispatcher { + private SolarisNativeDispatcher() { } + + /** + * int getextmntent(FILE *fp, struct extmnttab *mp, int len); + */ + static native int getextmntent(long fp, UnixMountEntry entry) + throws UnixException; + + /** + * int facl(int filedes, int cmd, int nentries, void aclbufp) + */ + static native int facl(int fd, int cmd, int nentries, long aclbufp) + throws UnixException; + + + // initialize + private static native void init(); + + static { + jdk.internal.loader.BootLoader.loadLibrary("nio"); + init(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java 2024-01-27 14:37:30.300676746 +0100 @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +class SolarisUserDefinedFileAttributeView + extends UnixUserDefinedFileAttributeView +{ + + SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) { + super(file, followLinks); + } + + @Override + protected int maxNameLength() { + return 255; + } + +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java 2024-01-27 14:37:30.301262890 +0100 @@ -0,0 +1,821 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.nio.fs; + +import java.nio.file.*; +import java.util.*; +import java.io.IOException; +import jdk.internal.misc.Unsafe; + +import static sun.nio.fs.UnixConstants.*; + +/** + * Solaris implementation of WatchService based on file events notification + * facility. + */ + +class SolarisWatchService + extends AbstractWatchService +{ + private static final Unsafe unsafe = Unsafe.getUnsafe(); + private static int addressSize = unsafe.addressSize(); + + private static int dependsArch(int value32, int value64) { + return (addressSize == 4) ? value32 : value64; + } + + /* + * typedef struct port_event { + * int portev_events; + * ushort_t portev_source; + * ushort_t portev_pad; + * uintptr_t portev_object; + * void *portev_user; + * } port_event_t; + */ + private static final int SIZEOF_PORT_EVENT = dependsArch(16, 24); + private static final int OFFSETOF_EVENTS = 0; + private static final int OFFSETOF_SOURCE = 4; + private static final int OFFSETOF_OBJECT = 8; + + /* + * typedef struct file_obj { + * timestruc_t fo_atime; + * timestruc_t fo_mtime; + * timestruc_t fo_ctime; + * uintptr_t fo_pad[3]; + * char *fo_name; + * } file_obj_t; + */ + private static final int SIZEOF_FILEOBJ = dependsArch(40, 80); + private static final int OFFSET_FO_NAME = dependsArch(36, 72); + + // port sources + private static final short PORT_SOURCE_USER = 3; + private static final short PORT_SOURCE_FILE = 7; + + // user-watchable events + private static final int FILE_MODIFIED = 0x00000002; + private static final int FILE_ATTRIB = 0x00000004; + private static final int FILE_NOFOLLOW = 0x10000000; + + // exception events + private static final int FILE_DELETE = 0x00000010; + private static final int FILE_RENAME_TO = 0x00000020; + private static final int FILE_RENAME_FROM = 0x00000040; + private static final int UNMOUNTED = 0x20000000; + private static final int MOUNTEDOVER = 0x40000000; + + // background thread to read change events + private final Poller poller; + + SolarisWatchService(UnixFileSystem fs) throws IOException { + int port = -1; + try { + port = portCreate(); + } catch (UnixException x) { + throw new IOException(x.errorString()); + } + + this.poller = new Poller(fs, this, port); + this.poller.start(); + } + + @Override + WatchKey register(Path dir, + WatchEvent.Kind[] events, + WatchEvent.Modifier... modifiers) + throws IOException + { + // delegate to poller + return poller.register(dir, events, modifiers); + } + + @Override + void implClose() throws IOException { + // delegate to poller + poller.close(); + } + + /** + * WatchKey implementation + */ + private class SolarisWatchKey extends AbstractWatchKey + implements DirectoryNode + { + private final UnixFileKey fileKey; + + // pointer to native file_obj object + private final long object; + + // events (may be changed). set to null when watch key is invalid + private volatile Set> events; + + // map of entries in directory; created lazily; accessed only by + // poller thread. + private Map children = new HashMap<>(); + + SolarisWatchKey(SolarisWatchService watcher, + UnixPath dir, + UnixFileKey fileKey, + long object, + Set> events) + { + super(dir, watcher); + this.fileKey = fileKey; + this.object = object; + this.events = events; + } + + UnixPath getDirectory() { + return (UnixPath)watchable(); + } + + UnixFileKey getFileKey() { + return fileKey; + } + + @Override + public long object() { + return object; + } + + void invalidate() { + events = null; + } + + Set> events() { + return events; + } + + void setEvents(Set> events) { + this.events = events; + } + + Map children() { + return children; + } + + @Override + public boolean isValid() { + return events != null; + } + + @Override + public void cancel() { + if (isValid()) { + // delegate to poller + poller.cancel(this); + } + } + + @Override + public void addChild(Path name, EntryNode node) { + children.put(name, node); + } + + @Override + public void removeChild(Path name) { + children.remove(name); + } + + @Override + public EntryNode getChild(Path name) { + return children.get(name); + } + } + + /** + * Background thread to read from port + */ + private class Poller extends AbstractPoller { + + // maximum number of events to read per call to port_getn + private static final int MAX_EVENT_COUNT = 128; + + // events that map to ENTRY_DELETE + private static final int FILE_REMOVED = + (FILE_DELETE|FILE_RENAME_TO|FILE_RENAME_FROM); + + // events that tell us not to re-associate the object + private static final int FILE_EXCEPTION = + (FILE_REMOVED|UNMOUNTED|MOUNTEDOVER); + + // address of event buffers (used to receive events with port_getn) + private final long bufferAddress; + + private final SolarisWatchService watcher; + + // the I/O port + private final int port; + + // maps file key (dev/inode) to WatchKey + private final Map fileKey2WatchKey; + + // maps file_obj object to Node + private final Map object2Node; + + /** + * Create a new instance + */ + Poller(UnixFileSystem fs, SolarisWatchService watcher, int port) { + this.watcher = watcher; + this.port = port; + this.bufferAddress = + unsafe.allocateMemory(SIZEOF_PORT_EVENT * MAX_EVENT_COUNT); + this.fileKey2WatchKey = new HashMap(); + this.object2Node = new HashMap(); + } + + @Override + void wakeup() throws IOException { + // write to port to wakeup polling thread + try { + portSend(port, 0); + } catch (UnixException x) { + throw new IOException(x.errorString()); + } + } + + @Override + Object implRegister(Path obj, + Set> events, + WatchEvent.Modifier... modifiers) + { + // no modifiers supported at this time + if (modifiers.length > 0) { + for (WatchEvent.Modifier modifier: modifiers) { + if (modifier == null) + return new NullPointerException(); + if (!ExtendedOptions.SENSITIVITY_HIGH.matches(modifier) && + !ExtendedOptions.SENSITIVITY_MEDIUM.matches(modifier) && + !ExtendedOptions.SENSITIVITY_LOW.matches(modifier)) { + return new UnsupportedOperationException("Modifier not supported"); + } + } + } + + UnixPath dir = (UnixPath)obj; + + // check file is directory + UnixFileAttributes attrs = null; + try { + attrs = UnixFileAttributes.get(dir, true); + } catch (UnixException x) { + return x.asIOException(dir); + } + if (!attrs.isDirectory()) { + return new NotDirectoryException(dir.getPathForExceptionMessage()); + } + + // if already registered then update the events and return existing key + UnixFileKey fileKey = attrs.fileKey(); + SolarisWatchKey watchKey = fileKey2WatchKey.get(fileKey); + if (watchKey != null) { + try { + updateEvents(watchKey, events); + } catch (UnixException x) { + return x.asIOException(dir); + } + return watchKey; + } + + // register directory + long object = 0L; + try { + object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB)); + } catch (UnixException x) { + return x.asIOException(dir); + } + + // create watch key and insert it into maps + watchKey = new SolarisWatchKey(watcher, dir, fileKey, object, events); + object2Node.put(object, watchKey); + fileKey2WatchKey.put(fileKey, watchKey); + + // register all entries in directory + registerChildren(dir, watchKey, false, false); + + return watchKey; + } + + // release resources for single entry + void releaseChild(EntryNode node) { + long object = node.object(); + if (object != 0L) { + object2Node.remove(object); + releaseObject(object, true); + node.setObject(0L); + } + } + + // release resources for entries in directory + void releaseChildren(SolarisWatchKey key) { + for (EntryNode node: key.children().values()) { + releaseChild(node); + } + } + + // cancel single key + @Override + void implCancelKey(WatchKey obj) { + SolarisWatchKey key = (SolarisWatchKey)obj; + if (key.isValid()) { + fileKey2WatchKey.remove(key.getFileKey()); + + // release resources for entries + releaseChildren(key); + + // release resources for directory + long object = key.object(); + object2Node.remove(object); + releaseObject(object, true); + + // and finally invalidate the key + key.invalidate(); + } + } + + // close watch service + @Override + void implCloseAll() { + // release all native resources + for (Long object: object2Node.keySet()) { + releaseObject(object, true); + } + + // invalidate all keys + for (Map.Entry entry: fileKey2WatchKey.entrySet()) { + entry.getValue().invalidate(); + } + + // clean-up + object2Node.clear(); + fileKey2WatchKey.clear(); + + // free global resources + unsafe.freeMemory(bufferAddress); + UnixNativeDispatcher.close(port, e -> null); + } + + /** + * Poller main loop. Blocks on port_getn waiting for events and then + * processes them. + */ + @Override + public void run() { + try { + for (;;) { + int n = portGetn(port, bufferAddress, MAX_EVENT_COUNT); + assert n > 0; + + long address = bufferAddress; + for (int i=0; iportev_source + short source = unsafe.getShort(address + OFFSETOF_SOURCE); + // pe->portev_object + long object = unsafe.getAddress(address + OFFSETOF_OBJECT); + // pe->portev_events + int events = unsafe.getInt(address + OFFSETOF_EVENTS); + + // user event is trigger to process pending requests + if (source != PORT_SOURCE_FILE) { + if (source == PORT_SOURCE_USER) { + // process any pending requests + boolean shutdown = processRequests(); + if (shutdown) + return true; + } + return false; + } + + // lookup object to get Node + Node node = object2Node.get(object); + if (node == null) { + // should not happen + return false; + } + + // As a workaround for 6642290 and 6636438/6636412 we don't use + // FILE_EXCEPTION events to tell use not to register the file. + // boolean reregister = (events & FILE_EXCEPTION) == 0; + boolean reregister = true; + + // If node is EntryNode then event relates to entry in directory + // If node is a SolarisWatchKey (DirectoryNode) then event relates + // to a watched directory. + boolean isDirectory = (node instanceof SolarisWatchKey); + if (isDirectory) { + processDirectoryEvents((SolarisWatchKey)node, events); + } else { + boolean ignore = processEntryEvents((EntryNode)node, events); + if (ignore) + reregister = false; + } + + // need to re-associate to get further events + if (reregister) { + try { + events = FILE_MODIFIED | FILE_ATTRIB; + if (!isDirectory) events |= FILE_NOFOLLOW; + portAssociate(port, + PORT_SOURCE_FILE, + object, + events); + } catch (UnixException x) { + // unable to re-register + reregister = false; + } + } + + // object is not re-registered so release resources. If + // object is a watched directory then signal key + if (!reregister) { + // release resources + object2Node.remove(object); + releaseObject(object, false); + + // if watch key then signal it + if (isDirectory) { + SolarisWatchKey key = (SolarisWatchKey)node; + fileKey2WatchKey.remove( key.getFileKey() ); + key.invalidate(); + key.signal(); + } else { + // if entry then remove it from parent + EntryNode entry = (EntryNode)node; + SolarisWatchKey key = (SolarisWatchKey)entry.parent(); + key.removeChild(entry.name()); + } + } + + return false; + } + + /** + * Process directory events. If directory is modified then re-scan + * directory to register any new entries + */ + void processDirectoryEvents(SolarisWatchKey key, int mask) { + if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) { + registerChildren(key.getDirectory(), key, + key.events().contains(StandardWatchEventKinds.ENTRY_CREATE), + key.events().contains(StandardWatchEventKinds.ENTRY_DELETE)); + } + } + + /** + * Process events for entries in registered directories. Returns {@code + * true} if events are ignored because the watch key has been cancelled. + */ + boolean processEntryEvents(EntryNode node, int mask) { + SolarisWatchKey key = (SolarisWatchKey)node.parent(); + Set> events = key.events(); + if (events == null) { + // key has been cancelled so ignore event + return true; + } + + // entry modified + if (((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) && + events.contains(StandardWatchEventKinds.ENTRY_MODIFY)) + { + key.signalEvent(StandardWatchEventKinds.ENTRY_MODIFY, node.name()); + } + + + return false; + } + + /** + * Registers all entries in the given directory + * + * The {@code sendCreateEvents} and {@code sendDeleteEvents} parameters + * indicates if ENTRY_CREATE and ENTRY_DELETE events should be queued + * when new entries are found. When initially registering a directory + * they will always be false. When re-scanning a directory then it + * depends on if the events are enabled or not. + */ + void registerChildren(UnixPath dir, + SolarisWatchKey parent, + boolean sendCreateEvents, + boolean sendDeleteEvents) + { + boolean isModifyEnabled = + parent.events().contains(StandardWatchEventKinds.ENTRY_MODIFY) ; + + // reset visited flag on entries so that we can detect file deletes + for (EntryNode node: parent.children().values()) { + node.setVisited(false); + } + + try (DirectoryStream stream = Files.newDirectoryStream(dir)) { + for (Path entry: stream) { + Path name = entry.getFileName(); + + // skip entry if already registered + EntryNode node = parent.getChild(name); + if (node != null) { + node.setVisited(true); + continue; + } + + // new entry found + + long object = 0L; + int errno = 0; + boolean addNode = false; + + // if ENTRY_MODIFY enabled then we register the entry for events + if (isModifyEnabled) { + try { + UnixPath path = (UnixPath)entry; + int events = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB); + object = registerImpl(path, events); + addNode = true; + } catch (UnixException x) { + errno = x.errno(); + } + } else { + addNode = true; + } + + if (addNode) { + // create node + node = new EntryNode(object, (UnixPath)entry.getFileName(), parent); + node.setVisited(true); + // tell the parent about it + parent.addChild(entry.getFileName(), node); + if (object != 0L) + object2Node.put(object, node); + } + + // send ENTRY_CREATE event for the new file + // send ENTRY_DELETE event for files that were deleted immediately + boolean deleted = (errno == ENOENT); + if (sendCreateEvents && (addNode || deleted)) + parent.signalEvent(StandardWatchEventKinds.ENTRY_CREATE, name); + if (sendDeleteEvents && deleted) + parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, name); + + } + } catch (DirectoryIteratorException | IOException x) { + // queue OVERFLOW event so that user knows to re-scan directory + parent.signalEvent(StandardWatchEventKinds.OVERFLOW, null); + return; + } + + // clean-up and send ENTRY_DELETE events for any entries that were + // not found + Iterator> iterator = + parent.children().entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + EntryNode node = entry.getValue(); + if (!node.isVisited()) { + long object = node.object(); + if (object != 0L) { + object2Node.remove(object); + releaseObject(object, true); + } + if (sendDeleteEvents) + parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, node.name()); + iterator.remove(); + } + } + } + + /** + * Update watch key's events. If ENTRY_MODIFY changes to be enabled + * then register each file in the directory; If ENTRY_MODIFY changed to + * be disabled then unregister each file. + */ + void updateEvents(SolarisWatchKey key, Set> events) + throws UnixException + { + + // update events, remembering if ENTRY_MODIFY was previously + // enabled or disabled. + boolean oldModifyEnabled = key.events() + .contains(StandardWatchEventKinds.ENTRY_MODIFY); + key.setEvents(events); + + // check if ENTRY_MODIFY has changed + boolean newModifyEnabled = events + .contains(StandardWatchEventKinds.ENTRY_MODIFY); + if (newModifyEnabled != oldModifyEnabled) { + UnixException ex = null; + for (EntryNode node: key.children().values()) { + if (newModifyEnabled) { + // register + UnixPath path = key.getDirectory().resolve(node.name()); + int ev = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB); + try { + long object = registerImpl(path, ev); + object2Node.put(object, node); + node.setObject(object); + } catch (UnixException x) { + // if file has been deleted then it will be detected + // as a FILE_MODIFIED event on the directory + if (x.errno() != ENOENT) { + ex = x; + break; + } + } + } else { + // unregister + releaseChild(node); + } + } + + // an error occurred + if (ex != null) { + releaseChildren(key); + throw ex; + } + } + } + + /** + * Calls port_associate to register the given path. + * Returns pointer to fileobj structure that is allocated for + * the registration. + */ + long registerImpl(UnixPath dir, int events) + throws UnixException + { + // allocate memory for the path (file_obj->fo_name field) + byte[] path = dir.getByteArrayForSysCalls(); + int len = path.length; + long name = unsafe.allocateMemory(len+1); + unsafe.copyMemory(path, Unsafe.ARRAY_BYTE_BASE_OFFSET, null, + name, (long)len); + unsafe.putByte(name + len, (byte)0); + + // allocate memory for filedatanode structure - this is the object + // to port_associate + long object = unsafe.allocateMemory(SIZEOF_FILEOBJ); + unsafe.setMemory(null, object, SIZEOF_FILEOBJ, (byte)0); + unsafe.putAddress(object + OFFSET_FO_NAME, name); + + // associate the object with the port + try { + portAssociate(port, + PORT_SOURCE_FILE, + object, + events); + } catch (UnixException x) { + // debugging + if (x.errno() == EAGAIN) { + System.err.println("The maximum number of objects associated "+ + "with the port has been reached"); + } + + unsafe.freeMemory(name); + unsafe.freeMemory(object); + throw x; + } + return object; + } + + /** + * Frees all resources for an file_obj object; optionally remove + * association from port + */ + void releaseObject(long object, boolean dissociate) { + // remove association + if (dissociate) { + try { + portDissociate(port, PORT_SOURCE_FILE, object); + } catch (UnixException x) { + // ignore + } + } + + // free native memory + long name = unsafe.getAddress(object + OFFSET_FO_NAME); + unsafe.freeMemory(name); + unsafe.freeMemory(object); + } + } + + /** + * A node with native (file_obj) resources + */ + private static interface Node { + long object(); + } + + /** + * A directory node with a map of the entries in the directory + */ + private static interface DirectoryNode extends Node { + void addChild(Path name, EntryNode node); + void removeChild(Path name); + EntryNode getChild(Path name); + } + + /** + * An implementation of a node that is an entry in a directory. + */ + private static class EntryNode implements Node { + private long object; + private final UnixPath name; + private final DirectoryNode parent; + private boolean visited; + + EntryNode(long object, UnixPath name, DirectoryNode parent) { + this.object = object; + this.name = name; + this.parent = parent; + } + + @Override + public long object() { + return object; + } + + void setObject(long ptr) { + this.object = ptr; + } + + UnixPath name() { + return name; + } + + DirectoryNode parent() { + return parent; + } + + boolean isVisited() { + return visited; + } + + void setVisited(boolean v) { + this.visited = v; + } + } + + // -- native methods -- + + private static native void init(); + + private static native int portCreate() throws UnixException; + + private static native void portAssociate(int port, int source, long object, int events) + throws UnixException; + + private static native void portDissociate(int port, int source, long object) + throws UnixException; + + private static native void portSend(int port, int events) + throws UnixException; + + private static native int portGetn(int port, long address, int max) + throws UnixException; + + static { + jdk.internal.loader.BootLoader.loadLibrary("nio"); + init(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c 2024-01-27 14:37:30.301597886 +0100 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 "jni.h" + +#include "ProcessHandleImpl_unix.h" + +#include + +/* + * Implementation of native ProcessHandleImpl functions for Solaris. + * See ProcessHandleImpl_unix.c for more details. + */ + +void os_initNative(JNIEnv *env, jclass clazz) {} + +jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, + jlongArray jparentArray, jlongArray jstimesArray) { + return unix_getChildren(env, jpid, jarray, jparentArray, jstimesArray); +} + +pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid, jlong *total, jlong *start) { + return unix_getParentPidAndTimings(env, pid, total, start); +} + +void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) { + unix_getCmdlineAndUserInfo(env, jinfo, pid); +} + diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.c 2024-01-27 14:37:30.302559094 +0100 @@ -0,0 +1,1552 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include + +#include "libjvm_db.h" +#include "JvmOffsets.h" + +#define LIBJVM_SO "libjvm.so" + +#if defined(i386) || defined(__i386) || defined(__amd64) +#ifdef COMPILER2 +#define X86_COMPILER2 +#endif /* COMPILER2 */ +#endif /* i386 */ + +typedef struct { + short vf_cnt; /* number of recognized java vframes */ + short bci; /* current frame method byte code index */ + int line; /* current frame method source line */ + uint64_t new_fp; /* fp for the next frame */ + uint64_t new_pc; /* pc for the next frame */ + uint64_t new_sp; /* "raw" sp for the next frame (includes extension by interpreter/adapter */ + char locinf; /* indicates there is valid location info */ +} Jframe_t; + +int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name, + size_t size, Jframe_t *jframe); + +int main(int arg) { return arg; } + +static int debug = 0; + +static void failed(int err, const char * file, int line) { + if (debug) { + fprintf(stderr, "failed %d at %s:%d\n", err, file, line); + } +} + +static void warn(const char * file, int line, const char * msg) { + if (debug) { + fprintf(stderr, "warning: %s at %s:%d\n", msg, file, line); + } +} + +static void warn1(const char * file, int line, const char * msg, intptr_t arg1) { + if (debug) { + fprintf(stderr, "warning: "); + fprintf(stderr, msg, arg1); + fprintf(stderr, " at %s:%d\n", file, line); + } +} + +#define CHECK_FAIL(err) \ + if (err != PS_OK) { failed(err, __FILE__, __LINE__); goto fail; } +#define WARN(msg) warn(__FILE__, __LINE__, msg) +#define WARN1(msg, arg1) warn1(__FILE__, __LINE__, msg, arg1) + +typedef struct VMStructEntry { + const char * typeName; /* The type name containing the given field (example: "Klass") */ + const char * fieldName; /* The field name within the type (example: "_name") */ + uint64_t address; /* Address of field; only used for static fields */ + /* ("offset" can not be reused because of apparent solstudio compiler bug */ + /* in generation of initializer data) */ +} VMStructEntry; + +/* Prototyping inlined methods */ + +int sprintf(char *s, const char *format, ...); + +#define SZ16 sizeof(int16_t) +#define SZ32 sizeof(int32_t) + +#define COMP_METHOD_SIGN '*' + +#define MAX_VFRAMES_CNT 256 + +typedef struct vframe { + uint64_t method; + int32_t sender_decode_offset; + int32_t methodIdx; + int32_t bci; + int32_t line; +} Vframe_t; + +typedef struct frame { + uintptr_t fp; + uintptr_t pc; + uintptr_t sp; + uintptr_t sender_sp; // The unextended sp of the caller +} Frame_t; + +typedef struct Nmethod_t { + struct jvm_agent* J; + Jframe_t *jframe; + + uint64_t nm; /* _nmethod */ + uint64_t pc; + uint64_t pc_desc; + + int32_t orig_pc_offset; /* _orig_pc_offset */ + uint64_t instrs_beg; /* _code_offset */ + uint64_t instrs_end; + uint64_t deopt_beg; /* _deoptimize_offset */ + uint64_t scopes_data_beg; /* _scopes_data_begin */ + int32_t scopes_data_end; + int32_t metadata_beg; /* _metadata_offset */ + int32_t metadata_end; + int32_t scopes_pcs_beg; /* _scopes_pcs_offset */ + int32_t scopes_pcs_end; + + int vf_cnt; + Vframe_t vframes[MAX_VFRAMES_CNT]; +} Nmethod_t; + +struct jvm_agent { + struct ps_prochandle* P; + + uint64_t nmethod_vtbl; + uint64_t CodeBlob_vtbl; + uint64_t BufferBlob_vtbl; + uint64_t RuntimeStub_vtbl; + uint64_t Method_vtbl; + + uint64_t Use_Compressed_Oops_address; + uint64_t Universe_narrow_oop_base_address; + uint64_t Universe_narrow_oop_shift_address; + uint64_t CodeCache_heaps_address; + + /* Volatiles */ + uint8_t Use_Compressed_Oops; + uint64_t Universe_narrow_oop_base; + uint32_t Universe_narrow_oop_shift; + // Code cache heaps + int32_t Number_of_heaps; + uint64_t* Heap_low; + uint64_t* Heap_high; + uint64_t* Heap_segmap_low; + uint64_t* Heap_segmap_high; + + int32_t SIZE_CodeCache_log2_segment; + + uint64_t methodPtr; + uint64_t bcp; + + Nmethod_t *N; /*Inlined methods support */ + Frame_t prev_fr; + Frame_t curr_fr; +}; + +static int +read_string(struct ps_prochandle *P, + char *buf, /* caller's buffer */ + size_t size, /* upper limit on bytes to read */ + uintptr_t addr) /* address in process */ +{ + int err = PS_OK; + while (size-- > 1 && err == PS_OK) { + err = ps_pread(P, addr, buf, 1); + if (*buf == '\0') { + return PS_OK; + } + addr += 1; + buf += 1; + } + return -1; +} + +static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) { + int err = -1; + uint32_t ptr32; + err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); + *ptr = ptr32; + return err; +} + +static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) { + int err = -1; + uint32_t ptr32; + + switch (DATA_MODEL) { + case PR_MODEL_LP64: + err = ps_pread(J->P, base, ptr, sizeof(uint64_t)); + break; + case PR_MODEL_ILP32: + err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t)); + *ptr = ptr32; + break; + } + + return err; +} + +static int read_string_pointer(jvm_agent_t* J, uint64_t base, const char ** stringp) { + uint64_t ptr; + int err; + char buffer[1024]; + + *stringp = NULL; + err = read_pointer(J, base, &ptr); + CHECK_FAIL(err); + if (ptr != 0) { + err = read_string(J->P, buffer, sizeof(buffer), ptr); + CHECK_FAIL(err); + *stringp = strdup(buffer); + } + return PS_OK; + + fail: + return err; +} + +static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) { + uint64_t ptr; + int err; + + err = read_string_pointer(J, base + OFFSET_VMStructEntrytypeName, &vmp->typeName); + CHECK_FAIL(err); + err = read_string_pointer(J, base + OFFSET_VMStructEntryfieldName, &vmp->fieldName); + CHECK_FAIL(err); + err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address); + CHECK_FAIL(err); + + return PS_OK; + + fail: + if (vmp->typeName != NULL) free((void*)vmp->typeName); + if (vmp->fieldName != NULL) free((void*)vmp->fieldName); + return err; +} + +static int parse_vmstructs(jvm_agent_t* J) { + VMStructEntry vmVar; + VMStructEntry* vmp = &vmVar; + uint64_t gHotSpotVMStructs; + psaddr_t sym_addr; + uint64_t base; + int err; + + /* Clear *vmp now in case we jump to fail: */ + memset(vmp, 0, sizeof(VMStructEntry)); + + err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr); + CHECK_FAIL(err); + err = read_pointer(J, sym_addr, &gHotSpotVMStructs); + CHECK_FAIL(err); + base = gHotSpotVMStructs; + + err = PS_OK; + while (err == PS_OK) { + memset(vmp, 0, sizeof(VMStructEntry)); + err = parse_vmstruct_entry(J, base, vmp); + if (err != PS_OK || vmp->typeName == NULL) { + break; + } + + if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) { + /* Read _heaps field of type GrowableArray* */ + if (strcmp("_heaps", vmp->fieldName) == 0) { + err = read_pointer(J, vmp->address, &J->CodeCache_heaps_address); + } + } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) { + if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) { + J->Universe_narrow_oop_base_address = vmp->address; + } + if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) { + J->Universe_narrow_oop_shift_address = vmp->address; + } + } + CHECK_FAIL(err); + + base += SIZE_VMStructEntry; + if (vmp->typeName != NULL) free((void*)vmp->typeName); + if (vmp->fieldName != NULL) free((void*)vmp->fieldName); + } + + return PS_OK; + + fail: + if (vmp->typeName != NULL) free((void*)vmp->typeName); + if (vmp->fieldName != NULL) free((void*)vmp->fieldName); + return -1; +} + +static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) { + psaddr_t sym_addr; + int err; + + err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); + if (err != PS_OK) goto fail; + *valuep = sym_addr; + return PS_OK; + + fail: + return err; +} + +static int read_volatiles(jvm_agent_t* J) { + int i; + uint64_t array_data; + uint64_t code_heap_address; + int err; + + err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address); + if (err == PS_OK) { + err = ps_pread(J->P, J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t)); + CHECK_FAIL(err); + } else { + J->Use_Compressed_Oops = 0; + } + + err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base); + CHECK_FAIL(err); + err = ps_pread(J->P, J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t)); + CHECK_FAIL(err); + + /* CodeCache_heaps_address points to GrowableArray, read _data field + pointing to the first entry of type CodeCache* in the array */ + err = read_pointer(J, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_data, &array_data); + /* Read _len field containing the number of code heaps */ + err = ps_pread(J->P, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_len, + &J->Number_of_heaps, sizeof(J->Number_of_heaps)); + + /* Allocate memory for heap configurations */ + J->Heap_low = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); + J->Heap_high = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); + J->Heap_segmap_low = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); + J->Heap_segmap_high = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t)); + + /* Read code heap configurations */ + for (i = 0; i < J->Number_of_heaps; ++i) { + /* Read address of heap */ + err = read_pointer(J, array_data, &code_heap_address); + CHECK_FAIL(err); + + err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory + + OFFSET_VirtualSpace_low, &J->Heap_low[i]); + CHECK_FAIL(err); + err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory + + OFFSET_VirtualSpace_high, &J->Heap_high[i]); + CHECK_FAIL(err); + err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap + + OFFSET_VirtualSpace_low, &J->Heap_segmap_low[i]); + CHECK_FAIL(err); + err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap + + OFFSET_VirtualSpace_high, &J->Heap_segmap_high[i]); + CHECK_FAIL(err); + + /* Increment pointer to next entry */ + array_data = array_data + POINTER_SIZE; + } + + err = ps_pread(J->P, code_heap_address + OFFSET_CodeHeap_log2_segment_size, + &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment)); + CHECK_FAIL(err); + + return PS_OK; + + fail: + return err; +} + +static int codeheap_contains(int heap_num, jvm_agent_t* J, uint64_t ptr) { + return (J->Heap_low[heap_num] <= ptr && ptr < J->Heap_high[heap_num]); +} + +static int codecache_contains(jvm_agent_t* J, uint64_t ptr) { + int i; + for (i = 0; i < J->Number_of_heaps; ++i) { + if (codeheap_contains(i, J, ptr)) { + return 1; + } + } + return 0; +} + +static uint64_t segment_for(int heap_num, jvm_agent_t* J, uint64_t p) { + return (p - J->Heap_low[heap_num]) >> J->SIZE_CodeCache_log2_segment; +} + +static uint64_t block_at(int heap_num, jvm_agent_t* J, int i) { + return J->Heap_low[heap_num] + (i << J->SIZE_CodeCache_log2_segment); +} + +static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) { + int err; + int i; + + for (i = 0; i < J->Number_of_heaps; ++i) { + *startp = 0; + if (codeheap_contains(i, J, ptr)) { + int32_t used; + uint64_t segment = segment_for(i, J, ptr); + uint64_t block = J->Heap_segmap_low[i]; + uint8_t tag; + err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); + CHECK_FAIL(err); + if (tag == 0xff) + return PS_OK; + while (tag > 0) { + err = ps_pread(J->P, block + segment, &tag, sizeof(tag)); + CHECK_FAIL(err); + segment -= tag; + } + block = block_at(i, J, segment); + err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used)); + CHECK_FAIL(err); + if (used) { + *startp = block + SIZE_HeapBlockHeader; + } + } + return PS_OK; + } + + fail: + return -1; +} + +static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) { + psaddr_t sym_addr; + int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr); + if (err == PS_OK) { + err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t)); + return err; + } + *valuep = -1; + return -1; +} + +jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) { + jvm_agent_t* J; + int err; + + if (vers != JVM_DB_VERSION) { + errno = ENOTSUP; + return NULL; + } + + J = (jvm_agent_t*)calloc(sizeof(struct jvm_agent), 1); + + debug = getenv("LIBJVMDB_DEBUG") != NULL; + if (debug) debug = 3; + + if (debug) { + fprintf(stderr, "Jagent_create: debug=%d\n", debug); +#ifdef X86_COMPILER2 + fprintf(stderr, "Jagent_create: R_SP=%d, R_FP=%d, POINTER_SIZE=%d\n", R_SP, R_FP, POINTER_SIZE); +#endif /* X86_COMPILER2 */ + } + + J->P = P; + + // Initialize the initial previous frame + + J->prev_fr.fp = 0; + J->prev_fr.pc = 0; + J->prev_fr.sp = 0; + J->prev_fr.sender_sp = 0; + + err = find_symbol(J, "__1cHnmethodG__vtbl_", &J->nmethod_vtbl); + CHECK_FAIL(err); + err = find_symbol(J, "__1cKBufferBlobG__vtbl_", &J->BufferBlob_vtbl); + if (err != PS_OK) J->BufferBlob_vtbl = 0; + err = find_symbol(J, "__1cICodeBlobG__vtbl_", &J->CodeBlob_vtbl); + CHECK_FAIL(err); + err = find_symbol(J, "__1cLRuntimeStubG__vtbl_", &J->RuntimeStub_vtbl); + CHECK_FAIL(err); + err = find_symbol(J, "__1cGMethodG__vtbl_", &J->Method_vtbl); + CHECK_FAIL(err); + + err = parse_vmstructs(J); + CHECK_FAIL(err); + err = read_volatiles(J); + CHECK_FAIL(err); + + return J; + + fail: + Jagent_destroy(J); + return NULL; +} + +void Jagent_destroy(jvm_agent_t *J) { + if (J != NULL) { + free(J); + } +} + +static int is_method(jvm_agent_t* J, uint64_t methodPtr) { + uint64_t klass; + int err = read_pointer(J, methodPtr, &klass); + if (err != PS_OK) goto fail; + return klass == J->Method_vtbl; + + fail: + return 0; +} + +static int +name_for_methodPtr(jvm_agent_t* J, uint64_t methodPtr, char * result, size_t size) +{ + short nameIndex; + short signatureIndex; + uint64_t constantPool; + uint64_t constMethod; + uint64_t nameSymbol; + uint64_t signatureSymbol; + uint64_t klassPtr; + uint64_t klassSymbol; + short klassSymbolLength; + short nameSymbolLength; + short signatureSymbolLength; + char * nameString = NULL; + char * klassString = NULL; + char * signatureString = NULL; + int err; + + err = read_pointer(J, methodPtr + OFFSET_Method_constMethod, &constMethod); + CHECK_FAIL(err); + err = read_pointer(J, constMethod + OFFSET_ConstMethod_constants, &constantPool); + CHECK_FAIL(err); + + /* To get name string */ + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_name_index, &nameIndex, 2); + CHECK_FAIL(err); + err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_ConstantPool, &nameSymbol); + CHECK_FAIL(err); + // The symbol is a CPSlot and has lower bit set to indicate metadata + nameSymbol &= (~1); // remove metadata lsb + err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2); + CHECK_FAIL(err); + nameString = (char*)calloc(nameSymbolLength + 1, 1); + err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_body, nameString, nameSymbolLength); + CHECK_FAIL(err); + + /* To get signature string */ + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_signature_index, &signatureIndex, 2); + CHECK_FAIL(err); + err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_ConstantPool, &signatureSymbol); + CHECK_FAIL(err); + signatureSymbol &= (~1); // remove metadata lsb + err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2); + CHECK_FAIL(err); + signatureString = (char*)calloc(signatureSymbolLength + 1, 1); + err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_body, signatureString, signatureSymbolLength); + CHECK_FAIL(err); + + /* To get klass string */ + err = read_pointer(J, constantPool + OFFSET_ConstantPool_pool_holder, &klassPtr); + CHECK_FAIL(err); + err = read_pointer(J, klassPtr + OFFSET_Klass_name, &klassSymbol); + CHECK_FAIL(err); + err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_length, &klassSymbolLength, 2); + CHECK_FAIL(err); + klassString = (char*)calloc(klassSymbolLength + 1, 1); + err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_body, klassString, klassSymbolLength); + CHECK_FAIL(err); + + result[0] = '\0'; + if (snprintf(result, size, + "%s.%s%s", + klassString, + nameString, + signatureString) >= size) { + // truncation + goto fail; + } + + if (nameString != NULL) free(nameString); + if (klassString != NULL) free(klassString); + if (signatureString != NULL) free(signatureString); + + return PS_OK; + + fail: + if (debug) { + fprintf(stderr, "name_for_methodPtr: FAIL \n\n"); + } + if (nameString != NULL) free(nameString); + if (klassString != NULL) free(klassString); + if (signatureString != NULL) free(signatureString); + return -1; +} + +static int nmethod_info(Nmethod_t *N) +{ + jvm_agent_t *J = N->J; + uint64_t nm = N->nm; + int32_t err; + + if (debug > 2 ) + fprintf(stderr, "\t nmethod_info: BEGIN \n"); + + /* Instructions */ + err = read_pointer(J, nm + OFFSET_CodeBlob_code_begin, &N->instrs_beg); + CHECK_FAIL(err); + err = read_pointer(J, nm + OFFSET_CodeBlob_code_end, &N->instrs_end); + CHECK_FAIL(err); + err = read_pointer(J, nm + OFFSET_nmethod_deopt_handler_begin, &N->deopt_beg); + CHECK_FAIL(err); + err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32); + CHECK_FAIL(err); + + /* Metadata */ + err = ps_pread(J->P, nm + OFFSET_nmethod_metadata_offset, &N->metadata_beg, SZ32); + CHECK_FAIL(err); + err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_begin, &N->metadata_end, SZ32); + CHECK_FAIL(err); + + /* scopes_pcs */ + err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32); + CHECK_FAIL(err); + err = ps_pread(J->P, nm + OFFSET_nmethod_dependencies_offset, &N->scopes_pcs_end, SZ32); + CHECK_FAIL(err); + + /* scopes_data */ + err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_begin, &N->scopes_data_beg, POINTER_SIZE); + CHECK_FAIL(err); + + if (debug > 2 ) { + N->scopes_data_end = N->scopes_pcs_beg; + + fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n", + N->instrs_beg, N->instrs_end); + + fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n", + N->deopt_beg); + + fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n", + N->orig_pc_offset); + + fprintf(stderr, "\t nmethod_info: metadata_beg: %#x, metadata_end: %#x\n", + N->metadata_beg, N->metadata_end); + + fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n", + N->scopes_data_beg, N->scopes_data_end); + + fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n", + N->scopes_pcs_beg, N->scopes_pcs_end); + + fprintf(stderr, "\t nmethod_info: END \n\n"); + } + return PS_OK; + + fail: + return err; +} + +static int +raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val) +{ + int shift = 0; + int value = 0; + uint8_t ch = 0; + int32_t err; + int32_t sum; + // Constants for UNSIGNED5 coding of Pack200 + // see compressedStream.hpp + enum { + lg_H = 6, + H = 1<P, (*buffer)++, &ch, sizeof(uint8_t)); + CHECK_FAIL(err); + if (debug > 2) + fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch); + + sum = ch; + if ( sum >= L ) { + int32_t lg_H_i = lg_H; + // Read maximum of 5 total bytes (we've already read 1). + // See CompressedReadStream::read_int_mb + for ( i = 0; i < 4; i++) { + err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t)); + CHECK_FAIL(err); + sum += ch << lg_H_i; + if (ch < L ) { + *val = sum; + return PS_OK; + } + lg_H_i += lg_H; + } + } + *val = sum; + return PS_OK; + + fail: + return err; +} + +static int +read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line) +{ + uint8_t next = 0; + int32_t bci_delta; + int32_t line_delta; + int32_t err; + + if (debug > 2) + fprintf(stderr, "\t\t read_pair: BEGIN\n"); + + err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t)); + CHECK_FAIL(err); + + if (next == 0) { + if (debug > 2) + fprintf(stderr, "\t\t read_pair: END: next == 0\n"); + return 1; /* stream terminated */ + } + if (next == 0xFF) { + if (debug > 2) + fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n"); + + /* Escape character, regular compression used */ + + err = raw_read_int(J, buffer, &bci_delta); + CHECK_FAIL(err); + + err = raw_read_int(J, buffer, &line_delta); + CHECK_FAIL(err); + + *bci += bci_delta; + *line += line_delta; + + if (debug > 2) { + fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", + line_delta, bci_delta); + fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", + *line, *bci); + } + } else { + /* Single byte compression used */ + *bci += next >> 3; + *line += next & 0x7; + if (debug > 2) { + fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n", + next & 0x7, next >> 3); + fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n", + *line, *bci); + } + } + if (debug > 2) + fprintf(stderr, "\t\t read_pair: END\n"); + return PS_OK; + + fail: + if (debug) + fprintf(stderr, "\t\t read_pair: FAIL\n"); + return err; +} + +static int +line_number_from_bci(jvm_agent_t* J, Vframe_t *vf) +{ + uint64_t buffer; + uint16_t code_size; + uint64_t code_end_delta; + uint64_t constMethod; + int8_t access_flags; + int32_t best_bci = 0; + int32_t stream_bci = 0; + int32_t stream_line = 0; + int32_t err; + + if (debug > 2) { + char name[256]; + err = name_for_methodPtr(J, vf->method, name, 256); + CHECK_FAIL(err); + fprintf(stderr, "\t line_number_from_bci: BEGIN, method name: %s, targ bci: %d\n", + name, vf->bci); + } + + err = read_pointer(J, vf->method + OFFSET_Method_constMethod, &constMethod); + CHECK_FAIL(err); + + vf->line = 0; + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_flags, &access_flags, sizeof(int8_t)); + CHECK_FAIL(err); + + if (!(access_flags & ConstMethod_has_linenumber_table)) { + if (debug > 2) + fprintf(stderr, "\t line_number_from_bci: END: !HAS_LINE_NUMBER_TABLE \n\n"); + return PS_OK; + } + + /* The line numbers are a short array of 2-tuples [start_pc, line_number]. + * Not necessarily sorted and not necessarily one-to-one. + */ + + err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_code_size, &code_size, SZ16); + CHECK_FAIL(err); + + /* inlined_table_start() */ + code_end_delta = (uint64_t) (access_flags & AccessFlags_NATIVE) ? 2*POINTER_SIZE : 0; + buffer = constMethod + (uint64_t) SIZE_ConstMethod + (uint64_t) code_size + code_end_delta; + + if (debug > 2) { + fprintf(stderr, "\t\t line_number_from_bci: method: %#llx, native: %d\n", + vf->method, (access_flags & AccessFlags_NATIVE)); + fprintf(stderr, "\t\t line_number_from_bci: buffer: %#llx, code_size: %d\n", + buffer, (int) code_size); + } + + while (read_pair(J, &buffer, &stream_bci, &stream_line) == 0) { + if (stream_bci == vf->bci) { + /* perfect match */ + if (debug > 2) + fprintf(stderr, "\t line_number_from_bci: END: exact line: %d \n\n", vf->line); + vf->line = stream_line; + return PS_OK; + } else { + /* update best_bci/line */ + if (stream_bci < vf->bci && stream_bci >= best_bci) { + best_bci = stream_bci; + vf->line = stream_line; + if (debug > 2) { + fprintf(stderr, "\t line_number_from_bci: best_bci: %d, best_line: %d\n", + best_bci, vf->line); + } + } + } + } + if (debug > 2) + fprintf(stderr, "\t line_number_from_bci: END: line: %d \n\n", vf->line); + return PS_OK; + + fail: + if (debug) + fprintf(stderr, "\t line_number_from_bci: FAIL\n"); + return err; +} + +static int +get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc) +{ + int32_t pc_offset; + int32_t err; + + err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32); + CHECK_FAIL(err); + + *real_pc = N->instrs_beg + pc_offset; + if (debug > 2) { + fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n", + pc_offset, *real_pc); + } + return PS_OK; + + fail: + return err; +} + +/* Finds a PcDesc with real-pc equal to N->pc */ +static int pc_desc_at(Nmethod_t *N) +{ + uint64_t pc_diff = 999; + int32_t offs; + int32_t err; + + if (debug > 2) + fprintf(stderr, "\t pc_desc_at: BEGIN\n"); + + N->vf_cnt = 0; + N->pc_desc = 0; + + for (offs = N->scopes_pcs_beg; offs < N->scopes_pcs_end; offs += SIZE_PcDesc) { + uint64_t pd; + uint64_t best_pc_diff = 16; /* some approximation */ + uint64_t real_pc = 0; + + pd = N->nm + offs; + err = get_real_pc(N, pd, &real_pc); + CHECK_FAIL(err); + + pc_diff = real_pc - N->pc; + + /* In general, this fragment should work */ + if (pc_diff == 0) { + N->pc_desc = pd; + if (debug) { + fprintf(stderr, "\t pc_desc_at: END: pc_desc: FOUND: %#lx \n\n", pd); + } + return PS_OK; + } + /* This fragment is to be able to find out an appropriate + * pc_desc entry even if pc_desc info is inaccurate. + */ + if (best_pc_diff > pc_diff && pc_diff > 0) { + best_pc_diff = pc_diff; + N->pc_desc = pd; + } + } + if (debug) { + fprintf(stderr, "\t pc_desc_at: END: pc_desc NOT FOUND"); + if (pc_diff < 20) + fprintf(stderr, ", best pc_diff: %d\n\n", pc_diff); + else + fprintf(stderr, "\n\n"); + } + return PS_OK; + + fail: + return err; +} + +static int +scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf) +{ + uint64_t buffer; + int32_t err; + + if (debug > 2) { + fprintf(stderr, "\t\t scope_desc_at: BEGIN \n"); + } + + buffer = N->scopes_data_beg + decode_offset; + + err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset); + CHECK_FAIL(err); + + err = raw_read_int(N->J, &buffer, &vf->methodIdx); + CHECK_FAIL(err); + + err = raw_read_int(N->J, &buffer, &vf->bci); + CHECK_FAIL(err); + + if (debug > 2) { + fprintf(stderr, "\t\t scope_desc_at: sender_decode_offset: %#x\n", + vf->sender_decode_offset); + fprintf(stderr, "\t\t scope_desc_at: methodIdx: %d\n", vf->methodIdx); + fprintf(stderr, "\t\t scope_desc_at: bci: %d\n", vf->bci); + + fprintf(stderr, "\t\t scope_desc_at: END \n\n"); + } + return PS_OK; + + fail: + return err; +} + +static int scopeDesc_chain(Nmethod_t *N) { + int32_t decode_offset = 0; + int32_t err; + + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: BEGIN\n"); + } + + err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset, + &decode_offset, SZ32); + CHECK_FAIL(err); + + while (decode_offset > 0) { + Vframe_t *vf = &N->vframes[N->vf_cnt]; + + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset); + } + + err = scope_desc_at(N, decode_offset, vf); + CHECK_FAIL(err); + + if (vf->methodIdx > ((N->metadata_end - N->metadata_beg) / POINTER_SIZE)) { + fprintf(stderr, "\t scopeDesc_chain: (methodIdx > metadata length) !\n"); + return -1; + } + err = read_pointer(N->J, N->nm + N->metadata_beg + (vf->methodIdx-1)*POINTER_SIZE, + &vf->method); + CHECK_FAIL(err); + + if (vf->method) { + N->vf_cnt++; + err = line_number_from_bci(N->J, vf); + CHECK_FAIL(err); + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: method: %#8llx, line: %d\n", + vf->method, vf->line); + } + } + decode_offset = vf->sender_decode_offset; + } + if (debug > 2) { + fprintf(stderr, "\t scopeDesc_chain: END \n\n"); + } + return PS_OK; + + fail: + if (debug) { + fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n"); + } + return err; +} + + +static int +name_for_nmethod(jvm_agent_t* J, + uint64_t nm, + uint64_t pc, + uint64_t method, + char *result, + size_t size, + Jframe_t *jframe +) { + Nmethod_t *N; + Vframe_t *vf; + int32_t err; + int deoptimized = 0; + + if (debug) { + fprintf(stderr, "name_for_nmethod: BEGIN: nmethod: %#llx, pc: %#llx\n", nm, pc); + } + if (J->N == NULL) { + J->N = (Nmethod_t *) malloc(sizeof(Nmethod_t)); + } + memset(J->N, 0, sizeof(Nmethod_t)); /* Initial stat: all values are zeros */ + N = J->N; + N->J = J; + N->nm = nm; + N->pc = pc; + N->jframe = jframe; + + err = nmethod_info(N); + CHECK_FAIL(err); + if (debug) { + fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc: %#llx\n", + pc, N->deopt_beg); + } + + /* check for a deoptimized frame */ + if ( pc == N->deopt_beg) { + uint64_t base; + if (debug) { + fprintf(stderr, "name_for_nmethod: found deoptimized frame\n"); + } + if (J->prev_fr.sender_sp != 0) { + base = J->prev_fr.sender_sp + N->orig_pc_offset; + } else { + base = J->curr_fr.sp + N->orig_pc_offset; + } + err = read_pointer(J, base, &N->pc); + CHECK_FAIL(err); + if (debug) { + fprintf(stderr, "name_for_nmethod: found deoptimized frame converting pc from %#8llx to %#8llx\n", + pc, N->pc); + } + deoptimized = 1; + } + + err = pc_desc_at(N); + CHECK_FAIL(err); + + if (N->pc_desc > 0) { + jframe->locinf = 1; + err = scopeDesc_chain(N); + CHECK_FAIL(err); + } + result[0] = COMP_METHOD_SIGN; + vf = &N->vframes[0]; + if (N->vf_cnt > 0) { + jframe->vf_cnt = N->vf_cnt; + jframe->bci = vf->bci; + jframe->line = vf->line; + err = name_for_methodPtr(J, N->vframes[0].method, result+1, size-1); + CHECK_FAIL(err); + } else { + err = name_for_methodPtr(J, method, result+1, size-1); + CHECK_FAIL(err); + } + if (deoptimized) { + strncat(result, " [deoptimized frame]; ", size - strlen(result) - 1); + } else { + strncat(result, " [compiled] ", size - strlen(result) - 1); + } + if (debug) + fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n", + result, N->vf_cnt); + return PS_OK; + + fail: + if (debug) + fprintf(stderr, "name_for_nmethod: FAIL \n\n"); + return err; +} + +static int +name_for_imethod(jvm_agent_t* J, + uint64_t bcp, + uint64_t method, + char *result, + size_t size, + Jframe_t *jframe +) { + uint64_t bci; + uint64_t constMethod; + Vframe_t vframe = {0}; + Vframe_t *vf = &vframe; + int32_t err; + + err = read_pointer(J, method + OFFSET_Method_constMethod, &constMethod); + CHECK_FAIL(err); + + bci = bcp - (constMethod + (uint64_t) SIZE_ConstMethod); + + if (debug) + fprintf(stderr, "\t name_for_imethod: BEGIN: method: %#llx\n", method); + + err = name_for_methodPtr(J, method, result, size); + CHECK_FAIL(err); + if (debug) + fprintf(stderr, "\t name_for_imethod: method name: %s\n", result); + + if (bci > 0) { + vf->method = method; + vf->bci = bci; + err = line_number_from_bci(J, vf); + CHECK_FAIL(err); + } + jframe->bci = vf->bci; + jframe->line = vf->line; + jframe->locinf = 1; + + if (debug) { + fprintf(stderr, "\t name_for_imethod: END: bci: %d, line: %d\n\n", + vf->bci, vf->line); + } + return PS_OK; + + fail: + if (debug) + fprintf(stderr, "\t name_for_imethod: FAIL\n"); + return err; +} + +static int +name_for_codecache(jvm_agent_t* J, uint64_t fp, uint64_t pc, char * result, + size_t size, Jframe_t *jframe, int* is_interpreted) +{ + uint64_t start; + uint64_t vtbl; + int32_t err; + *is_interpreted = 0; + + result[0] = '\0'; + + err = find_start(J, pc, &start); + CHECK_FAIL(err); + + err = read_pointer(J, start, &vtbl); + CHECK_FAIL(err); + + if (vtbl == J->nmethod_vtbl) { + uint64_t method; + + err = read_pointer(J, start + OFFSET_nmethod_method, &method); + CHECK_FAIL(err); + + if (debug) { + fprintf(stderr, "name_for_codecache: start: %#8llx, pc: %#8llx, method: %#8llx \n", + start, pc, method); + } + err = name_for_nmethod(J, start, pc, method, result, size, jframe); + CHECK_FAIL(err); + } else if (vtbl == J->BufferBlob_vtbl) { + const char * name; + + err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name); + + /* + * Temporary usage of string "Interpreter". + * We need some other way to distinguish "StubRoutines" + * and regular interpreted frames. + */ + if (err == PS_OK && strncmp(name, "Interpreter", 11) == 0) { + *is_interpreted = 1; + if (is_method(J, J->methodPtr)) { + return name_for_imethod(J, J->bcp, J->methodPtr, result, size, jframe); + } + } + + if (err == PS_OK) { + strncpy(result, name, size); + free((void*)name); + } else { + strncpy(result, "", size); + } + /* return PS_OK; */ + } else { + const char * name; + + err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name); + if (err == PS_OK) { + strncpy(result, name, size); + free((void*)name); + } else { + strncpy(result, "", size); + WARN1("unknown CodeBlob: vtbl = 0x%x", vtbl); + } + } + result[size-1] = '\0'; + +#ifdef X86_COMPILER2 + if (vtbl != J->RuntimeStub_vtbl) { + uint64_t trial_pc; + int frame_size; + err = ps_pread(J->P, start + OFFSET_CodeBlob_frame_size, + &frame_size, SZ32); + CHECK_FAIL(err); + + // frame_size is in words, we want bytes. + frame_size *= POINTER_SIZE; /* word => byte conversion */ + + /* + Because c2 doesn't use FP as a framepointer the value of sp/fp we receive + in the initial entry to a set of stack frames containing server frames + will pretty much be nonsense. We can detect that nonsense by looking to + see if the PC we received is correct if we look at the expected storage + location in relation to the FP (ie. POINTER_SIZE(FP) ) + */ + + err = read_pointer(J, fp + POINTER_SIZE , &trial_pc); + if ( (err != PS_OK || trial_pc != pc) && frame_size > 0 ) { + // Either we couldn't even read at the "fp" or the pc didn't match + // both are sure clues that the fp is bogus. We no search the stack + // for a reasonable number of words trying to find the bogus fp + // and the current pc in adjacent words. The we will be able to + // deduce an approximation of the frame pointer and actually get + // the correct stack pointer. Which we can then unwind for the + // next frame. + int i; + uint64_t check; + uint64_t base = J->curr_fr.sp; + uint64_t prev_fp = 0; + for ( i = 0; i < frame_size * 5 ; i++, base += POINTER_SIZE ) { + err = read_pointer(J, base , &check); + CHECK_FAIL(err); + if (check == fp) { + base += POINTER_SIZE; + err = read_pointer(J, base , &check); + CHECK_FAIL(err); + if (check == pc) { + if (debug) { + fprintf(stderr, "name_for_codecache: found matching fp/pc combo at 0x%llx\n", base - POINTER_SIZE); + } + prev_fp = base - 2 * POINTER_SIZE; + break; + } + } + } + if ( prev_fp != 0 ) { + // real_sp is the sp we should have received for this frame + uint64_t real_sp = prev_fp + 2 * POINTER_SIZE; + // +POINTER_SIZE because callee owns the return address so caller's sp is +1 word + jframe->new_sp = real_sp + frame_size + POINTER_SIZE; + err = read_pointer(J, jframe->new_sp - POINTER_SIZE , &jframe->new_pc); + CHECK_FAIL(err); + err = read_pointer(J, jframe->new_sp - 2*POINTER_SIZE, &jframe->new_fp); + CHECK_FAIL(err); + return PS_OK; + } + } + + /* A prototype to workaround FP absence */ + /* + * frame_size can be 0 for StubRoutines (1) frame. + * In this case it should work with fp as usual. + */ + if (frame_size > 0) { + jframe->new_fp = J->prev_fr.fp + frame_size; + jframe->new_sp = jframe->new_fp + 2 * POINTER_SIZE; + } else { + memset(&J->curr_fr, 0, sizeof(Frame_t)); + err = read_pointer(J, fp, &jframe->new_fp); + CHECK_FAIL(err); + + err = read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc); + CHECK_FAIL(err); + } + if (debug) { + fprintf(stderr, "name_for_codecache: %s, frame_size=%#lx\n", + result, frame_size); + fprintf(stderr, "name_for_codecache: prev_fr.fp=%#lx, fp=%#lx\n", + J->prev_fr.fp, jframe->new_fp); + } + } +#endif /* X86_COMPILER2 */ + + return PS_OK; + + fail: + return err; +} + +int Jget_vframe(jvm_agent_t* J, int vframe_no, + char *name, size_t size, Jframe_t *jframe) +{ + Nmethod_t *N = J->N; + Vframe_t *vf; + int32_t err; + + if (vframe_no >= N->vf_cnt) { + (void) sprintf(name, "Wrong inlinedMethod%1d()", vframe_no); + return -1; + } + vf = N->vframes + vframe_no; + name[0] = COMP_METHOD_SIGN; + err = name_for_methodPtr(J, vf->method, name + 1, size); + CHECK_FAIL(err); + + jframe->bci = vf->bci; + jframe->line = vf->line; + if (debug) { + fprintf(stderr, "\t Jget_vframe: method name: %s, line: %d\n", + name, vf->line); + } + return PS_OK; + + fail: + if (debug) { + fprintf(stderr, "\t Jget_vframe: FAIL\n"); + } + return err; +} + +#define MAX_SYM_SIZE 256 + +int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name, + size_t size, Jframe_t *jframe) { + uintptr_t fp; + uintptr_t pc; + /* arguments given to read_pointer need to be worst case sized */ + uint64_t methodPtr = 0; + uint64_t sender_sp; + uint64_t bcp = 0; + int is_interpreted = 0; + int result = PS_OK; + int err = PS_OK; + + if (J == NULL) { + return -1; + } + + jframe->vf_cnt = 1; + jframe->new_fp = 0; + jframe->new_pc = 0; + jframe->line = 0; + jframe->bci = 0; + jframe->locinf = 0; + + read_volatiles(J); + pc = (uintptr_t) regs[R_PC]; + J->curr_fr.pc = pc; + J->curr_fr.fp = regs[R_FP]; + J->curr_fr.sp = regs[R_SP]; + + if (debug) + fprintf(stderr, "Jlookup_by_regs: BEGINs: fp=%#lx, pc=%#lx\n", regs[R_FP], pc); + +#if defined(i386) || defined(__i386) || defined(__amd64) + + fp = (uintptr_t) regs[R_FP]; + if (J->prev_fr.fp == 0) { +#ifdef X86_COMPILER2 + /* A workaround for top java frames */ + J->prev_fr.fp = (uintptr_t)(regs[R_SP] - 2 * POINTER_SIZE); +#else + J->prev_fr.fp = (uintptr_t)(regs[R_SP] - POINTER_SIZE); +#endif /* COMPILER2 */ + } + if (debug > 2) { + printf("Jlookup_by_regs: J->prev_fr.fp = %#lx\n", J->prev_fr.fp); + } + + if (read_pointer(J, fp + OFFSET_interpreter_frame_method, &methodPtr) != PS_OK) { + methodPtr = 0; + } + if (read_pointer(J, fp + OFFSET_interpreter_frame_sender_sp, &sender_sp) != PS_OK) { + sender_sp = 0; + } + if (read_pointer(J, fp + OFFSET_interpreter_frame_bcp_offset, &bcp) != PS_OK) { + bcp = 0; + } +#endif /* i386 */ + + J->methodPtr = methodPtr; + 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. + * 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. + * So it is better to call codecache_contains(J, pc) from the beginning. + */ +#ifndef X86_COMPILER2 + if (is_method(J, J->methodPtr)) { + result = name_for_imethod(J, bcp, J->methodPtr, name, size, jframe); + /* If the methodPtr is a method then this is highly likely to be + an interpreter frame */ + if (result >= 0) { + is_interpreted = 1; + } + } else +#endif /* ! X86_COMPILER2 */ + + if (codecache_contains(J, pc)) { + result = name_for_codecache(J, fp, pc, name, size, jframe, &is_interpreted); + } +#ifdef X86_COMPILER2 + else if (is_method(J, J->methodPtr)) { + result = name_for_imethod(J, bcp, J->methodPtr, name, size, jframe); + /* If the methodPtr is a method then this is highly likely to be + an interpreter frame */ + if (result >= 0) { + is_interpreted = 1; + } + } +#endif /* X86_COMPILER2 */ + else { + if (debug) { + fprintf(stderr, "Jlookup_by_regs: END with -1\n\n"); + } + result = -1; + } + if (!is_interpreted) { + sender_sp = 0; + } + J->curr_fr.sender_sp = sender_sp; + +#ifdef X86_COMPILER2 + if (!J->curr_fr.fp) { + J->curr_fr.fp = (jframe->new_fp) ? jframe->new_fp : (uintptr_t)regs[R_FP]; + } + if (!jframe->new_pc && jframe->new_fp) { + // This seems dubious + read_pointer(J, jframe->new_fp + POINTER_SIZE, &jframe->new_pc); + CHECK_FAIL(err); + if (debug > 2) { + printf("Jlookup_by_regs: (update pc) jframe->new_fp: %#llx, jframe->new_pc: %#llx\n", + jframe->new_fp, jframe->new_pc); + } + } + +#endif /* X86_COMPILER2 */ + J->prev_fr = J->curr_fr; + + if (debug) + fprintf(stderr, "Jlookup_by_regs: END\n\n"); + + return result; + + fail: + return err; +} + +void update_gregs(prgregset_t gregs, Jframe_t jframe) { +#ifdef X86_COMPILER2 + if (debug > 0) { + fprintf(stderr, "update_gregs: before update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]); + } + /* + * A workaround for java C2 frames with unconventional FP. + * may have to modify regset with new values for FP/PC/SP when needed. + */ + if (jframe.new_sp) { + *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) jframe.new_sp; + } else { + // *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) gregs[R_FP] + 2 * POINTER_SIZE; + } + + if (jframe.new_fp) { + *((uintptr_t *) &gregs[R_FP]) = (uintptr_t) jframe.new_fp; + } + if (jframe.new_pc) { + *((uintptr_t *) &gregs[R_PC]) = (uintptr_t) jframe.new_pc; + } + if (debug > 0) { + fprintf(stderr, "update_gregs: after update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]); + } +#endif /* X86_COMPILER2 */ +} + +/* + * Iterates over java frames at current location given by 'gregs'. + * + * Returns -1 if no java frames are present or if an error is encountered. + * Returns the result of calling 'func' if the return value is non-zero. + * Returns 0 otherwise. + */ +int Jframe_iter(jvm_agent_t *J, prgregset_t gregs, java_stack_f *func, void* cld) { + char buf[MAX_SYM_SIZE + 1]; + Jframe_t jframe; + int i = 0, res; +#ifdef X86_COMPILER2 + if (debug > 0) { + fprintf(stderr, "Jframe_iter: Entry sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]); + } +#endif /* X86_COMPILER2 */ + + memset(&jframe, 0, sizeof(Jframe_t)); + memset(buf, 0, sizeof(buf)); + res = Jlookup_by_regs(J, gregs, buf, sizeof(buf), &jframe); + if (res != PS_OK) + return (-1); + + + res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1, + jframe.line, NULL); + if (res != 0) { + update_gregs(gregs, jframe); + return (res); + } + for (i = 1; i < jframe.vf_cnt; i++) { + Jget_vframe(J, i, buf, sizeof(buf), &jframe); + res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1, + jframe.line, NULL); + if (res != 0) { + update_gregs(gregs, jframe); + return (res); + } + } + update_gregs(gregs, jframe); + return (0); +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.h jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.h 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.h 2024-01-27 14:37:30.302820832 +0100 @@ -0,0 +1,69 @@ +/* + * 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. + * + */ + +#ifndef OS_SOLARIS_DTRACE_LIBJVM_DB_H +#define OS_SOLARIS_DTRACE_LIBJVM_DB_H + +#include +#include "jni.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct jvm_agent jvm_agent_t; + +#define JVM_DB_VERSION 1 + +JNIEXPORT jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers); + +/* + * Called from Jframe_iter() for each java frame. If it returns 0, then + * Jframe_iter() proceeds to the next frame. Otherwise, the return value is + * immediately returned to the caller of Jframe_iter(). + * + * Parameters: + * 'cld' is client supplied data (to maintain iterator state, if any). + * 'name' is java method name. + * 'bci' is byte code index. it will be -1 if not available. + * 'line' is java source line number. it will be 0 if not available. + * 'handle' is an abstract client handle, reserved for future expansions + */ + +typedef int java_stack_f(void *cld, const prgregset_t regs, const char* name, int bci, int line, void *handle); + +/* + * Iterates over the java frames at the current location. Returns -1 if no java + * frames were found, or if there was some unrecoverable error. Otherwise, + * returns the last value returned from 'func'. + */ +JNIEXPORT int Jframe_iter(jvm_agent_t *agent, prgregset_t gregs, java_stack_f *func, void* cld); + +JNIEXPORT void Jagent_destroy(jvm_agent_t *J); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif // OS_SOLARIS_DTRACE_LIBJVM_DB_H diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c 2024-01-27 14:37:30.303346224 +0100 @@ -0,0 +1,562 @@ +/* + * Copyright (c) 2006, 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jvm_dtrace.h" + +// NOTE: These constants are used in JVM code as well. +// KEEP JVM CODE IN SYNC if you are going to change these... + +#define DTRACE_ALLOC_PROBES 0x1 +#define DTRACE_METHOD_PROBES 0x2 +#define DTRACE_MONITOR_PROBES 0x4 +#define DTRACE_ALL_PROBES -1 + +// 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" + +// error messages for attach +#define JVM_ERR_CANT_OPEN_DOOR "cannot open door file" +#define JVM_ERR_CANT_CREATE_ATTACH_FILE "cannot create attach file" +#define JVM_ERR_DOOR_FILE_PERMISSION "door file is not secure" +#define JVM_ERR_CANT_SIGNAL "cannot send SIGQUIT to target" + +// error messages for enable probe +#define JVM_ERR_DOOR_CMD_SEND "door command send failed" +#define JVM_ERR_DOOR_CANT_READ_STATUS "cannot read door command status" +#define JVM_ERR_DOOR_CMD_STATUS "door command error status" + +// error message for detach +#define JVM_ERR_CANT_CLOSE_DOOR "cannot close door file" + +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + +struct _jvm_t { + pid_t pid; + int door_fd; +}; + +static int libjvm_dtrace_debug; +static void print_debug(const char* fmt,...) { + if (libjvm_dtrace_debug) { + va_list alist; + va_start(alist, fmt); + fputs("libjvm_dtrace DEBUG: ", stderr); + vfprintf(stderr, fmt, alist); + va_end(alist); + } +} + +/* Key for thread local error message */ +static thread_key_t jvm_error_key; + +/* init function for this library */ +static void init_jvm_dtrace() { + /* check for env. var for debug mode */ + libjvm_dtrace_debug = getenv("LIBJVM_DTRACE_DEBUG") != NULL; + /* create key for thread local error message */ + if (thr_keycreate(&jvm_error_key, NULL) != 0) { + print_debug("can't create thread_key_t for jvm error key\n"); + // exit(1); ? + } +} + +#pragma init(init_jvm_dtrace) + +/* set thread local error message */ +static void set_jvm_error(const char* msg) { + thr_setspecific(jvm_error_key, (void*)msg); +} + +/* clear thread local error message */ +static void clear_jvm_error() { + thr_setspecific(jvm_error_key, NULL); +} + +/* file handling functions that can handle interrupt */ + +static int file_open(const char* path, int flag) { + int ret; + RESTARTABLE(open(path, flag), ret); + return ret; +} + +static int file_close(int fd) { + return close(fd); +} + +static int file_read(int fd, char* buf, int len) { + int ret; + RESTARTABLE(read(fd, buf, len), ret); + return ret; +} + +/* send SIGQUIT signal to given process */ +static int send_sigquit(pid_t pid) { + int ret; + RESTARTABLE(kill(pid, SIGQUIT), ret); + return ret; +} + +/* called to check permissions on attach file */ +static int check_permission(const char* path) { + struct stat64 sb; + uid_t uid, gid; + int res; + + /* + * Check that the path is owned by the effective uid/gid of this + * process. Also check that group/other access is not allowed. + */ + uid = geteuid(); + gid = getegid(); + + res = stat64(path, &sb); + if (res != 0) { + print_debug("stat failed for %s\n", path); + return -1; + } + + if ((sb.st_uid != uid) || (sb.st_gid != gid) || + ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0)) { + print_debug("well-known file %s is not secure\n", path); + return -1; + } + return 0; +} + +#define ATTACH_FILE_PATTERN "/tmp/.attach_pid%d" + +/* fill-in the name of attach file name in given buffer */ +static void fill_attach_file_name(char* path, int len, pid_t pid) { + memset(path, 0, len); + sprintf(path, ATTACH_FILE_PATTERN, pid); +} + +#define DOOR_FILE_PATTERN "/tmp/.java_pid%d" + +/* open door file for the given JVM */ +static int open_door(pid_t pid) { + char path[PATH_MAX + 1]; + int fd; + + sprintf(path, DOOR_FILE_PATTERN, pid); + fd = file_open(path, O_RDONLY); + if (fd < 0) { + set_jvm_error(JVM_ERR_CANT_OPEN_DOOR); + print_debug("cannot open door file %s\n", path); + return -1; + } + print_debug("opened door file %s\n", path); + if (check_permission(path) != 0) { + set_jvm_error(JVM_ERR_DOOR_FILE_PERMISSION); + print_debug("check permission failed for %s\n", path); + file_close(fd); + fd = -1; + } + return fd; +} + +/* create attach file for given process */ +static int create_attach_file(pid_t pid) { + char path[PATH_MAX + 1]; + int fd; + fill_attach_file_name(path, sizeof(path), pid); + fd = file_open(path, O_CREAT | O_RDWR); + if (fd < 0) { + set_jvm_error(JVM_ERR_CANT_CREATE_ATTACH_FILE); + print_debug("cannot create file %s\n", path); + } else { + print_debug("created attach file %s\n", path); + } + return fd; +} + +/* delete attach file for given process */ +static void delete_attach_file(pid_t pid) { + char path[PATH_MAX + 1]; + fill_attach_file_name(path, sizeof(path), pid); + int res = unlink(path); + if (res) { + print_debug("cannot delete attach file %s\n", path); + } else { + print_debug("deleted attach file %s\n", path); + } +} + +/* attach to given JVM */ +jvm_t* jvm_attach(pid_t pid) { + jvm_t* jvm; + int door_fd, attach_fd, i = 0; + + jvm = (jvm_t*) calloc(1, sizeof(jvm_t)); + if (jvm == NULL) { + set_jvm_error(JVM_ERR_OUT_OF_MEMORY); + print_debug("calloc failed in %s at %d\n", __FILE__, __LINE__); + return NULL; + } + jvm->pid = pid; + attach_fd = -1; + + door_fd = open_door(pid); + if (door_fd < 0) { + print_debug("trying to create attach file\n"); + if ((attach_fd = create_attach_file(pid)) < 0) { + goto quit; + } + + /* send QUIT signal to the target so that it will + * check for the attach file. + */ + if (send_sigquit(pid) != 0) { + set_jvm_error(JVM_ERR_CANT_SIGNAL); + print_debug("sending SIGQUIT failed\n"); + goto quit; + } + + /* give the target VM time to start the attach mechanism */ + do { + int res; + RESTARTABLE(poll(0, 0, 200), res); + door_fd = open_door(pid); + i++; + } while (i <= 50 && door_fd == -1); + if (door_fd < 0) { + print_debug("Unable to open door to process %d\n", pid); + goto quit; + } + } + +quit: + if (attach_fd >= 0) { + file_close(attach_fd); + delete_attach_file(jvm->pid); + } + if (door_fd >= 0) { + jvm->door_fd = door_fd; + clear_jvm_error(); + } else { + free(jvm); + jvm = NULL; + } + return jvm; +} + +/* return the last thread local error message */ +const char* jvm_get_last_error() { + const char* res = NULL; + thr_getspecific(jvm_error_key, (void**)&res); + return res; +} + +/* detach the givenb JVM */ +int jvm_detach(jvm_t* jvm) { + if (jvm) { + int res = 0; + if (jvm->door_fd != -1) { + if (file_close(jvm->door_fd) != 0) { + set_jvm_error(JVM_ERR_CANT_CLOSE_DOOR); + res = -1; + } else { + clear_jvm_error(); + } + } + free(jvm); + return res; + } else { + set_jvm_error(JVM_ERR_NULL_PARAM); + print_debug("jvm_t* is NULL\n"); + return -1; + } +} + +/* + * A simple table to translate some known errors into reasonable + * error messages + */ +static struct { + int err; + const char* msg; +} const error_messages[] = { + { 100, "Bad request" }, + { 101, "Protocol mismatch" }, + { 102, "Resource failure" }, + { 103, "Internal error" }, + { 104, "Permission denied" }, +}; + +/* + * Lookup the given error code and return the appropriate + * message. If not found return NULL. + */ +static const char* translate_error(int err) { + int table_size = sizeof(error_messages) / sizeof(error_messages[0]); + int i; + + for (i=0; i\0\0 + */ + if (cstr == NULL) { + print_debug("command name is NULL\n"); + goto quit; + } + size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2; + buf = (char*)malloc(size); + if (buf != NULL) { + char* pos = buf; + strcpy(buf, PROTOCOL_VERSION); + pos += strlen(PROTOCOL_VERSION)+1; + strcpy(pos, cstr); + } else { + set_jvm_error(JVM_ERR_OUT_OF_MEMORY); + print_debug("malloc failed at %d in %s\n", __LINE__, __FILE__); + goto quit; + } + + /* + * Next we iterate over the arguments and extend the buffer + * to include them. + */ + for (i=0; idoor_fd, &door_args), rc); + + /* + * door_call failed + */ + if (rc == -1) { + print_debug("door_call failed\n"); + } else { + /* + * door_call succeeded but the call didn't return the expected jint. + */ + if (door_args.data_size < sizeof(int)) { + print_debug("Enqueue error - reason unknown as result is truncated!"); + } else { + int* res = (int*)(door_args.data_ptr); + if (*res != 0) { + const char* msg = translate_error(*res); + if (msg == NULL) { + print_debug("Unable to enqueue command to target VM: %d\n", *res); + } else { + print_debug("Unable to enqueue command to target VM: %s\n", msg); + } + } else { + /* + * The door call should return a file descriptor to one end of + * a socket pair + */ + if ((door_args.desc_ptr != NULL) && + (door_args.desc_num == 1) && + (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) { + result = door_args.desc_ptr->d_data.d_desc.d_descriptor; + } else { + print_debug("Reply from enqueue missing descriptor!\n"); + } + } + } + } + +quit: + if (buf) free(buf); + return result; +} + +/* read status code for a door command */ +static int read_status(int fd) { + char ch, buf[16]; + int index = 0; + + while (1) { + if (file_read(fd, &ch, sizeof(ch)) != sizeof(ch)) { + set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS); + print_debug("door cmd status: read status failed\n"); + return -1; + } + buf[index++] = ch; + if (ch == '\n') { + buf[index - 1] = '\0'; + return atoi(buf); + } + if (index == sizeof(buf)) { + set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS); + print_debug("door cmd status: read status overflow\n"); + return -1; + } + } +} + +static const char* ENABLE_DPROBES_CMD = "enabledprobes"; + +/* enable one or more DTrace probes for a given JVM */ +int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types) { + int fd, status = 0; + char ch; + const char* args[1]; + char buf[16]; + int probe_type = 0, index; + int count = 0; + + if (jvm == NULL) { + set_jvm_error(JVM_ERR_NULL_PARAM); + print_debug("jvm_t* is NULL\n"); + return -1; + } + + if (num_probe_types == 0 || probe_types == NULL || + probe_types[0] == NULL) { + set_jvm_error(JVM_ERR_INVALID_PARAM); + print_debug("invalid probe type argument(s)\n"); + return -1; + } + + for (index = 0; index < num_probe_types; index++) { + const char* p = probe_types[index]; + if (strcmp(p, JVM_DTPROBE_OBJECT_ALLOC) == 0) { + probe_type |= DTRACE_ALLOC_PROBES; + count++; + } else if (strcmp(p, JVM_DTPROBE_METHOD_ENTRY) == 0 || + strcmp(p, JVM_DTPROBE_METHOD_RETURN) == 0) { + probe_type |= DTRACE_METHOD_PROBES; + count++; + } else if (strcmp(p, JVM_DTPROBE_MONITOR_ENTER) == 0 || + strcmp(p, JVM_DTPROBE_MONITOR_ENTERED) == 0 || + strcmp(p, JVM_DTPROBE_MONITOR_EXIT) == 0 || + strcmp(p, JVM_DTPROBE_MONITOR_WAIT) == 0 || + strcmp(p, JVM_DTPROBE_MONITOR_WAITED) == 0 || + strcmp(p, JVM_DTPROBE_MONITOR_NOTIFY) == 0 || + strcmp(p, JVM_DTPROBE_MONITOR_NOTIFYALL) == 0) { + probe_type |= DTRACE_MONITOR_PROBES; + count++; + } else if (strcmp(p, JVM_DTPROBE_ALL) == 0) { + probe_type |= DTRACE_ALL_PROBES; + count++; + } + } + + if (count == 0) { + return count; + } + sprintf(buf, "%d", probe_type); + args[0] = buf; + + fd = enqueue_command(jvm, ENABLE_DPROBES_CMD, 1, args); + if (fd < 0) { + set_jvm_error(JVM_ERR_DOOR_CMD_SEND); + return -1; + } + + status = read_status(fd); + // non-zero status is error + if (status) { + set_jvm_error(JVM_ERR_DOOR_CMD_STATUS); + print_debug("%s command failed (status: %d) in target JVM\n", + ENABLE_DPROBES_CMD, status); + file_close(fd); + return -1; + } + // read from stream until EOF + while (file_read(fd, &ch, sizeof(ch)) == sizeof(ch)) { + if (libjvm_dtrace_debug) { + printf("%c", ch); + } + } + + file_close(fd); + clear_jvm_error(); + return count; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h 2024-01-27 14:37:30.303623011 +0100 @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2006, 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. + * + */ + +#ifndef _JVM_DTRACE_H_ +#define _JVM_DTRACE_H_ + +/* + * Interface to dynamically turn on probes in Hotspot JVM. Currently, + * this interface can be used to dynamically enable certain DTrace + * probe points that are costly to have "always on". + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include "jni.h" + +struct _jvm_t; +typedef struct _jvm_t jvm_t; + + +/* Attach to the given JVM process. Returns NULL on failure. + jvm_get_last_error() returns last error message. */ +JNIEXPORT jvm_t* jvm_attach(pid_t pid); + +/* Returns the last error message from this library or NULL if none. */ +JNIEXPORT const char* jvm_get_last_error(); + +/* few well-known probe type constants for 'probe_types' param below */ + +#define JVM_DTPROBE_METHOD_ENTRY "method-entry" +#define JVM_DTPROBE_METHOD_RETURN "method-return" +#define JVM_DTPROBE_MONITOR_ENTER "monitor-contended-enter" +#define JVM_DTPROBE_MONITOR_ENTERED "monitor-contended-entered" +#define JVM_DTPROBE_MONITOR_EXIT "monitor-contended-exit" +#define JVM_DTPROBE_MONITOR_WAIT "monitor-wait" +#define JVM_DTPROBE_MONITOR_WAITED "monitor-waited" +#define JVM_DTPROBE_MONITOR_NOTIFY "monitor-notify" +#define JVM_DTPROBE_MONITOR_NOTIFYALL "monitor-notifyall" +#define JVM_DTPROBE_OBJECT_ALLOC "object-alloc" +#define JVM_DTPROBE_ALL "*" + +/* Enable the specified DTrace probes of given probe types on + * the specified JVM. Returns >= 0 on success, -1 on failure. + * On success, this returns number of probe_types enabled. + * On failure, jvm_get_last_error() returns the last error message. + */ +JNIEXPORT int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types); + +/* Note: There is no jvm_disable_dtprobes function. Probes are automatically + * disabled when there are no more clients requiring those probes. + */ + +/* Detach the given JVM. Returns 0 on success, -1 on failure. + * jvm_get_last_error() returns the last error message. + */ +JNIEXPORT int jvm_detach(jvm_t* jvm); + +#ifdef __cplusplus +} +#endif + +#endif /* _JVM_DTRACE_H_ */ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnet/solaris_close.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnet/solaris_close.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnet/solaris_close.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnet/solaris_close.c 2024-01-27 14:37:30.303944537 +0100 @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 +#include +#include +#include +#include "jvm.h" +#include "net_util.h" + +/* Support for restartable system calls on Solaris. */ + +#define RESTARTABLE_RETURN_INT(_cmd) do { \ + int _result; \ + if (1) { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ + return _result; \ + } \ +} while(0) + +int NET_Read(int s, void* buf, size_t len) { + RESTARTABLE_RETURN_INT(recv(s, buf, len, 0)); +} + +int NET_NonBlockingRead(int s, void* buf, size_t len) { + RESTARTABLE_RETURN_INT(recv(s, buf, len, MSG_DONTWAIT)); +} + +int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, + struct sockaddr *from, socklen_t *fromlen) { + RESTARTABLE_RETURN_INT(recvfrom(s, buf, len, flags, from, fromlen)); +} + +int NET_Send(int s, void *msg, int len, unsigned int flags) { + RESTARTABLE_RETURN_INT(send(s, msg, len, flags)); +} + +int NET_SendTo(int s, const void *msg, int len, unsigned int flags, + const struct sockaddr *to, int tolen) { + RESTARTABLE_RETURN_INT(sendto(s, msg, len, flags, to, tolen)); +} + +int NET_Connect(int s, struct sockaddr *addr, int addrlen) { + RESTARTABLE_RETURN_INT(connect(s, addr, addrlen)); +} + +int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { + RESTARTABLE_RETURN_INT(accept(s, addr, addrlen)); +} + +int NET_SocketClose(int fd) { + return close(fd); +} + +int NET_Dup2(int fd, int fd2) { + return dup2(fd, fd2); +} + +int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { + RESTARTABLE_RETURN_INT(poll(ufds, nfds, timeout)); +} + +int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) { + int result; + jlong prevNanoTime = nanoTimeStamp; + jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC; + struct pollfd pfd; + pfd.fd = s; + pfd.events = POLLIN; + + for(;;) { + result = poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC); + if (result < 0 && errno == EINTR) { + jlong newNanoTime = JVM_NanoTime(env, 0); + nanoTimeout -= newNanoTime - prevNanoTime; + if (nanoTimeout < NET_NSEC_PER_MSEC) + return 0; + prevNanoTime = newNanoTime; + } else { + return result; + } + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c 2024-01-27 14:37:30.304307768 +0100 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2001, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 +#include +#include +#include +#include + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" + +#include "sun_nio_ch_DevPollArrayWrapper.h" + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_DevPollArrayWrapper_init(JNIEnv *env, jobject this) +{ + int wfd = open("/dev/poll", O_RDWR); + if (wfd < 0) { + JNU_ThrowIOExceptionWithLastError(env, "Error opening driver"); + return -1; + } + return wfd; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this, + jint wfd, jint fd, jint mask) +{ + struct pollfd a[1]; + int n; + + a[0].fd = fd; + a[0].events = mask; + a[0].revents = 0; + + n = write(wfd, &a[0], sizeof(a)); + if (n != sizeof(a)) { + if (n < 0) { + JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds"); + } else { + JNU_ThrowIOException(env, "Unexpected number of bytes written"); + } + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple(JNIEnv *env, jobject this, + jint wfd, jlong address, + jint len) +{ + unsigned char *pollBytes = (unsigned char *)jlong_to_ptr(address); + unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * len; + while (pollBytes < pollEnd) { + int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes)); + if (bytesWritten < 0) { + JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds"); + return; + } + pollBytes += bytesWritten; + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this, + jlong address, jint numfds, + jlong timeout, jint wfd) +{ + struct dvpoll a; + void *pfd = (void *) jlong_to_ptr(address); + int result; + + a.dp_fds = pfd; + a.dp_nfds = numfds; + a.dp_timeout = (int)timeout; + result = ioctl(wfd, DP_POLL, &a); + if (result < 0) { + if (errno == EINTR) { + return IOS_INTERRUPTED; + } else { + JNU_ThrowIOExceptionWithLastError(env, "Error reading driver"); + return IOS_THROWN; + } + } + return result; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c 2024-01-27 14:37:30.304588678 +0100 @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 +#include +#include +#include + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" + +#include "sun_nio_ch_SolarisEventPort.h" + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_SolarisEventPort_port_1create + (JNIEnv* env, jclass clazz) +{ + int port = port_create(); + if (port == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_create"); + } + return (jint)port; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_port_1close + (JNIEnv* env, jclass clazz, jint port) +{ + int res = close(port); + if (res < 0 && res != EINTR) { + JNU_ThrowIOExceptionWithLastError(env, "close failed"); + } +} + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_SolarisEventPort_port_1associate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + if (port_associate((int)port, (int)source, object, (int)events, NULL) == 0) { + return JNI_TRUE; + } else { + if (errno != EBADFD) + JNU_ThrowIOExceptionWithLastError(env, "port_associate"); + return JNI_FALSE; + } +} + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_SolarisEventPort_port_1dissociate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + + if (port_dissociate((int)port, (int)source, object) == 0) { + return JNI_TRUE; + } else { + if (errno != ENOENT) + JNU_ThrowIOExceptionWithLastError(env, "port_dissociate"); + return JNI_FALSE; + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_SolarisEventPort_port_1send(JNIEnv* env, jclass clazz, + jint port, jint events) +{ + if (port_send((int)port, (int)events, NULL) == -1) { + JNU_ThrowIOExceptionWithLastError(env, "port_send"); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_SolarisEventPort_port_1get(JNIEnv* env, jclass clazz, + jint port, jlong eventAddress) +{ + int res; + port_event_t* ev = (port_event_t*)jlong_to_ptr(eventAddress); + + res = port_get((int)port, ev, NULL); + if (res == -1) { + if (errno == EINTR) { + return IOS_INTERRUPTED; + } else { + JNU_ThrowIOExceptionWithLastError(env, "port_get failed"); + return IOS_THROWN; + } + } + return res; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_SolarisEventPort_port_1getn(JNIEnv* env, jclass clazz, + jint port, jlong arrayAddress, jint max, jlong timeout) +{ + int res; + uint_t n = 1; + port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress); + timespec_t ts; + timespec_t* tsp; + + if (timeout >= 0L) { + ts.tv_sec = timeout / 1000; + ts.tv_nsec = 1000000 * (timeout % 1000); + tsp = &ts; + } else { + tsp = NULL; + } + + res = port_getn((int)port, list, (uint_t)max, &n, tsp); + if (res == -1 && errno != ETIME) { + if (errno == EINTR) { + return IOS_INTERRUPTED; + } else { + JNU_ThrowIOExceptionWithLastError(env, "port_getn failed"); + return IOS_THROWN; + } + } + + return (jint)n; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c 2024-01-27 14:37:30.304948430 +0100 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include +#include +#include +#include +#include + +#include "jni.h" + +#include "sun_nio_fs_SolarisNativeDispatcher.h" + +static jfieldID entry_name; +static jfieldID entry_dir; +static jfieldID entry_fstype; +static jfieldID entry_options; +static jfieldID entry_dev; + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisNativeDispatcher_init(JNIEnv *env, jclass clazz) { + clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry"); + CHECK_NULL(clazz); + entry_name = (*env)->GetFieldID(env, clazz, "name", "[B"); + CHECK_NULL(entry_name); + entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B"); + CHECK_NULL(entry_dir); + entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B"); + CHECK_NULL(entry_fstype); + entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B"); + CHECK_NULL(entry_options); + entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J"); + CHECK_NULL(entry_dev); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_SolarisNativeDispatcher_facl(JNIEnv* env, jclass this, jint fd, + jint cmd, jint nentries, jlong address) +{ + void* aclbufp = jlong_to_ptr(address); + int n = -1; + + n = facl((int)fd, (int)cmd, (int)nentries, aclbufp); + if (n == -1) { + throwUnixException(env, errno); + } + return (jint)n; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_SolarisNativeDispatcher_getextmntent(JNIEnv* env, jclass this, + jlong value, jobject entry) +{ + struct extmnttab ent; + FILE* fp = jlong_to_ptr(value); + jsize len; + jbyteArray bytes; + char* name; + char* dir; + char* fstype; + char* options; + dev_t dev; + + if (getextmntent(fp, &ent, 0)) + return -1; + name = ent.mnt_special; + dir = ent.mnt_mountp; + fstype = ent.mnt_fstype; + options = ent.mnt_mntopts; + dev = makedev(ent.mnt_major, ent.mnt_minor); + if (dev == NODEV) { + throwUnixException(env, errno); + return -1; + } + + len = strlen(name); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name); + (*env)->SetObjectField(env, entry, entry_name, bytes); + + len = strlen(dir); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir); + (*env)->SetObjectField(env, entry, entry_dir, bytes); + + len = strlen(fstype); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype); + (*env)->SetObjectField(env, entry, entry_fstype, bytes); + + len = strlen(options); + bytes = (*env)->NewByteArray(env, len); + if (bytes == NULL) + return -1; + (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options); + (*env)->SetObjectField(env, entry, entry_options, bytes); + + if (dev != 0) + (*env)->SetLongField(env, entry, entry_dev, (jlong)dev); + + return 0; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c 2024-01-27 14:37:30.305216729 +0100 @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2008, 2009, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" + +#include +#include +#include +#include // Solaris 10 + +#include "sun_nio_fs_SolarisWatchService.h" + +static void throwUnixException(JNIEnv* env, int errnum) { + jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException", + "(I)V", errnum); + if (x != NULL) { + (*env)->Throw(env, x); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_init(JNIEnv *env, jclass clazz) +{ +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_SolarisWatchService_portCreate + (JNIEnv* env, jclass clazz) +{ + int port = port_create(); + if (port == -1) { + throwUnixException(env, errno); + } + return (jint)port; +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_portAssociate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + + if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_portDissociate + (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress) +{ + uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress); + + if (port_dissociate((int)port, (int)source, object) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_fs_SolarisWatchService_portSend(JNIEnv* env, jclass clazz, + jint port, jint events) +{ + if (port_send((int)port, (int)events, NULL) == -1) { + throwUnixException(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_fs_SolarisWatchService_portGetn(JNIEnv* env, jclass clazz, + jint port, jlong arrayAddress, jint max) +{ + uint_t n = 1; + port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress); + + if (port_getn((int)port, list, (uint_t)max, &n, NULL) == -1) { + throwUnixException(env, errno); + } + return (jint)n; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/java/lang/ProcessImpl.java jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/java/lang/ProcessImpl.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/java/lang/ProcessImpl.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/java/lang/ProcessImpl.java 2024-01-27 14:37:30.253043033 +0100 @@ -83,6 +83,9 @@ private /* final */ InputStream stdout; private /* final */ InputStream stderr; + // only used on Solaris + private /* final */ DeferredCloseInputStream stdout_inner_stream; + private static enum LaunchMechanism { // order IS important! FORK, @@ -108,6 +111,7 @@ return lm; // All options are valid for Linux case AIX: case MACOS: + case SOLARIS: if (lm != LaunchMechanism.VFORK) { return lm; // All but VFORK are valid } @@ -364,6 +368,41 @@ }); break; + case SOLARIS: + stdin = (fds[0] == -1) ? + ProcessBuilder.NullOutputStream.INSTANCE : + new BufferedOutputStream( + new FileOutputStream(newFileDescriptor(fds[0]))); + + stdout = (fds[1] == -1 || forceNullOutputStream) ? + ProcessBuilder.NullInputStream.INSTANCE : + new BufferedInputStream( + stdout_inner_stream = + new DeferredCloseInputStream( + newFileDescriptor(fds[1]))); + + stderr = (fds[2] == -1) ? + ProcessBuilder.NullInputStream.INSTANCE : + new DeferredCloseInputStream(newFileDescriptor(fds[2])); + + /* + * For each subprocess forked a corresponding reaper task + * is submitted. That task is the only thread which waits + * for the subprocess to terminate and it doesn't hold any + * locks while doing so. This design allows waitFor() and + * exitStatus() to be safely executed in parallel (and they + * need no native code). + */ + ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> { + synchronized (this) { + this.exitcode = (exitcode == null) ? -1 : exitcode.intValue(); + this.hasExited = true; + this.notifyAll(); + } + return null; + }); + break; + case AIX: stdin = (fds[0] == -1) ? ProcessBuilder.NullOutputStream.INSTANCE : @@ -480,6 +519,29 @@ try { stderr.close(); } catch (IOException ignored) {} break; + case SOLARIS: + // There is a risk that pid will be recycled, causing us to + // kill the wrong process! So we only terminate processes + // that appear to still be running. Even with this check, + // there is an unavoidable race condition here, but the window + // is very small, and OSes try hard to not recycle pids too + // soon, so this is quite safe. + synchronized (this) { + if (!hasExited) + processHandle.destroyProcess(force); + try { + stdin.close(); + if (stdout_inner_stream != null) + stdout_inner_stream.closeDeferred(stdout); + if (stderr instanceof DeferredCloseInputStream) + ((DeferredCloseInputStream) stderr) + .closeDeferred(stderr); + } catch (IOException e) { + // ignore + } + } + break; + default: throw new AssertionError("Unsupported platform: " + OperatingSystem.current()); } } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/net/PortConfig.java jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/net/PortConfig.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/net/PortConfig.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/net/PortConfig.java 2024-01-27 14:37:30.253377354 +0100 @@ -47,6 +47,10 @@ defaultLower = 32768; defaultUpper = 61000; break; + case SOLARIS: + defaultLower = 32768; + defaultUpper = 65535; + break; case MACOS: defaultLower = 49152; defaultUpper = 65535; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template 2024-01-27 14:37:30.253736087 +0100 @@ -35,6 +35,10 @@ #include #endif +/* On Solaris, "sun" is defined as a macro. Undefine to make package + declaration valid */ +#undef sun + /* To be able to name the Java constants the same as the C constants without having the preprocessor rewrite those identifiers, add PREFIX_ to all identifiers matching a C constant. The PREFIX_ is filtered out in the diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java 2024-01-27 14:37:30.254220531 +0100 @@ -127,6 +127,10 @@ return rootDirectory; } + boolean isSolaris() { + return false; + } + static List standardFileAttributeViews() { return Arrays.asList("basic", "posix", "unix", "owner"); } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixPath.java jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/nio/fs/UnixPath.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixPath.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/nio/fs/UnixPath.java 2024-01-27 14:37:30.254656609 +0100 @@ -779,7 +779,15 @@ ("NOFOLLOW_LINKS is not supported on this platform"); flags |= O_NOFOLLOW; } - return open(this, flags, 0); + try { + return open(this, flags, 0); + } catch (UnixException x) { + // HACK: EINVAL instead of ELOOP on Solaris 10 prior to u4 (see 6460380) + if (getFileSystem().isSolaris() && x.errno() == EINVAL) + x.setError(ELOOP); + + throw x; + } } void checkRead() { diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/security/provider/NativePRNG.java jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/security/provider/NativePRNG.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/classes/sun/security/provider/NativePRNG.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/classes/sun/security/provider/NativePRNG.java 2024-01-27 14:37:30.255118398 +0100 @@ -33,7 +33,7 @@ import sun.security.util.Debug; /** - * Native PRNG implementation for Linux/MacOS. + * Native PRNG implementation for Solaris/Linux/MacOS. *

* It obtains seed and random numbers by reading system files such as * the special device files /dev/random and /dev/urandom. This diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/io_util_md.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/io_util_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/io_util_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/io_util_md.c 2024-01-27 14:37:30.258040069 +0100 @@ -30,6 +30,10 @@ #include #include +#ifdef __solaris__ +#include +#endif + #if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX) #include #endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/java_props_md.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/java_props_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/java_props_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/java_props_md.c 2024-01-27 14:37:30.258500184 +0100 @@ -323,6 +323,27 @@ } #endif +#ifdef __solaris__ + if (strcmp(p,"eucJP") == 0) { + /* For Solaris use customized vendor defined character + * customized EUC-JP converter + */ + *std_encoding = "eucJP-open"; + } else if (strcmp(p, "Big5") == 0 || strcmp(p, "BIG5") == 0) { + /* + * Remap the encoding string to Big5_Solaris which augments + * the default converter for Solaris Big5 locales to include + * seven additional ideographic characters beyond those included + * in the Java "Big5" converter. + */ + *std_encoding = "Big5_Solaris"; + } else if (strcmp(p, "Big5-HKSCS") == 0) { + /* + * Solaris uses HKSCS2001 + */ + *std_encoding = "Big5-HKSCS-2001"; + } +#endif #ifdef MACOSX /* * For the case on MacOS X where encoding is set to US-ASCII, but we diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/jlong_md.h jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/jlong_md.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/jlong_md.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/jlong_md.h 2024-01-27 14:37:30.258843076 +0100 @@ -23,8 +23,8 @@ * questions. */ -#ifndef _UNIX_JLONG_MD_H_ -#define _UNIX_JLONG_MD_H_ +#ifndef _SOLARIS_JLONG_MD_H_ +#define _SOLARIS_JLONG_MD_H_ /* Make sure ptrdiff_t is defined */ #include @@ -97,4 +97,4 @@ #define size_to_jlong(a) ((jlong)(a)) #define long_to_jlong(a) ((jlong)(a)) -#endif /* !_UNIX_JLONG_MD_H_ */ +#endif /* !_SOLARIS_JLONG_MD_H_ */ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c 2024-01-27 14:37:30.255775692 +0100 @@ -45,10 +45,20 @@ #include #include +/* For POSIX-compliant getpwuid_r on Solaris */ +#if defined(__solaris__) +#define _POSIX_PTHREAD_SEMANTICS +#endif #include +#ifdef _AIX +#include +#endif +#ifdef __solaris__ +#include +#endif + #if defined(_AIX) - #include #define DIR DIR64 #define dirent dirent64 #define opendir opendir64 @@ -128,13 +138,18 @@ #define WTERMSIG(status) ((status)&0x7F) #endif +#ifdef __solaris__ /* The child exited because of a signal. * The best value to return is 0x80 + signal number, * because that is what all Unix shells do, and because * it allows callers to distinguish between process exit and * process death by signal. - */ + * Unfortunately, the historical behavior on Solaris is to return + * the signal number, and we preserve this for compatibility. */ +#define WTERMSIG_RETURN(status) WTERMSIG(status) +#else #define WTERMSIG_RETURN(status) (WTERMSIG(status) + 0x80) +#endif #define RESTARTABLE(_cmd, _result) do { \ do { \ @@ -488,7 +503,7 @@ * The following functions are for Linux */ -#if defined (__linux__) +#if defined(__solaris__) || defined (__linux__) /* * Return pids of active processes, and optionally parent pids and @@ -617,13 +632,13 @@ return count; } -#endif // defined (__linux__) +#endif // defined(__solaris__) || defined (__linux__) /* - * The following functions are for AIX. + * The following functions are common on Solaris and AIX. */ -#if defined(_AIX) +#if defined(__solaris__) || defined(_AIX) /** * Helper function to get the 'psinfo_t' data from "/proc/%d/psinfo". @@ -687,6 +702,19 @@ int ret; /* + * On Solaris, the full path to the executable command is the link in + * /proc//paths/a.out. But it is only readable for processes we own. + */ +#if defined(__solaris__) + snprintf(fn, sizeof fn, "/proc/%d/path/a.out", pid); + if ((ret = readlink(fn, exePath, PATH_MAX - 1)) > 0) { + // null terminate and create String to store for command + exePath[ret] = '\0'; + CHECK_NULL(cmdexe = JNU_NewStringPlatform(env, exePath)); + } +#endif + + /* * Now try to open /proc/%d/psinfo */ if (getPsinfo(pid, &psinfo) < 0) { @@ -715,4 +743,4 @@ prargs[0] == '\0' ? NULL : prargs); } -#endif // defined(_AIX) +#endif // defined(__solaris__) || defined(_AIX) diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h 2024-01-27 14:37:30.256084125 +0100 @@ -29,7 +29,7 @@ * Declaration of ProcessHandleImpl functions common on all Unix platforms. * 'unix_' functions have a single implementation in ProcessHandleImpl_unix.c * 'os_' prefixed functions have different, os-specific implementations in the - * various ProcessHandleImpl_{linux,macosx,aix}.c files. + * various ProcessHandleImpl_{linux,macosx,solaris,aix}.c files. * See ProcessHandleImpl_unix.c for more details. */ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/ProcessImpl_md.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/ProcessImpl_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/ProcessImpl_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/ProcessImpl_md.c 2024-01-27 14:37:30.256599288 +0100 @@ -230,7 +230,14 @@ static const char* defaultPath(void) { - return ":/bin:/usr/bin"; +#ifdef __solaris__ + /* These really are the Solaris defaults! */ + return (geteuid() == 0 || getuid() == 0) ? + "/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" : + "/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:"; +#else + return ":/bin:/usr/bin"; /* glibc */ +#endif } static const char* @@ -443,7 +450,7 @@ #endif /* vfork(2) is deprecated on Darwin */ -#ifndef __APPLE__ +#ifndef __solaris__ static pid_t vforkChild(ChildStuff *c) { volatile pid_t resultPid; @@ -596,7 +603,7 @@ startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) { switch (c->mode) { /* vfork(2) is deprecated on Darwin*/ - #ifndef __APPLE__ + #ifndef __solaris__ case MODE_VFORK: return vforkChild(c); #endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/TimeZone_md.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/TimeZone_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/TimeZone_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/TimeZone_md.c 2024-01-27 14:37:30.257292853 +0100 @@ -35,6 +35,9 @@ #include #include #include +#if defined(__solaris__) +#include +#endif #include "jvm.h" #include "TimeZone_md.h" @@ -50,9 +53,11 @@ } while((_result == -1) && (errno == EINTR)); \ } while(0) +#if !defined(__solaris__) || defined(__sparcv9) || defined(amd64) #define fileopen fopen #define filegets fgets #define fileclose fclose +#endif #if defined(_ALLBSD_SOURCE) #define stat64 stat @@ -76,7 +81,7 @@ static const char *ETC_ENVIRONMENT_FILE = "/etc/environment"; #endif -#if defined(__linux__) || defined(MACOSX) +#if defined(__linux__) || defined(MACOSX) || defined(__solaris__) /* * remove repeated path separators ('/') in the given 'path'. @@ -186,6 +191,13 @@ */ if ((strcmp(dp->d_name, "ROC") == 0) || (strcmp(dp->d_name, "posixrules") == 0) +#if defined(__solaris__) + /* + * Skip the "src" and "tab" directories on Solaris. + */ + || (strcmp(dp->d_name, "src") == 0) + || (strcmp(dp->d_name, "tab") == 0) +#endif || (strcmp(dp->d_name, "localtime") == 0)) { continue; } @@ -257,6 +269,8 @@ return possibleMatch; } +#if defined(__linux__) || defined(MACOSX) + /* * Performs Linux specific mapping and returns a zone ID * if found. Otherwise, NULL is returned. @@ -368,6 +382,183 @@ return tz; } +#elif defined(__solaris__) + +/* + * Performs Solaris dependent mapping. Returns a zone ID if + * found. Otherwise, NULL is returned. Solaris libc looks up + * "/etc/default/init" to get the default TZ value if TZ is not defined + * as an environment variable. + */ +static char * +getPlatformTimeZoneID() +{ + char *tz = NULL; + FILE *fp; + + /* + * Try the TZ entry in /etc/default/init. + */ + if ((fp = fileopen(SYS_INIT_FILE, "r")) != NULL) { + char line[256]; + char quote = '\0'; + + while (filegets(line, sizeof(line), fp) != NULL) { + char *p = line; + char *s; + char c; + + /* quick check for comment lines */ + if (*p == '#') { + continue; + } + if (strncmp(p, "TZ=", 3) == 0) { + p += 3; + SKIP_SPACE(p); + c = *p; + if (c == '"' || c == '\'') { + quote = c; + p++; + } + + /* + * PSARC/2001/383: quoted string support + */ + for (s = p; (c = *s) != '\0' && c != '\n'; s++) { + /* No '\\' is supported here. */ + if (c == quote) { + quote = '\0'; + break; + } + if (c == ' ' && quote == '\0') { + break; + } + } + if (quote != '\0') { + jio_fprintf(stderr, "ZoneInfo: unterminated time zone name in /etc/TIMEZONE\n"); + } + *s = '\0'; + tz = strdup(p); + break; + } + } + (void) fileclose(fp); + } + return tz; +} + +#define TIMEZONE_FMRI "svc:/system/timezone:default" +#define TIMEZONE_PG "timezone" +#define LOCALTIME_PROP "localtime" + +static void +cleanupScf(scf_handle_t *h, + scf_snapshot_t *snap, + scf_instance_t *inst, + scf_propertygroup_t *pg, + scf_property_t *prop, + scf_value_t *val, + char *buf) { + if (buf != NULL) { + free(buf); + } + if (snap != NULL) { + scf_snapshot_destroy(snap); + } + if (val != NULL) { + scf_value_destroy(val); + } + if (prop != NULL) { + scf_property_destroy(prop); + } + if (pg != NULL) { + scf_pg_destroy(pg); + } + if (inst != NULL) { + scf_instance_destroy(inst); + } + if (h != NULL) { + scf_handle_destroy(h); + } +} + +/* + * Returns a zone ID of Solaris when the TZ value is "localtime". + * First, it tries scf. If scf fails, it looks for the same file as + * /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/. + */ +static char * +getSolarisDefaultZoneID() { + char *tz = NULL; + struct stat64 statbuf; + size_t size; + char *buf; + int fd; + int res; + /* scf specific variables */ + scf_handle_t *h = NULL; + scf_snapshot_t *snap = NULL; + scf_instance_t *inst = NULL; + scf_propertygroup_t *pg = NULL; + scf_property_t *prop = NULL; + scf_value_t *val = NULL; + + if ((h = scf_handle_create(SCF_VERSION)) != NULL + && scf_handle_bind(h) == 0 + && (inst = scf_instance_create(h)) != NULL + && (snap = scf_snapshot_create(h)) != NULL + && (pg = scf_pg_create(h)) != NULL + && (prop = scf_property_create(h)) != NULL + && (val = scf_value_create(h)) != NULL + && scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst, + NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0 + && scf_instance_get_snapshot(inst, "running", snap) == 0 + && scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0 + && scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0 + && scf_property_get_value(prop, val) == 0) { + ssize_t len; + + /* Gets the length of the zone ID string */ + len = scf_value_get_astring(val, NULL, 0); + if (len != -1) { + tz = malloc(++len); /* +1 for a null byte */ + if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) { + cleanupScf(h, snap, inst, pg, prop, val, NULL); + return tz; + } + } + } + cleanupScf(h, snap, inst, pg, prop, val, tz); + + RESTARTABLE(stat64(DEFAULT_ZONEINFO_FILE, &statbuf), res); + if (res == -1) { + return NULL; + } + size = (size_t) statbuf.st_size; + buf = malloc(size); + if (buf == NULL) { + return NULL; + } + RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd); + if (fd == -1) { + free((void *) buf); + return NULL; + } + + RESTARTABLE(read(fd, buf, size), res); + if (res != (ssize_t) size) { + (void) close(fd); + free((void *) buf); + return NULL; + } + (void) close(fd); + tz = findZoneinfoFile(buf, size, ZONEINFO_DIR); + free((void *) buf); + return tz; +} + +#endif /* defined(__solaris__) */ + #elif defined(_AIX) static char * @@ -533,6 +724,15 @@ free((void *) freetz); } #else +#if defined(__solaris__) + /* Solaris might use localtime, so handle it here. */ + if (strcmp(tz, "localtime") == 0) { + javatz = getSolarisDefaultZoneID(); + if (freetz != NULL) { + free((void *) freetz); + } + } else +#endif if (freetz == NULL) { /* strdup if we are still working on getenv result. */ javatz = strdup(tz); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/UnixFileSystem_md.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/UnixFileSystem_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjava/UnixFileSystem_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjava/UnixFileSystem_md.c 2024-01-27 14:37:30.257692274 +0100 @@ -63,6 +63,10 @@ #define stat stat64 #endif +#if defined(__solaris__) && !defined(NAME_MAX) + #define NAME_MAX MAXNAMLEN +#endif + #if defined(_ALLBSD_SOURCE) #ifndef MACOSX #define statvfs64 statvfs diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjsig/jsig.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjsig/jsig.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libjsig/jsig.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libjsig/jsig.c 2024-01-27 14:37:30.259491369 +0100 @@ -35,6 +35,16 @@ #include "jni.h" +#ifdef SOLARIS +/* Our redeclarations of the system functions must not have a less + * restrictive linker scoping, so we have to declare them as JNIEXPORT + * before including signal.h */ +#include "sys/signal.h" +JNIEXPORT void (*signal(int sig, void (*disp)(int)))(int); +JNIEXPORT void (*sigset(int sig, void (*disp)(int)))(int); +JNIEXPORT int sigaction(int sig, const struct sigaction *act, struct sigaction *oact); +#endif + #include #include #include @@ -51,9 +61,16 @@ #define false 0 #endif +#ifdef SOLARIS +#define MAX_SIGNALS (SIGRTMAX+1) + +/* On solaris, MAX_SIGNALS is a macro, not a constant, so we must allocate sact dynamically. */ +static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */ +#else #define MAX_SIGNALS NSIG static struct sigaction sact[MAX_SIGNALS]; /* saved signal handlers */ +#endif static sigset_t jvmsigs; /* Signals used by jvm. */ @@ -78,6 +95,20 @@ static bool jvm_signal_installed = false; +/* assume called within signal_lock */ +static void allocate_sact() { +#ifdef SOLARIS + if (sact == NULL) { + sact = (struct sigaction *)malloc((MAX_SIGNALS) * (size_t)sizeof(struct sigaction)); + if (sact == NULL) { + printf("%s\n", "libjsig.so unable to allocate memory"); + exit(0); + } + memset(sact, 0, (MAX_SIGNALS) * (size_t)sizeof(struct sigaction)); + } +#endif +} + static void signal_lock() { pthread_mutex_lock(&mutex); /* When the jvm is installing its set of signal handlers, threads @@ -137,7 +168,18 @@ sact[sig].sa_handler = disp; sigemptyset(&set); sact[sig].sa_mask = set; - sact[sig].sa_flags = 0; + if (!is_sigset) { +#ifdef SOLARIS + sact[sig].sa_flags = SA_NODEFER; + if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) { + sact[sig].sa_flags |= SA_RESETHAND; + } +#else + sact[sig].sa_flags = 0; +#endif + } else { + sact[sig].sa_flags = 0; + } } static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) { @@ -146,6 +188,7 @@ bool sigblocked; signal_lock(); + allocate_sact(); sigused = sigismember(&jvmsigs, sig); if (jvm_signal_installed && sigused) { @@ -157,6 +200,13 @@ oldhandler = sact[sig].sa_handler; save_signal_handler(sig, disp, is_sigset); +#ifdef SOLARIS + if (is_sigset && sigblocked) { + /* We won't honor the SIG_HOLD request to change the signal mask */ + oldhandler = SIG_HOLD; + } +#endif + signal_unlock(); return oldhandler; } else if (jvm_signal_installing) { @@ -234,6 +284,7 @@ signal_lock(); + allocate_sact(); sigused = sigismember(&jvmsigs, sig); if (jvm_signal_installed && sigused) { /* jvm has installed its signal handler for this signal. */ @@ -300,6 +351,7 @@ } JNIEXPORT struct sigaction *JVM_get_signal_action(int sig) { + allocate_sact(); /* Does race condition make sense here? */ if (sigismember(&jvmsigs, sig)) { return &sact[sig]; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/Inet4AddressImpl.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/Inet4AddressImpl.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/Inet4AddressImpl.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/Inet4AddressImpl.c 2024-01-27 14:37:30.259894450 +0100 @@ -66,8 +66,27 @@ if (gethostname(hostname, sizeof(hostname)) != 0) { strcpy(hostname, "localhost"); } else { +#if defined(__solaris__) + // try to resolve hostname via nameservice + // if it is known but getnameinfo fails, hostname will still be the + // value from gethostname + struct addrinfo hints, *res; + // make sure string is null-terminated hostname[NI_MAXHOST] = '\0'; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_INET; + + if (getaddrinfo(hostname, NULL, &hints, &res) == 0) { + getnameinfo(res->ai_addr, res->ai_addrlen, hostname, sizeof(hostname), + NULL, 0, NI_NAMEREQD); + freeaddrinfo(res); + } +#else + // make sure string is null-terminated + hostname[NI_MAXHOST] = '\0'; +#endif } return (*env)->NewStringUTF(env, hostname); } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/Inet6AddressImpl.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/Inet6AddressImpl.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/Inet6AddressImpl.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/Inet6AddressImpl.c 2024-01-27 14:37:30.260314595 +0100 @@ -67,8 +67,27 @@ if (gethostname(hostname, sizeof(hostname)) != 0) { strcpy(hostname, "localhost"); } else { +#if defined(__solaris__) + // try to resolve hostname via nameservice + // if it is known but getnameinfo fails, hostname will still be the + // value from gethostname + struct addrinfo hints, *res; + // make sure string is null-terminated hostname[NI_MAXHOST] = '\0'; + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = AF_UNSPEC; + + if (getaddrinfo(hostname, NULL, &hints, &res) == 0) { + getnameinfo(res->ai_addr, res->ai_addrlen, hostname, sizeof(hostname), + NULL, 0, NI_NAMEREQD); + freeaddrinfo(res); + } +#else + // make sure string is null-terminated + hostname[NI_MAXHOST] = '\0'; +#endif } return (*env)->NewStringUTF(env, hostname); } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/net_util_md.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/net_util_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/net_util_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/net_util_md.c 2024-01-27 14:37:30.262387096 +0100 @@ -37,6 +37,14 @@ #include #endif +#if defined(__solaris__) +#include +#include +#include +#include +#include +#endif + #if defined(MACOSX) #include #endif @@ -51,6 +59,20 @@ #define IPV6_FLOWINFO_SEND 33 #endif +#if defined(__solaris__) && !defined(MAXINT) +#define MAXINT INT_MAX +#endif + +/* + * EXCLBIND socket options only on Solaris + */ +#if defined(__solaris__) && !defined(TCP_EXCLBIND) +#define TCP_EXCLBIND 0x21 +#endif +#if defined(__solaris__) && !defined(UDP_EXCLBIND) +#define UDP_EXCLBIND 0x0101 +#endif + #define RESTARTABLE(_cmd, _result) do { \ do { \ _result = _cmd; \ @@ -63,6 +85,94 @@ return result; } +#ifdef __solaris__ +static int init_tcp_max_buf, init_udp_max_buf; +static int tcp_max_buf; +static int udp_max_buf; +static int useExclBind = 0; + +/* + * Get the specified parameter from the specified driver. The value + * of the parameter is assumed to be an 'int'. If the parameter + * cannot be obtained return -1 + */ +int net_getParam(char *driver, char *param) +{ + struct strioctl stri; + char buf [64]; + int s; + int value; + + s = open (driver, O_RDWR); + if (s < 0) { + return -1; + } + strncpy (buf, param, sizeof(buf)); + stri.ic_cmd = ND_GET; + stri.ic_timout = 0; + stri.ic_dp = buf; + stri.ic_len = sizeof(buf); + if (ioctl (s, I_STR, &stri) < 0) { + value = -1; + } else { + value = atoi(buf); + } + close (s); + return value; +} + +/* + * Iterative way to find the max value that SO_SNDBUF or SO_RCVBUF + * for Solaris versions that do not support the ioctl() in net_getParam(). + * Ugly, but only called once (for each sotype). + * + * As an optimization, we make a guess using the default values for Solaris + * assuming they haven't been modified with ndd. + */ + +#define MAX_TCP_GUESS 1024 * 1024 +#define MAX_UDP_GUESS 2 * 1024 * 1024 + +#define FAIL_IF_NOT_ENOBUFS if (errno != ENOBUFS) return -1 + +static int findMaxBuf(int fd, int opt, int sotype) { + int a = 0; + int b = MAXINT; + int initial_guess; + int limit = -1; + + if (sotype == SOCK_DGRAM) { + initial_guess = MAX_UDP_GUESS; + } else { + initial_guess = MAX_TCP_GUESS; + } + + if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess, sizeof(int)) == 0) { + initial_guess++; + if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess,sizeof(int)) < 0) { + FAIL_IF_NOT_ENOBUFS; + return initial_guess - 1; + } + a = initial_guess; + } else { + FAIL_IF_NOT_ENOBUFS; + b = initial_guess - 1; + } + do { + int mid = a + (b-a)/2; + if (setsockopt(fd, SOL_SOCKET, opt, &mid, sizeof(int)) == 0) { + limit = mid; + a = mid + 1; + } else { + FAIL_IF_NOT_ENOBUFS; + b = mid - 1; + } + } while (b >= a); + + return limit; +} +#endif + void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, const char *defaultDetail) { @@ -146,6 +256,50 @@ } #endif + /** + * On Solaris 8 it's possible to create INET6 sockets even + * though IPv6 is not enabled on all interfaces. Thus we + * query the number of IPv6 addresses to verify that IPv6 + * has been configured on at least one interface. + * + * On Linux it doesn't matter - if IPv6 is built-in the + * kernel then IPv6 addresses will be bound automatically + * to all interfaces. + */ +#ifdef __solaris__ + +#ifdef SIOCGLIFNUM + { + struct lifnum numifs; + + numifs.lifn_family = AF_INET6; + numifs.lifn_flags = 0; + if (ioctl(fd, SIOCGLIFNUM, (char *)&numifs) < 0) { + /** + * SIOCGLIFNUM failed - assume IPv6 not configured + */ + close(fd); + return JNI_FALSE; + } + /** + * If no IPv6 addresses then return false. If count > 0 + * it's possible that all IPv6 addresses are "down" but + * that's okay as they may be brought "up" while the + * VM is running. + */ + if (numifs.lifn_count == 0) { + close(fd); + return JNI_FALSE; + } + } +#else + /* SIOCGLIFNUM not defined in build environment ??? */ + close(fd); + return JNI_FALSE; +#endif + +#endif /* __solaris */ + /* * OK we may have the stack available in the kernel, * we should also check if the APIs are available. @@ -210,6 +364,26 @@ } } +void parseExclusiveBindProperty(JNIEnv *env) { +#ifdef __solaris__ + jstring s, flagSet; + jclass iCls; + jmethodID mid; + + s = (*env)->NewStringUTF(env, "sun.net.useExclusiveBind"); + CHECK_NULL(s); + iCls = (*env)->FindClass(env, "java/lang/System"); + CHECK_NULL(iCls); + mid = (*env)->GetStaticMethodID(env, iCls, "getProperty", + "(Ljava/lang/String;)Ljava/lang/String;"); + CHECK_NULL(mid); + flagSet = (*env)->CallStaticObjectMethod(env, iCls, mid, s); + if (flagSet != NULL) { + useExclBind = 1; + } +#endif +} + JNIEXPORT jint JNICALL NET_EnableFastTcpLoopback(int fd) { return 0; @@ -368,7 +542,7 @@ *level = IPPROTO_IPV6; *optname = IPV6_MULTICAST_LOOP; return 0; -#if defined(MACOSX) +#if (defined(__solaris__) || defined(MACOSX)) // Map IP_TOS request to IPV6_TCLASS case java_net_SocketOptions_IP_TOS: *level = IPPROTO_IPV6; @@ -517,6 +691,65 @@ *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK); } + /* + * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp + * the value when it exceeds the system limit. + */ +#ifdef __solaris__ + if (level == SOL_SOCKET) { + if (opt == SO_SNDBUF || opt == SO_RCVBUF) { + int sotype=0; + socklen_t arglen; + int *bufsize, maxbuf; + int ret; + + /* Attempt with the original size */ + ret = setsockopt(fd, level, opt, arg, len); + if ((ret == 0) || (ret == -1 && errno != ENOBUFS)) + return ret; + + /* Exceeded system limit so clamp and retry */ + + arglen = sizeof(sotype); + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype, + &arglen) < 0) { + return -1; + } + + /* + * We try to get tcp_maxbuf (and udp_max_buf) using + * an ioctl() that isn't available on all versions of Solaris. + * If that fails, we use the search algorithm in findMaxBuf() + */ + if (!init_tcp_max_buf && sotype == SOCK_STREAM) { + tcp_max_buf = net_getParam("/dev/tcp", "tcp_max_buf"); + if (tcp_max_buf == -1) { + tcp_max_buf = findMaxBuf(fd, opt, SOCK_STREAM); + if (tcp_max_buf == -1) { + return -1; + } + } + init_tcp_max_buf = 1; + } else if (!init_udp_max_buf && sotype == SOCK_DGRAM) { + udp_max_buf = net_getParam("/dev/udp", "udp_max_buf"); + if (udp_max_buf == -1) { + udp_max_buf = findMaxBuf(fd, opt, SOCK_DGRAM); + if (udp_max_buf == -1) { + return -1; + } + } + init_udp_max_buf = 1; + } + + maxbuf = (sotype == SOCK_STREAM) ? tcp_max_buf : udp_max_buf; + bufsize = (int *)arg; + if (*bufsize > maxbuf) { + *bufsize = maxbuf; + } + } + } +#endif + #ifdef _AIX if (level == SOL_SOCKET) { if (opt == SO_SNDBUF || opt == SO_RCVBUF) { @@ -629,10 +862,20 @@ * * Linux allows a socket to bind to 127.0.0.255 which must be * caught. + * + * On Solaris with IPv6 enabled we must use an exclusive + * bind to guarantee a unique port number across the IPv4 and + * IPv6 port spaces. + * */ int NET_Bind(int fd, SOCKETADDRESS *sa, int len) { +#if defined(__solaris__) + int level = -1; + int exclbind = -1; + int arg, alen; +#endif int rv; #ifdef __linux__ @@ -649,8 +892,61 @@ } #endif +#if defined(__solaris__) + /* + * Solaris has separate IPv4 and IPv6 port spaces so we + * use an exclusive bind when SO_REUSEADDR is not used to + * give the illusion of a unified port space. + * This also avoids problems with IPv6 sockets connecting + * to IPv4 mapped addresses whereby the socket conversion + * results in a late bind that fails because the + * corresponding IPv4 port is in use. + */ + alen = sizeof(arg); + + if (useExclBind || + getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg, &alen) == 0) + { + if (useExclBind || arg == 0) { + /* + * SO_REUSEADDR is disabled or sun.net.useExclusiveBind + * property is true so enable TCP_EXCLBIND or + * UDP_EXCLBIND + */ + alen = sizeof(arg); + if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg, &alen) == 0) + { + if (arg == SOCK_STREAM) { + level = IPPROTO_TCP; + exclbind = TCP_EXCLBIND; + } else { + level = IPPROTO_UDP; + exclbind = UDP_EXCLBIND; + } + } + + arg = 1; + setsockopt(fd, level, exclbind, (char *)&arg, sizeof(arg)); + } + } + +#endif + rv = bind(fd, &sa->sa, len); +#if defined(__solaris__) + if (rv < 0) { + int en = errno; + /* Restore *_EXCLBIND if the bind fails */ + if (exclbind != -1) { + int arg = 0; + setsockopt(fd, level, exclbind, (char *)&arg, + sizeof(arg)); + } + errno = en; + } +#endif + return rv; } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/net_util_md.h jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/net_util_md.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/net_util_md.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/net_util_md.h 2024-01-27 14:37:30.262728792 +0100 @@ -47,6 +47,8 @@ #ifndef SO_REUSEPORT #ifdef __linux__ #define SO_REUSEPORT 15 +#elif defined(__solaris__) +#define SO_REUSEPORT 0x100e #elif defined(AIX) || defined(MACOSX) #define SO_REUSEPORT 0x0200 #else @@ -80,4 +82,8 @@ void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, const char *defaultDetail); +#ifdef __solaris__ +int net_getParam(char *driver, char *param); +#endif + #endif /* NET_UTILS_MD_H */ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/NetworkInterface.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/NetworkInterface.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/NetworkInterface.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/NetworkInterface.c 2024-01-27 14:37:30.261178404 +0100 @@ -37,6 +37,12 @@ #include #endif +#if defined(__solaris__) +#include +#include +#include +#endif + #if defined(_ALLBSD_SOURCE) #include #include @@ -49,6 +55,11 @@ #if defined(__linux__) #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" +#elif defined(__solaris__) + #ifndef SIOCGLIFHWADDR + #define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq) + #endif + #define DEV_PREFIX "/dev/" #endif #ifdef LIFNAMSIZ @@ -135,6 +146,11 @@ const struct in_addr *addr, unsigned char *buf); static int getMTU(JNIEnv *env, int sock, const char *ifname); +#if defined(__solaris__) +static int getMacFromDevice(JNIEnv *env, const char *ifname, + unsigned char *retbuf); +#endif + /******************* Java entry points *****************************/ /* @@ -1658,6 +1674,372 @@ #endif /* _AIX */ +/** Solaris **/ +#if defined(__solaris__) + +/* + * Opens a socket for further ioctl calls. Tries AF_INET socket first and + * if it fails return AF_INET6 socket. + */ +static int openSocketWithFallback(JNIEnv *env, const char *ifname) { + int sock, alreadyV6 = 0; + struct lifreq if2; + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) { + if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); + return -1; + } + alreadyV6 = 1; + } else { // errno is not NOSUPPORT + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed"); + return -1; + } + } + + // Solaris requires that we have an IPv6 socket to query an interface + // without an IPv4 address - check it here. POSIX 1 require the kernel to + // return ENOTTY if the call is inappropriate for a device e.g. the NETMASK + // for a device having IPv6 only address but not all devices follow the + // standard so fall back on any error. It's not an ecologically friendly + // gesture but more reliable. + if (!alreadyV6) { + memset((char *)&if2, 0, sizeof(if2)); + strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); + if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) { + close(sock); + if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed"); + return -1; + } + } + } + + return sock; +} + +/* + * Enumerates and returns all IPv4 interfaces on Solaris. + */ +static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) { + struct lifconf ifc; + struct lifreq *ifreqP; + struct lifnum numifs; + char *buf = NULL; + unsigned i; + + // call SIOCGLIFNUM to get the interface count + numifs.lifn_family = AF_INET; + numifs.lifn_flags = 0; + if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed"); + return ifs; + } + + // call SIOCGLIFCONF to enumerate the interfaces + ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq); + CHECKED_MALLOC3(buf, char *, ifc.lifc_len); + ifc.lifc_buf = buf; + ifc.lifc_family = AF_INET; + ifc.lifc_flags = 0; + if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed"); + free(buf); + return ifs; + } + + // iterate through each interface + ifreqP = ifc.lifc_req; + for (i = 0; i < numifs.lifn_count; i++, ifreqP++) { + struct sockaddr addr, *broadaddrP = NULL; + + // ignore non IPv4 addresses + if (ifreqP->lifr_addr.ss_family != AF_INET) { + continue; + } + + // save socket address + memcpy(&addr, &(ifreqP->lifr_addr), sizeof(struct sockaddr)); + + // determine broadcast address, if applicable + if ((ioctl(sock, SIOCGLIFFLAGS, ifreqP) == 0) && + ifreqP->lifr_flags & IFF_BROADCAST) { + + // restore socket address to ifreqP + memcpy(&(ifreqP->lifr_addr), &addr, sizeof(struct sockaddr)); + + // query broadcast address and set pointer to it + if (ioctl(sock, SIOCGLIFBRDADDR, ifreqP) == 0) { + broadaddrP = (struct sockaddr *)&(ifreqP->lifr_broadaddr); + } + } + + // add to the list + ifs = addif(env, sock, ifreqP->lifr_name, ifs, + &addr, broadaddrP, AF_INET, (short)ifreqP->lifr_addrlen); + + // if an exception occurred we return immediately + if ((*env)->ExceptionOccurred(env)) { + free(buf); + return ifs; + } + } + + // free buffer + free(buf); + return ifs; +} + +/* + * Enumerates and returns all IPv6 interfaces on Solaris. + */ +static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) { + struct lifconf ifc; + struct lifreq *ifreqP; + struct lifnum numifs; + char *buf = NULL; + unsigned i; + + // call SIOCGLIFNUM to get the interface count + numifs.lifn_family = AF_INET6; + numifs.lifn_flags = 0; + if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed"); + return ifs; + } + + // call SIOCGLIFCONF to enumerate the interfaces + ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq); + CHECKED_MALLOC3(buf, char *, ifc.lifc_len); + ifc.lifc_buf = buf; + ifc.lifc_family = AF_INET6; + ifc.lifc_flags = 0; + if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed"); + free(buf); + return ifs; + } + + // iterate through each interface + ifreqP = ifc.lifc_req; + for (i = 0; i < numifs.lifn_count; i++, ifreqP++) { + + // ignore non IPv6 addresses + if (ifreqP->lifr_addr.ss_family != AF_INET6) { + continue; + } + + // set scope ID to interface index + ((struct sockaddr_in6 *)&(ifreqP->lifr_addr))->sin6_scope_id = + getIndex(sock, ifreqP->lifr_name); + + // add to the list + ifs = addif(env, sock, ifreqP->lifr_name, ifs, + (struct sockaddr *)&(ifreqP->lifr_addr), + NULL, AF_INET6, (short)ifreqP->lifr_addrlen); + + // if an exception occurred we return immediately + if ((*env)->ExceptionOccurred(env)) { + free(buf); + return ifs; + } + } + + // free buffer + free(buf); + return ifs; +} + +/* + * Try to get the interface index. + * (Not supported on Solaris 2.6 or 7) + */ +static int getIndex(int sock, const char *name) { + struct lifreq if2; + memset((char *)&if2, 0, sizeof(if2)); + strncpy(if2.lifr_name, name, sizeof(if2.lifr_name) - 1); + + if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) { + return -1; + } + + return if2.lifr_index; +} + +/* + * Solaris specific DLPI code to get hardware address from a device. + * Unfortunately, at least up to Solaris X, you have to have special + * privileges (i.e. be root). + */ +static int getMacFromDevice + (JNIEnv *env, const char *ifname, unsigned char *retbuf) +{ + char style1dev[MAXPATHLEN]; + int fd; + dl_phys_addr_req_t dlpareq; + dl_phys_addr_ack_t *dlpaack; + dl_error_ack_t *dlerack; + struct strbuf msg; + char buf[128]; + int flags = 0; + + // Device is in /dev. e.g.: /dev/bge0 + strcpy(style1dev, DEV_PREFIX); + strcat(style1dev, ifname); + if ((fd = open(style1dev, O_RDWR)) < 0) { + // Can't open it. We probably are missing the privilege. + // We'll have to try something else + return 0; + } + + dlpareq.dl_primitive = DL_PHYS_ADDR_REQ; + dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR; + + msg.buf = (char *)&dlpareq; + msg.len = DL_PHYS_ADDR_REQ_SIZE; + + if (putmsg(fd, &msg, NULL, 0) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "putmsg() failed"); + return -1; + } + + dlpaack = (dl_phys_addr_ack_t *)buf; + + msg.buf = (char *)buf; + msg.len = 0; + msg.maxlen = sizeof (buf); + if (getmsg(fd, &msg, NULL, &flags) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "getmsg() failed"); + return -1; + } + + if (dlpaack->dl_primitive == DL_ERROR_ACK) { + dlerack = (dl_error_ack_t *)buf; + if (dlerack->dl_error_primitive != DL_PHYS_ADDR_REQ) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", + "Couldn't obtain physical address\n"); + return -1; + } + if (dlerack->dl_errno == DL_UNSUPPORTED) { + // fallback to lookup in the ARP table + return 0; + } + } + + if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", + "Couldn't obtain phys addr\n"); + return -1; + } + + memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length); + return dlpaack->dl_addr_length; +} + +/* + * Gets the Hardware address (usually MAC address) for the named interface. + * On return puts the data in buf, and returns the length, in byte, of the + * MAC address. Returns -1 if there is no hardware address on that interface. + */ +static int getMacAddress + (JNIEnv *env, const char *ifname, const struct in_addr *addr, + unsigned char *buf) +{ + struct lifreq if2; + int len, i, sock; + + if ((sock = openSocketWithFallback(env, ifname)) < 0) { + return -1; + } + + // First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails + // try the old way. + memset((char *)&if2, 0, sizeof(if2)); + strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); + + if (ioctl(sock, SIOCGLIFHWADDR, &if2) != -1) { + struct sockaddr_dl *sp; + sp = (struct sockaddr_dl *)&if2.lifr_addr; + memcpy(buf, &sp->sdl_data[0], sp->sdl_alen); + close(sock); + return sp->sdl_alen; + } + + // On Solaris we have to use DLPI, but it will only work if we have + // privileged access (i.e. root). If that fails, we try a lookup + // in the ARP table, which requires an IPv4 address. + if (((len = getMacFromDevice(env, ifname, buf)) == 0) && (addr != NULL)) { + struct arpreq arpreq; + struct sockaddr_in *sin; + struct sockaddr_in ipAddr; + + len = 6; //??? + + sin = (struct sockaddr_in *)&arpreq.arp_pa; + memset((char *)&arpreq, 0, sizeof(struct arpreq)); + ipAddr.sin_port = 0; + ipAddr.sin_family = AF_INET; + memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr)); + memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in)); + arpreq.arp_flags= ATF_PUBL; + + if (ioctl(sock, SIOCGARP, &arpreq) < 0) { + close(sock); + return -1; + } + + memcpy(buf, &arpreq.arp_ha.sa_data[0], len); + } + close(sock); + + // all bytes to 0 means no hardware address + for (i = 0; i < len; i++) { + if (buf[i] != 0) + return len; + } + + return -1; +} + +static int getMTU(JNIEnv *env, int sock, const char *ifname) { + struct lifreq if2; + memset((char *)&if2, 0, sizeof(if2)); + strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); + + if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) { + JNU_ThrowByNameWithMessageAndLastError + (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFMTU) failed"); + return -1; + } + + return if2.lifr_mtu; +} + +static int getFlags(int sock, const char *ifname, int *flags) { + struct lifreq if2; + memset((char *)&if2, 0, sizeof(if2)); + strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1); + + if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2) < 0) { + return -1; + } + + *flags = if2.lifr_flags; + return 0; +} + +#endif /* __solaris__ */ + /** BSD **/ #if defined(_ALLBSD_SOURCE) diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/portconfig.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/portconfig.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/portconfig.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/portconfig.c 2024-01-27 14:37:30.263031299 +0100 @@ -60,6 +60,13 @@ } return -1; } + +#elif defined(__solaris__) + { + range->higher = net_getParam("/dev/tcp", "tcp_largest_anon_port"); + range->lower = net_getParam("/dev/tcp", "tcp_smallest_anon_port"); + return 0; + } #elif defined(_ALLBSD_SOURCE) { int ret; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/SdpSupport.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/SdpSupport.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnet/SdpSupport.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnet/SdpSupport.c 2024-01-27 14:37:30.261579994 +0100 @@ -27,7 +27,11 @@ #include #include -#if defined(__linux__) +#if defined(__solaris__) + #if !defined(PROTO_SDP) + #define PROTO_SDP 257 + #endif +#elif defined(__linux__) #if !defined(AF_INET_SDP) #define AF_INET_SDP 27 #endif @@ -51,7 +55,10 @@ { int s; -#if defined(__linux__) +#if defined(__solaris__) + int domain = ipv6_available() ? AF_INET6 : AF_INET; + s = socket(domain, SOCK_STREAM, PROTO_SDP); +#elif defined(__linux__) /** * IPv6 not supported by SDP on Linux */ diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c 2024-01-27 14:37:30.263465003 +0100 @@ -50,6 +50,9 @@ jint fd = fdval(env, fdo); int rv; +#if defined(__solaris__) + rv = connect(fd, 0, 0); +#else #if defined(__APPLE__) // On macOS systems we use disconnectx rv = disconnectx(fd, SAE_ASSOCID_ANY, SAE_CONNID_ANY); @@ -83,6 +86,8 @@ rv = errno = 0; #endif // defined(_ALLBSD_SOURCE) || defined(_AIX) +#endif // defined(__solaris__) + if (rv < 0) handleSocketError(env, errno); } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/NativeThread.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/NativeThread.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/NativeThread.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/NativeThread.c 2024-01-27 14:37:30.263835074 +0100 @@ -40,6 +40,9 @@ #elif defined(_AIX) /* Also defined in net/aix_close.c */ #define INTERRUPT_SIGNAL (SIGRTMAX - 1) +#elif defined(__solaris__) + #include + #define INTERRUPT_SIGNAL (SIGRTMAX - 2) #elif defined(_ALLBSD_SOURCE) /* Also defined in net/bsd_close.c */ #define INTERRUPT_SIGNAL SIGIO @@ -73,14 +76,22 @@ JNIEXPORT jlong JNICALL Java_sun_nio_ch_NativeThread_current0(JNIEnv *env, jclass cl) { +#ifdef __solaris__ + return (jlong)thr_self(); +#else return (jlong)pthread_self(); +#endif } JNIEXPORT void JNICALL Java_sun_nio_ch_NativeThread_signal0(JNIEnv *env, jclass cl, jlong thread) { int ret; +#ifdef __solaris__ + ret = thr_kill((thread_t)thread, INTERRUPT_SIGNAL); +#else ret = pthread_kill((pthread_t)thread, INTERRUPT_SIGNAL); +#endif #ifdef MACOSX if (ret != 0 && ret != ESRCH) #else diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/Net.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/Net.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/Net.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/Net.c 2024-01-27 14:37:30.264317558 +0100 @@ -215,7 +215,7 @@ JNIEXPORT jboolean JNICALL Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl) { -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) || defined(__APPLE__) || defined(__solaris__) /* IPv6 sockets can join IPv4 multicast groups */ return JNI_TRUE; #else @@ -227,7 +227,7 @@ JNIEXPORT jboolean JNICALL Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl) { -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__solaris__) /* IPV6_ADD_MEMBERSHIP can be used to join IPv4 multicast groups */ return JNI_TRUE; #else diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/nio_util.h jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/nio_util.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/ch/nio_util.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/ch/nio_util.h 2024-01-27 14:37:30.264654438 +0100 @@ -41,6 +41,8 @@ #ifndef SO_REUSEPORT #ifdef __linux__ #define SO_REUSEPORT 15 +#elif defined(__solaris__) +#define SO_REUSEPORT 0x100e #elif defined(AIX) || defined(MACOSX) #define SO_REUSEPORT 0x0200 #else diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c 2024-01-27 14:37:30.265241690 +0100 @@ -45,10 +45,17 @@ #include #endif -/* For POSIX-compliant getpwuid_r */ +/* For POSIX-compliant getpwuid_r, getgrgid_r on Solaris */ +#if defined(__solaris__) +#define _POSIX_PTHREAD_SEMANTICS +#endif #include #include +#ifdef __solaris__ +#include +#endif + #ifdef __linux__ #include #include // makedev macros @@ -374,7 +381,8 @@ /* system calls that might not be available at run time */ -#if defined(_ALLBSD_SOURCE) +#if (defined(__solaris__) && defined(_LP64)) || defined(_ALLBSD_SOURCE) + /* Solaris 64-bit does not have openat64/fstatat64 */ my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat"); my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat"); #else diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.base/windows/native/libnet/net_util_md.c jdk21u-jdk-21.0.2-ga/src/java.base/windows/native/libnet/net_util_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.base/windows/native/libnet/net_util_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.base/windows/native/libnet/net_util_md.c 2024-01-27 14:37:30.265681808 +0100 @@ -125,6 +125,8 @@ } return TRUE; } + +void parseExclusiveBindProperty(JNIEnv *env) {} /* * Since winsock doesn't have the equivalent of strerror(errno) diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/classes/sun/awt/FontConfiguration.java jdk21u-jdk-21.0.2-ga/src/java.desktop/share/classes/sun/awt/FontConfiguration.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/classes/sun/awt/FontConfiguration.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/share/classes/sun/awt/FontConfiguration.java 2024-01-27 14:37:30.266545982 +0100 @@ -1422,6 +1422,22 @@ } } } + if (OSInfo.getOSType() == OSInfo.OSType.SOLARIS) { + for (int ii = 0; ii < table_awtfontpaths.length; ii++) { + if (table_awtfontpaths[ii] == 0) { + String script = getString(table_scriptIDs[ii]); + if (script.contains("dingbats") || + script.contains("symbol")) { + continue; + } + System.err.println("\nError: " + + " entry is missing!!!"); + errors++; + } + } + } if (errors != 0) { System.err.println("!!THERE ARE " + errors + " ERROR(S) IN " + "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n"); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/classes/sun/awt/OSInfo.java jdk21u-jdk-21.0.2-ga/src/java.desktop/share/classes/sun/awt/OSInfo.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/classes/sun/awt/OSInfo.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/share/classes/sun/awt/OSInfo.java 2024-01-27 14:37:30.266914895 +0100 @@ -39,6 +39,7 @@ public static enum OSType { WINDOWS, LINUX, + SOLARIS, MACOSX, AIX, UNKNOWN @@ -95,6 +96,7 @@ // Map OperatingSystem enum values to OSType enum values. case WINDOWS -> WINDOWS; case LINUX -> LINUX; + case SOLARIS -> SOLARIS; case MACOS -> MACOSX; case AIX -> AIX; default -> UNKNOWN; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/classes/sun/font/FontUtilities.java jdk21u-jdk-21.0.2-ga/src/java.desktop/share/classes/sun/font/FontUtilities.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/classes/sun/font/FontUtilities.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/share/classes/sun/font/FontUtilities.java 2024-01-27 14:37:30.267416410 +0100 @@ -41,6 +41,8 @@ */ public final class FontUtilities { + public static boolean isSolaris; + public static boolean isLinux; public static boolean isMacOSX; @@ -66,6 +68,8 @@ @Override public Object run() { + isSolaris = OSInfo.getOSType() == OSInfo.OSType.SOLARIS; + isLinux = OSInfo.getOSType() == OSInfo.OSType.LINUX; isMacOSX = OSInfo.getOSType() == OSInfo.OSType.MACOSX; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/native/libjsound/SoundDefs.h jdk21u-jdk-21.0.2-ga/src/java.desktop/share/native/libjsound/SoundDefs.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/share/native/libjsound/SoundDefs.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/share/native/libjsound/SoundDefs.h 2024-01-27 14:37:30.267847458 +0100 @@ -29,9 +29,10 @@ // types for X_PLATFORM #define X_WINDOWS 1 -#define X_LINUX 2 -#define X_BSD 3 -#define X_MACOSX 4 +#define X_SOLARIS 2 +#define X_LINUX 3 +#define X_BSD 4 +#define X_MACOSX 5 // ********************************** // Make sure you set X_PLATFORM defines correctly. @@ -44,7 +45,7 @@ // following is needed for _LP64 -#if ((X_PLATFORM == X_LINUX) || (X_PLATFORM == X_MACOSX)) +#if ((X_PLATFORM == X_SOLARIS) || (X_PLATFORM == X_LINUX) || (X_PLATFORM == X_MACOSX)) #include #endif @@ -114,6 +115,11 @@ #endif +#if X_PLATFORM == X_SOLARIS +#define INLINE +#endif + + #if X_PLATFORM == X_LINUX #define INLINE inline #endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java 2024-01-27 14:37:30.305627404 +0100 @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2001, 2008, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.font; + +import java.nio.CharBuffer; +import java.nio.ByteBuffer; +import java.nio.charset.*; +import sun.nio.cs.*; + +public abstract class X11CNS11643 extends Charset { + private final int plane; + public X11CNS11643 (int plane, String name) { + super(name, null); + switch (plane) { + case 1: + this.plane = 0; // CS1 + break; + case 2: + case 3: + this.plane = plane; + break; + default: + throw new IllegalArgumentException + ("Only planes 1, 2, and 3 supported"); + } + } + + public CharsetEncoder newEncoder() { + return new Encoder(this, plane); + } + + public CharsetDecoder newDecoder() { + return new Decoder(this, plane); + } + + public boolean contains(Charset cs) { + return cs instanceof X11CNS11643; + } + + private class Encoder extends EUC_TW.Encoder { + private int plane; + public Encoder(Charset cs, int plane) { + super(cs); + this.plane = plane; + } + + private byte[] bb = new byte[4]; + public boolean canEncode(char c) { + if (c <= 0x7F) { + return false; + } + int nb = toEUC(c, bb); + if (nb == -1) + return false; + int p = 0; + if (nb == 4) + p = (bb[1] & 0xff) - 0xa0; + return (p == plane); + } + + public boolean isLegalReplacement(byte[] repl) { + return true; + } + + protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) { + char[] sa = src.array(); + int sp = src.arrayOffset() + src.position(); + int sl = src.arrayOffset() + src.limit(); + byte[] da = dst.array(); + int dp = dst.arrayOffset() + dst.position(); + int dl = dst.arrayOffset() + dst.limit(); + + try { + while (sp < sl) { + char c = sa[sp]; + if ( c > '\u007f'&& c < '\uFFFE') { + int nb = toEUC(c, bb); + if (nb != -1) { + int p = 0; + if (nb == 4) + p = (bb[1] & 0xff) - 0xa0; + if (p == plane) { + if (dl - dp < 2) + return CoderResult.OVERFLOW; + if (nb == 2) { + da[dp++] = (byte)(bb[0] & 0x7f); + da[dp++] = (byte)(bb[1] & 0x7f); + } else { + da[dp++] = (byte)(bb[2] & 0x7f); + da[dp++] = (byte)(bb[3] & 0x7f); + } + sp++; + continue; + } + } + } + return CoderResult.unmappableForLength(1); + } + return CoderResult.UNDERFLOW; + } finally { + src.position(sp - src.arrayOffset()); + dst.position(dp - dst.arrayOffset()); + } + } + } + + private class Decoder extends EUC_TW.Decoder { + int plane; + private String table; + protected Decoder(Charset cs, int plane) { + super(cs); + if (plane == 0) + this.plane = plane; + else if (plane == 2 || plane == 3) + this.plane = plane - 1; + else + throw new IllegalArgumentException + ("Only planes 1, 2, and 3 supported"); + } + + //we only work on array backed buffer. + protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) { + byte[] sa = src.array(); + int sp = src.arrayOffset() + src.position(); + int sl = src.arrayOffset() + src.limit(); + + char[] da = dst.array(); + int dp = dst.arrayOffset() + dst.position(); + int dl = dst.arrayOffset() + dst.limit(); + + try { + while (sp < sl) { + if ( sl - sp < 2) { + return CoderResult.UNDERFLOW; + } + int b1 = (sa[sp] & 0xff) | 0x80; + int b2 = (sa[sp + 1] & 0xff) | 0x80; + char[] cc = toUnicode(b1, b2, plane); + // plane3 has non-bmp characters(added), x11cnsp3 + // however does not support them + if (cc == null || cc.length == 2) + return CoderResult.unmappableForLength(2); + if (dl - dp < 1) + return CoderResult.OVERFLOW; + da[dp++] = cc[0]; + sp +=2; + } + return CoderResult.UNDERFLOW; + } finally { + src.position(sp - src.arrayOffset()); + dst.position(dp - dst.arrayOffset()); + } + } + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java 2024-01-27 14:37:30.305860242 +0100 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 1996, 2005, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + + +package sun.font; + +public class X11CNS11643P1 extends X11CNS11643 { + public X11CNS11643P1() { + super(1, "X11CNS11643P1"); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java 2024-01-27 14:37:30.306095883 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1996, 2005, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.font; + +public class X11CNS11643P2 extends X11CNS11643 { + public X11CNS11643P2() { + super(2, "X11CNS11643P2"); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java 2024-01-27 14:37:30.306323801 +0100 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 1997, 2005, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package sun.font; + +public class X11CNS11643P3 extends X11CNS11643 { + public X11CNS11643P3() { + super(3, "X11CNS11643P3"); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/data/fontconfig/fontconfig.properties jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/data/fontconfig/fontconfig.properties --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/data/fontconfig/fontconfig.properties 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/data/fontconfig/fontconfig.properties 2024-01-27 14:37:30.282501269 +0100 @@ -0,0 +1,516 @@ +# +# +# Copyright (c) 2005, 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# + +# Version + +version=1 + +# Component Font Mappings + +allfonts.chinese-gb2312=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-gbk=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-gb18030-0=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-gb18030-1=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-cns11643-1=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-cns11643-2=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-cns11643-3=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-big5=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.chinese-hkscs=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.dingbats=-microsoft-wingdings-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific +allfonts.japanese-x0212=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.korean=-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.korean-johab=-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +allfonts.symbol=-monotype-symbol-medium-r-normal--*-%d-*-*-p-*-adobe-symbol +allfonts.bengali=-misc-lohit bengali-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.gujarati=-misc-lohit gujarati-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.hindi=-misc-lohit hindi-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.kannada=-misc-lohit kannada-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.malayalam=-misc-lohit malayalam-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.marathi=-misc-lohit marathi-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.tamil=-misc-lohit tamil-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.telugu=-misc-lohit telugu-medium-r-normal--0-0-0-0-p-0-iso10646-1 +allfonts.dejavusans=-misc-dejavu sans-medium-r-normal--0-0-0-0-p-0-iso10646-1 + +serif.plain.arabic=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.cyrillic-iso8859-5=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.cyrillic-cp1251=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.cyrillic-koi8-r=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.greek=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.hebrew=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.plain.latin-1=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.latin-2=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.latin-5=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.latin-7=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.latin-9=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.plain.thai=-monotype-angsana new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 + +serif.bold.arabic=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.cyrillic-iso8859-5=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.cyrillic-cp1251=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.cyrillic-koi8-r=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.greek=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.hebrew=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.bold.latin-1=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.latin-2=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.latin-5=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.latin-7=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.latin-9=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bold.thai=-monotype-angsana new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 + +serif.italic.arabic=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.cyrillic-iso8859-5=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.cyrillic-cp1251=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.cyrillic-koi8-r=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.greek=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.hebrew=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.italic.latin-1=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.latin-2=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.latin-5=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.latin-7=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.latin-9=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.italic.thai=-monotype-angsana new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 + +serif.bolditalic.arabic=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.cyrillic-iso8859-5=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.cyrillic-cp1251=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.cyrillic-koi8-r=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.greek=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.hebrew=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +serif.bolditalic.latin-1=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.latin-2=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.latin-5=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.latin-7=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.latin-9=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +serif.bolditalic.thai=-monotype-angsana new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 + +sansserif.plain.arabic=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.cyrillic-iso8859-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.cyrillic-cp1251=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.cyrillic-koi8-r=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.greek=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.hebrew=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.plain.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.plain.latin-1=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.latin-2=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.latin-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.latin-7=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.latin-9=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.plain.thai=-monotype-browallia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 + +sansserif.bold.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.cyrillic-iso8859-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.cyrillic-cp1251=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.cyrillic-koi8-r=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.greek=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.hebrew=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.bold.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.bold.latin-1=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.latin-2=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.latin-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.latin-7=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.latin-9=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bold.thai=-monotype-browallia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 + +sansserif.italic.arabic=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.cyrillic-iso8859-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.cyrillic-cp1251=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.cyrillic-koi8-r=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.greek=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.hebrew=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.italic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.italic.latin-1=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.latin-2=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.latin-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.latin-7=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.latin-9=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.italic.thai=-monotype-browallia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 + +sansserif.bolditalic.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.cyrillic-iso8859-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.cyrillic-cp1251=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.cyrillic-koi8-r=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.greek=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.hebrew=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.bolditalic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +sansserif.bolditalic.latin-1=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.latin-2=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.latin-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.latin-7=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.latin-9=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +sansserif.bolditalic.thai=-monotype-browallia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 + +monospaced.plain.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.cyrillic-iso8859-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.cyrillic-cp1251=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.cyrillic-koi8-r=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.greek=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.hebrew=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.plain.latin-1=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.latin-2=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.latin-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.latin-7=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.latin-9=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.plain.thai=-monotype-cordia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 + +monospaced.bold.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.cyrillic-iso8859-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.cyrillic-cp1251=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.cyrillic-koi8-r=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.greek=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.hebrew=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.bold.latin-1=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.latin-2=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.latin-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.latin-7=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.latin-9=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bold.thai=-monotype-cordia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 + +monospaced.italic.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.cyrillic-iso8859-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.cyrillic-cp1251=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.cyrillic-koi8-r=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.greek=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.hebrew=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.italic.latin-1=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.latin-2=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.latin-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.latin-7=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.latin-9=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.italic.thai=-monotype-cordia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 + +monospaced.bolditalic.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.cyrillic-iso8859-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.cyrillic-cp1251=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.cyrillic-koi8-r=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.greek=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.hebrew=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +monospaced.bolditalic.latin-1=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.latin-2=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.latin-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.latin-7=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.latin-9=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +monospaced.bolditalic.thai=-monotype-cordia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 + +dialog.plain.arabic=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.cyrillic-iso8859-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.cyrillic-cp1251=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.cyrillic-koi8-r=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.greek=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.hebrew=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.plain.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.plain.latin-1=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.latin-2=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.latin-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.latin-7=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.latin-9=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.plain.thai=-monotype-browallia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 + +dialog.bold.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.cyrillic-iso8859-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.cyrillic-cp1251=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.cyrillic-koi8-r=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.greek=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.hebrew=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.bold.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.bold.latin-1=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.latin-2=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.latin-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.latin-7=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.latin-9=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bold.thai=-monotype-browallia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 + +dialog.italic.arabic=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.cyrillic-iso8859-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.cyrillic-cp1251=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.cyrillic-koi8-r=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.greek=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.hebrew=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.italic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.italic.latin-1=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.latin-2=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.latin-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.latin-7=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.latin-9=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.italic.thai=-monotype-browallia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 + +dialog.bolditalic.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.cyrillic-iso8859-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.cyrillic-cp1251=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.cyrillic-koi8-r=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.greek=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.hebrew=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.bolditalic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialog.bolditalic.latin-1=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.latin-2=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.latin-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.latin-7=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.latin-9=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialog.bolditalic.thai=-monotype-browallia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 + +dialoginput.plain.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.cyrillic-iso8859-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.cyrillic-cp1251=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.cyrillic-koi8-r=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.greek=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.hebrew=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.plain.latin-1=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.latin-2=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.latin-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.latin-7=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.latin-9=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.plain.thai=-monotype-cordia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 + +dialoginput.bold.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.cyrillic-iso8859-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.cyrillic-cp1251=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.cyrillic-koi8-r=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.greek=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.hebrew=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.bold.latin-1=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.latin-2=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.latin-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.latin-7=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.latin-9=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bold.thai=-monotype-cordia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 + +dialoginput.italic.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.cyrillic-iso8859-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.cyrillic-cp1251=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.cyrillic-koi8-r=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.greek=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.hebrew=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.italic.latin-1=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.latin-2=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.latin-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.latin-7=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.latin-9=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.italic.thai=-monotype-cordia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1 + +dialoginput.bolditalic.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.cyrillic-iso8859-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.cyrillic-cp1251=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.cyrillic-koi8-r=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.greek=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.hebrew=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1 +dialoginput.bolditalic.latin-1=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.latin-2=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.latin-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.latin-7=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.latin-9=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 +dialoginput.bolditalic.thai=-monotype-cordia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1 + +# Search Sequences + +sequence.allfonts=latin-1 + +sequence.allfonts.Big5=latin-1,chinese-big5 + +sequence.allfonts.Big5-HKSCS-2001=latin-1,chinese-big5,chinese-hkscs + +sequence.allfonts.windows-1251=cyrillic-cp1251,latin-1 + +sequence.allfonts.GB2312=latin-1,chinese-gb2312 + +sequence.allfonts.x-eucJP-Open=latin-1,japanese-x0201,japanese-x0208,japanese-x0212 + +sequence.allfonts.EUC-KR=latin-1,korean + +sequence.allfonts.x-EUC-TW=latin-1,chinese-cns11643-1,chinese-cns11643-2,chinese-cns11643-3 + +sequence.allfonts.GBK=latin-1,chinese-gbk + +sequence.allfonts.GB18030=latin-1,chinese-gb18030-0,chinese-gb18030-1 + +sequence.allfonts.ISO-8859-2=latin-2,latin-1 + +sequence.allfonts.ISO-8859-5=cyrillic-iso8859-5,latin-1 + +sequence.allfonts.ISO-8859-6=arabic,latin-1 + +sequence.allfonts.ISO-8859-7=latin-1,greek + +sequence.allfonts.ISO-8859-8=latin-1,hebrew + +sequence.allfonts.ISO-8859-9=latin-5,latin-1 + +sequence.allfonts.ISO-8859-13=latin-7,latin-1 + +sequence.allfonts.ISO-8859-15=latin-9 + +sequence.allfonts.KOI8-R=cyrillic-koi8-r,latin-1 + +sequence.allfonts.x-PCK=latin-1,japanese-x0201,japanese-x0208,japanese-x0212 + +sequence.allfonts.TIS-620=latin-1,thai + +sequence.allfonts.UTF-8=latin-1 +sequence.allfonts.UTF-8.en=latin-1 +sequence.allfonts.UTF-8.hi=latin-1,hindi +sequence.allfonts.UTF-8.be=latin-1,bengali +sequence.allfonts.UTF-8.te=latin-1,telugu +sequence.allfonts.UTF-8.mr=latin-1,marathi +sequence.allfonts.UTF-8.ta=latin-1,tamil +sequence.allfonts.UTF-8.gu=latin-1,gujarati +sequence.allfonts.UTF-8.kn=latin-1,kannada +sequence.allfonts.UTF-8.ma=latin-1,malayalam + +sequence.allfonts.UTF-8.ko=latin-1,korean-johab,japanese-x0201,japanese-x0208,japanese-x0212 + +sequence.allfonts.UTF-8.th=latin-1,thai + +sequence.allfonts.UTF-8.zh.CN=latin-1,chinese-gb18030-0,chinese-gb18030-1,chinese-big5,chinese-hkscs + +sequence.allfonts.UTF-8.zh.HK=latin-1,chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1 + +sequence.allfonts.UTF-8.zh.TW=latin-1,chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1 + +# the fallback sequence omits the following character subsets: +# - chinese: all same file : just use chinese-gb18030-0 +# - japanese-x0208: same files as japanese-x0201 +# - japanese-x0212: same files as japanese-x0201 +# - korean: same file as korean-johab +sequence.fallback=latin-1,latin-2,latin-7,cyrillic-iso8859-5,greek,latin-5,latin-9,\ + arabic,hebrew,thai,\ + chinese-gb18030-0,\ + japanese-x0201,korean-johab,\ + hindi,bengali,telugu,marathi,tamil,gujarati,kannada,malayalam,\ + dejavusans,dingbats,symbol + +# Font File Names + +filename.-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arial.ttf +filename.-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/ariali.ttf +filename.-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbd.ttf +filename.-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbi.ttf +filename.-monotype-courier_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cour.ttf +filename.-monotype-courier_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/couri.ttf +filename.-monotype-courier_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbd.ttf +filename.-monotype-courier_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbi.ttf +filename.-monotype-times_new_roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/times.ttf +filename.-monotype-times_new_roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesi.ttf +filename.-monotype-times_new_roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbd.ttf +filename.-monotype-times_new_roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbi.ttf + +filename.-monotype-angsana_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsa.ttf +filename.-monotype-angsana_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsai.ttf +filename.-monotype-angsana_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsab.ttf +filename.-monotype-angsana_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsaz.ttf +filename.-monotype-browallia_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browa.ttf +filename.-monotype-browallia_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browai.ttf +filename.-monotype-browallia_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browab.ttf +filename.-monotype-browallia_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browaz.ttf +filename.-monotype-cordia_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordia.ttf +filename.-monotype-cordia_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiai.ttf +filename.-monotype-cordia_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiab.ttf +filename.-monotype-cordia_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiaz.ttf + +filename.-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/ipafont/ipag.otf +filename.-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/ipafont/ipam.otf +filename.-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/hanyang/h2gtrm.ttf +filename.-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/arphic/uming.ttf +filename.-monotype-symbol-medium-r-normal--*-%d-*-*-p-*-adobe-symbol=/usr/share/fonts/TrueType/core/symbol.ttf +filename.-microsoft-wingdings-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific=/usr/share/fonts/TrueType/core/wingdings.ttf +filename.-misc-lohit_bengali-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Bengali.ttf +filename.-misc-lohit_gujarati-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Gujarati.ttf +filename.-misc-lohit_hindi-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Hindi.ttf +filename.-misc-lohit_kannada-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Kannada.ttf +filename.-misc-lohit_malayalam-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Malayalam.ttf +filename.-misc-lohit_marathi-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Marathi.ttf +filename.-misc-lohit_tamil-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Tamil.ttf +filename.-misc-lohit_telugu-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Telugu.ttf +filename.-misc-dejavu_sans-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/dejavu/DejaVuSans.ttf + +# AWT X11 font paths +awtfontpath.latin-1=/usr/share/fonts/TrueType/core +awtfontpath.latin-2=/usr/share/fonts/TrueType/core +awtfontpath.latin-5=/usr/share/fonts/TrueType/core +awtfontpath.latin-7=/usr/share/fonts/TrueType/core +awtfontpath.latin-9=/usr/share/fonts/TrueType/core +awtfontpath.hebrew=/usr/share/fonts/TrueType/core +awtfontpath.arabic=/usr/share/fonts/TrueType/core +awtfontpath.thai=/usr/share/fonts/TrueType/core +awtfontpath.greek=/usr/share/fonts/TrueType/core +awtfontpath.cyrillic-iso8859-5=/usr/share/fonts/TrueType/core +awtfontpath.cyrillic-cp1251=/usr/share/fonts/TrueType/core +awtfontpath.cyrillic-koi8-r=/usr/share/fonts/TrueType/core +awtfontpath.korean=/usr/share/fonts/TrueType/hanyang +awtfontpath.korean-johab=/usr/share/fonts/TrueType/hanyang +awtfontpath.japanese-x0201=/usr/share/fonts/TrueType/ipafont +awtfontpath.japanese-x0208=/usr/share/fonts/TrueType/ipafont +awtfontpath.japanese-x0212=/usr/share/fonts/TrueType/ipafont +awtfontpath.chinese-gbk=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-cns11643-1=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-cns11643-2=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-cns11643-3=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-big5=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-gb2312=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-gb18030-0=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-gb18030-1=/usr/share/fonts/TrueType/arphic +awtfontpath.chinese-hkscs=/usr/share/fonts/TrueType/arphic +awtfontpath.bengali=/usr/share/fonts/TrueType/lohit +awtfontpath.gujarati=/usr/share/fonts/TrueType/lohit +awtfontpath.hindi=/usr/share/fonts/TrueType/lohit +awtfontpath.kannada=/usr/share/fonts/TrueType/lohit +awtfontpath.malayalam=/usr/share/fonts/TrueType/lohit +awtfontpath.marathi=/usr/share/fonts/TrueType/lohit +awtfontpath.tamil=/usr/share/fonts/TrueType/lohit +awtfontpath.telugu=/usr/share/fonts/TrueType/lohit +awtfontpath.dejavusans=/usr/share/fonts/TrueType/dejavu + +# Appended Font Path + diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c 2024-01-27 14:37:30.306873039 +0100 @@ -0,0 +1,627 @@ +/* + * Copyright (c) 2003, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +#define USE_ERROR +#define USE_TRACE + +#include "PLATFORM_API_SolarisOS_Utils.h" +#include "DirectAudio.h" + +#if USE_DAUDIO == TRUE + + +// The default buffer time +#define DEFAULT_PERIOD_TIME_MILLIS 50 + +///// implemented functions of DirectAudio.h + +INT32 DAUDIO_GetDirectAudioDeviceCount() { + return (INT32) getAudioDeviceCount(); +} + + +INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex, + DirectAudioDeviceDescription* description) { + AudioDeviceDescription desc; + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { + description->maxSimulLines = desc.maxSimulLines; + strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1); + description->name[DAUDIO_STRING_LENGTH-1] = 0; + strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1); + description->vendor[DAUDIO_STRING_LENGTH-1] = 0; + strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1); + description->version[DAUDIO_STRING_LENGTH-1] = 0; + /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/ + strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1); + description->description[DAUDIO_STRING_LENGTH-1] = 0; + return TRUE; + } + return FALSE; + +} + +#define MAX_SAMPLE_RATES 20 + +void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) { + int fd = -1; + AudioDeviceDescription desc; + am_sample_rates_t *sr; + /* hardcoded bits and channels */ + int bits[] = {8, 16}; + int bitsCount = 2; + int channels[] = {1, 2}; + int channelsCount = 2; + /* for querying sample rates */ + int err; + int ch, b; + uint_t s; + + TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource); + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + fd = open(desc.pathctl, O_RDONLY); + } + if (fd < 0) { + ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); + return; + } + + /* get sample rates */ + sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES)); + if (sr == NULL) { + ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex); + close(fd); + return; + } + + sr->num_samp_rates = MAX_SAMPLE_RATES; + sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD; + sr->samp_rates[0] = -2; + err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr); + if (err < 0) { + ERROR1(" DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n", + (int)mixerIndex); + ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n", + (int) sr->num_samp_rates, + (int) sr->samp_rates[0]); + /* Some Solaris 8 drivers fail for get sample rates! + * Do as if we support all sample rates + */ + sr->flags = MIXER_SR_LIMITS; + } + if ((sr->flags & MIXER_SR_LIMITS) + || (sr->num_samp_rates > MAX_SAMPLE_RATES)) { +#ifdef USE_TRACE + if ((sr->flags & MIXER_SR_LIMITS)) { + TRACE1(" DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n", + (int)mixerIndex); + } + if (sr->num_samp_rates > MAX_SAMPLE_RATES) { + TRACE2(" DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n", + MAX_SAMPLE_RATES, (int)mixerIndex); + } +#endif + /* + * Fake it to have only one sample rate: -1 + */ + sr->num_samp_rates = 1; + sr->samp_rates[0] = -1; + } + close(fd); + + for (ch = 0; ch < channelsCount; ch++) { + for (b = 0; b < bitsCount; b++) { + for (s = 0; s < sr->num_samp_rates; s++) { + DAUDIO_AddAudioFormat(creator, + bits[b], /* significant bits */ + 0, /* frameSize: let it be calculated */ + channels[ch], + (float) ((int) sr->samp_rates[s]), + DAUDIO_PCM, /* encoding - let's only do PCM */ + (bits[b] > 8)?TRUE:TRUE, /* isSigned */ +#ifdef _LITTLE_ENDIAN + FALSE /* little endian */ +#else + (bits[b] > 8)?TRUE:FALSE /* big endian */ +#endif + ); + } + } + } + free(sr); +} + + +typedef struct { + int fd; + audio_info_t info; + int bufferSizeInBytes; + int frameSize; /* storage size in Bytes */ + /* how many bytes were written or read */ + INT32 transferedBytes; + /* if transferedBytes exceed 32-bit boundary, + * it will be reset and positionOffset will receive + * the offset + */ + INT64 positionOffset; +} SolPcmInfo; + + +void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource, + int encoding, float sampleRate, int sampleSizeInBits, + int frameSize, int channels, + int isSigned, int isBigEndian, int bufferSizeInBytes) { + int err = 0; + int openMode; + AudioDeviceDescription desc; + SolPcmInfo* info; + + TRACE0("> DAUDIO_Open\n"); + if (encoding != DAUDIO_PCM) { + ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding); + return NULL; + } + if (channels <= 0) { + ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels); + return NULL; + } + + info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo)); + if (!info) { + ERROR0("Out of memory\n"); + return NULL; + } + memset(info, 0, sizeof(SolPcmInfo)); + info->frameSize = frameSize; + info->fd = -1; + + if (isSource) { + openMode = O_WRONLY; + } else { + openMode = O_RDONLY; + } + +#ifndef __linux__ + /* blackdown does not use NONBLOCK */ + openMode |= O_NONBLOCK; +#endif + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + info->fd = open(desc.path, openMode); + } + if (info->fd < 0) { + ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex); + free(info); + return NULL; + } + /* set to multiple open */ + if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) { + TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path); + } else { + ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path); + } + + AUDIO_INITINFO(&(info->info)); + /* need AUDIO_GETINFO ioctl to get this to work on solaris x86 */ + err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); + + /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */ + AUDIO_INITINFO(&(info->info)); + + if (isSource) { + info->info.play.sample_rate = sampleRate; + info->info.play.precision = sampleSizeInBits; + info->info.play.channels = channels; + info->info.play.encoding = AUDIO_ENCODING_LINEAR; + info->info.play.buffer_size = bufferSizeInBytes; + info->info.play.pause = 1; + } else { + info->info.record.sample_rate = sampleRate; + info->info.record.precision = sampleSizeInBits; + info->info.record.channels = channels; + info->info.record.encoding = AUDIO_ENCODING_LINEAR; + info->info.record.buffer_size = bufferSizeInBytes; + info->info.record.pause = 1; + } + err = ioctl(info->fd, AUDIO_SETINFO, &(info->info)); + if (err < 0) { + ERROR0("DAUDIO_Open: could not set info!\n"); + DAUDIO_Close((void*) info, isSource); + return NULL; + } + DAUDIO_Flush((void*) info, isSource); + + err = ioctl(info->fd, AUDIO_GETINFO, &(info->info)); + if (err >= 0) { + if (isSource) { + info->bufferSizeInBytes = info->info.play.buffer_size; + } else { + info->bufferSizeInBytes = info->info.record.buffer_size; + } + TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n", + (int) bufferSizeInBytes, + (int) info->bufferSizeInBytes); + } else { + ERROR0("DAUDIO_Open: cannot get info!\n"); + DAUDIO_Close((void*) info, isSource); + return NULL; + } + TRACE0("< DAUDIO_Open: Opened device successfully.\n"); + return (void*) info; +} + + +int DAUDIO_Start(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err, modified; + audio_info_t audioInfo; + + TRACE0("> DAUDIO_Start\n"); + + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + // unpause + modified = FALSE; + if (isSource && audioInfo.play.pause) { + audioInfo.play.pause = 0; + modified = TRUE; + } + if (!isSource && audioInfo.record.pause) { + audioInfo.record.pause = 0; + modified = TRUE; + } + if (modified) { + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + } + } + + TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error"); + return (err >= 0)?TRUE:FALSE; +} + +int DAUDIO_Stop(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err, modified; + audio_info_t audioInfo; + + TRACE0("> DAUDIO_Stop\n"); + + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + // pause + modified = FALSE; + if (isSource && !audioInfo.play.pause) { + audioInfo.play.pause = 1; + modified = TRUE; + } + if (!isSource && !audioInfo.record.pause) { + audioInfo.record.pause = 1; + modified = TRUE; + } + if (modified) { + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + } + } + + TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error"); + return (err >= 0)?TRUE:FALSE; +} + +void DAUDIO_Close(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + + TRACE0("DAUDIO_Close\n"); + if (info != NULL) { + if (info->fd >= 0) { + DAUDIO_Flush(id, isSource); + close(info->fd); + } + free(info); + } +} + +#ifndef USE_TRACE +/* close to 2^31 */ +#define POSITION_MAX 2000000000 +#else +/* for testing */ +#define POSITION_MAX 1000000 +#endif + +void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) { + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int err; + int offset = -1; + int underrun = FALSE; + int devBytes = 0; + + if (count > 0) { + info->transferedBytes += count; + + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + underrun = prinfo->error; + devBytes = prinfo->samples * info->frameSize; + } + AUDIO_INITINFO(&audioInfo); + if (underrun) { + /* if an underrun occurred, reset */ + ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n", + (devBytes - info->transferedBytes)); + ERROR1(" devBytes from %d to 0, ", devBytes); + ERROR2(" positionOffset from %d to %d ", + (int) info->positionOffset, + (int) (info->positionOffset + info->transferedBytes)); + ERROR1(" transferedBytes from %d to 0\n", + (int) info->transferedBytes); + prinfo->samples = 0; + info->positionOffset += info->transferedBytes; + info->transferedBytes = 0; + } + else if (info->transferedBytes > POSITION_MAX) { + /* we will reset transferedBytes and + * the samples field in prinfo + */ + offset = devBytes; + prinfo->samples = 0; + } + /* reset error flag */ + prinfo->error = 0; + + err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo); + if (err >= 0) { + if (offset > 0) { + /* upon exit of AUDIO_SETINFO, the samples parameter + * was set to the previous value. This is our + * offset. + */ + TRACE1("Adjust samplePos: offset=%d, ", (int) offset); + TRACE2("transferedBytes=%d -> %d, ", + (int) info->transferedBytes, + (int) (info->transferedBytes - offset)); + TRACE2("positionOffset=%d -> %d\n", + (int) (info->positionOffset), + (int) (((int) info->positionOffset) + offset)); + info->transferedBytes -= offset; + info->positionOffset += offset; + } + } else { + ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n"); + } + } +} + +// returns -1 on error +int DAUDIO_Write(void* id, char* data, int byteSize) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = -1; + + TRACE1("> DAUDIO_Write %d bytes\n", byteSize); + if (info!=NULL) { + ret = write(info->fd, data, byteSize); + resetErrorFlagAndAdjustPosition(info, TRUE, ret); + /* sets ret to -1 if buffer full, no error! */ + if (ret < 0) { + ret = 0; + } + } + TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret); + return ret; +} + +// returns -1 on error +int DAUDIO_Read(void* id, char* data, int byteSize) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = -1; + + TRACE1("> DAUDIO_Read %d bytes\n", byteSize); + if (info != NULL) { + ret = read(info->fd, data, byteSize); + resetErrorFlagAndAdjustPosition(info, TRUE, ret); + /* sets ret to -1 if buffer full, no error! */ + if (ret < 0) { + ret = 0; + } + } + TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret); + return ret; +} + + +int DAUDIO_GetBufferSize(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + if (info) { + return info->bufferSizeInBytes; + } + return 0; +} + +int DAUDIO_StillDraining(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int ret = FALSE; + + if (info!=NULL) { + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + /* check error flag */ + AUDIO_INITINFO(&audioInfo); + ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + ret = (prinfo->error != 0)?FALSE:TRUE; + } + return ret; +} + + +int getDevicePosition(SolPcmInfo* info, int isSource) { + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int err; + + if (isSource) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + AUDIO_INITINFO(&audioInfo); + err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo); + if (err >= 0) { + /*TRACE2("---> device paused: %d eof=%d\n", + prinfo->pause, prinfo->eof); + */ + return (int) (prinfo->samples * info->frameSize); + } + ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n"); + return -1; +} + +int DAUDIO_Flush(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int err = -1; + int pos; + + TRACE0("DAUDIO_Flush\n"); + if (info) { + if (isSource) { + err = ioctl(info->fd, I_FLUSH, FLUSHW); + } else { + err = ioctl(info->fd, I_FLUSH, FLUSHR); + } + if (err >= 0) { + /* resets the transferedBytes parameter to + * the current samples count of the device + */ + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + info->transferedBytes = pos; + } + } + } + if (err < 0) { + ERROR0("ERROR in DAUDIO_Flush\n"); + } + return (err < 0)?FALSE:TRUE; +} + +int DAUDIO_GetAvailable(void* id, int isSource) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret = 0; + int pos; + + if (info) { + /* unfortunately, the STREAMS architecture + * seems to not have a method for querying + * the available bytes to read/write! + * estimate it... + */ + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + if (isSource) { + /* we usually have written more bytes + * to the queue than the device position should be + */ + ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos); + } else { + /* for record, the device stream should + * be usually ahead of our read actions + */ + ret = pos - info->transferedBytes; + } + if (ret > info->bufferSizeInBytes) { + ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n", + (int) ret, (int) info->bufferSizeInBytes); + ERROR2(" devicePos=%d, transferedBytes=%d\n", + (int) pos, (int) info->transferedBytes); + ret = info->bufferSizeInBytes; + } + else if (ret < 0) { + ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n", + (int) ret); + ERROR2(" devicePos=%d, transferedBytes=%d\n", + (int) pos, (int) info->transferedBytes); + ret = 0; + } + } + } + + TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret); + return ret; +} + +INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret; + int pos; + INT64 result = javaBytePos; + + if (info) { + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + result = info->positionOffset + pos; + } + } + + //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result); + return result; +} + + +void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) { + SolPcmInfo* info = (SolPcmInfo*) id; + int ret; + int pos; + + if (info) { + pos = getDevicePosition(info, isSource); + if (pos >= 0) { + info->positionOffset = javaBytePos - pos; + } + } +} + +int DAUDIO_RequiresServicing(void* id, int isSource) { + // never need servicing on Solaris + return FALSE; +} + +void DAUDIO_Service(void* id, int isSource) { + // never need servicing on Solaris +} + + +#endif // USE_DAUDIO diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c 2024-01-27 14:37:30.307358573 +0100 @@ -0,0 +1,600 @@ +/* + * Copyright (c) 2002, 2016, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +#define USE_ERROR +//#define USE_TRACE + +#include "Ports.h" +#include "PLATFORM_API_SolarisOS_Utils.h" + +#if USE_PORTS == TRUE + +#define MONITOR_GAIN_STRING "Monitor Gain" + +#define ALL_TARGET_PORT_COUNT 6 + +// define the following to not use audio_prinfo_t.mod_ports +#define SOLARIS7_COMPATIBLE + +// Solaris audio defines +static int targetPorts[ALL_TARGET_PORT_COUNT] = { + AUDIO_SPEAKER, + AUDIO_HEADPHONE, + AUDIO_LINE_OUT, + AUDIO_AUX1_OUT, + AUDIO_AUX2_OUT, + AUDIO_SPDIF_OUT +}; + +static char* targetPortNames[ALL_TARGET_PORT_COUNT] = { + "Speaker", + "Headphone", + "Line Out", + "AUX1 Out", + "AUX2 Out", + "SPDIF Out" +}; + +// defined in Ports.h +static int targetPortJavaSoundMapping[ALL_TARGET_PORT_COUNT] = { + PORT_DST_SPEAKER, + PORT_DST_HEADPHONE, + PORT_DST_LINE_OUT, + PORT_DST_UNKNOWN, + PORT_DST_UNKNOWN, + PORT_DST_UNKNOWN, +}; + +#define ALL_SOURCE_PORT_COUNT 7 + +// Solaris audio defines +static int sourcePorts[ALL_SOURCE_PORT_COUNT] = { + AUDIO_MICROPHONE, + AUDIO_LINE_IN, + AUDIO_CD, + AUDIO_AUX1_IN, + AUDIO_AUX2_IN, + AUDIO_SPDIF_IN, + AUDIO_CODEC_LOOPB_IN +}; + +static char* sourcePortNames[ALL_SOURCE_PORT_COUNT] = { + "Microphone In", + "Line In", + "Compact Disc In", + "AUX1 In", + "AUX2 In", + "SPDIF In", + "Internal Loopback" +}; + +// Ports.h defines +static int sourcePortJavaSoundMapping[ALL_SOURCE_PORT_COUNT] = { + PORT_SRC_MICROPHONE, + PORT_SRC_LINE_IN, + PORT_SRC_COMPACT_DISC, + PORT_SRC_UNKNOWN, + PORT_SRC_UNKNOWN, + PORT_SRC_UNKNOWN, + PORT_SRC_UNKNOWN +}; + +struct tag_PortControlID; + +typedef struct tag_PortInfo { + int fd; // file descriptor of the pseudo device + audio_info_t audioInfo; + // ports + int targetPortCount; + int sourcePortCount; + // indexes to sourcePorts/targetPorts + // contains first target ports, then source ports + int ports[ALL_TARGET_PORT_COUNT + ALL_SOURCE_PORT_COUNT]; + // controls + int maxControlCount; // upper bound of number of controls + int usedControlIDs; // number of items already filled in controlIDs + struct tag_PortControlID* controlIDs; // the control IDs themselves +} PortInfo; + +#define PORT_CONTROL_TYPE_PLAY 0x4000000 +#define PORT_CONTROL_TYPE_RECORD 0x8000000 +#define PORT_CONTROL_TYPE_SELECT_PORT 1 +#define PORT_CONTROL_TYPE_GAIN 2 +#define PORT_CONTROL_TYPE_BALANCE 3 +#define PORT_CONTROL_TYPE_MONITOR_GAIN 10 +#define PORT_CONTROL_TYPE_OUTPUT_MUTED 11 +#define PORT_CONTROL_TYPE_PLAYRECORD_MASK PORT_CONTROL_TYPE_PLAY | PORT_CONTROL_TYPE_RECORD +#define PORT_CONTROL_TYPE_MASK 0xFFFFFF + + +typedef struct tag_PortControlID { + PortInfo* portInfo; + INT32 controlType; // PORT_CONTROL_TYPE_XX + uint_t port; +} PortControlID; + + +///// implemented functions of Ports.h + +INT32 PORT_GetPortMixerCount() { + return (INT32) getAudioDeviceCount(); +} + + +INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) { + AudioDeviceDescription desc; + + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) { + strncpy(description->name, desc.name, PORT_STRING_LENGTH-1); + description->name[PORT_STRING_LENGTH-1] = 0; + strncpy(description->vendor, desc.vendor, PORT_STRING_LENGTH-1); + description->vendor[PORT_STRING_LENGTH-1] = 0; + strncpy(description->version, desc.version, PORT_STRING_LENGTH-1); + description->version[PORT_STRING_LENGTH-1] = 0; + /*strncpy(description->description, desc.description, PORT_STRING_LENGTH-1);*/ + strncpy(description->description, "Solaris Ports", PORT_STRING_LENGTH-1); + description->description[PORT_STRING_LENGTH-1] = 0; + return TRUE; + } + return FALSE; +} + + +void* PORT_Open(INT32 mixerIndex) { + PortInfo* info = NULL; + int fd = -1; + AudioDeviceDescription desc; + int success = FALSE; + + TRACE0("PORT_Open\n"); + if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) { + fd = open(desc.pathctl, O_RDWR); + } + if (fd < 0) { + ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex); + return NULL; + } + + info = (PortInfo*) malloc(sizeof(PortInfo)); + if (info != NULL) { + memset(info, 0, sizeof(PortInfo)); + info->fd = fd; + success = TRUE; + } + if (!success) { + if (fd >= 0) { + close(fd); + } + PORT_Close((void*) info); + info = NULL; + } + return info; +} + +void PORT_Close(void* id) { + TRACE0("PORT_Close\n"); + if (id != NULL) { + PortInfo* info = (PortInfo*) id; + if (info->fd >= 0) { + close(info->fd); + info->fd = -1; + } + if (info->controlIDs) { + free(info->controlIDs); + info->controlIDs = NULL; + } + free(info); + } +} + + + +INT32 PORT_GetPortCount(void* id) { + int ret = 0; + PortInfo* info = (PortInfo*) id; + if (info != NULL) { + if (!info->targetPortCount && !info->sourcePortCount) { + int i; + AUDIO_INITINFO(&info->audioInfo); + if (ioctl(info->fd, AUDIO_GETINFO, &info->audioInfo) >= 0) { + for (i = 0; i < ALL_TARGET_PORT_COUNT; i++) { + if (info->audioInfo.play.avail_ports & targetPorts[i]) { + info->ports[info->targetPortCount] = i; + info->targetPortCount++; + } +#ifdef SOLARIS7_COMPATIBLE + TRACE3("Target %d %s: avail=%d\n", i, targetPortNames[i], + info->audioInfo.play.avail_ports & targetPorts[i]); +#else + TRACE4("Target %d %s: avail=%d mod=%d\n", i, targetPortNames[i], + info->audioInfo.play.avail_ports & targetPorts[i], + info->audioInfo.play.mod_ports & targetPorts[i]); +#endif + } + for (i = 0; i < ALL_SOURCE_PORT_COUNT; i++) { + if (info->audioInfo.record.avail_ports & sourcePorts[i]) { + info->ports[info->targetPortCount + info->sourcePortCount] = i; + info->sourcePortCount++; + } +#ifdef SOLARIS7_COMPATIBLE + TRACE3("Source %d %s: avail=%d\n", i, sourcePortNames[i], + info->audioInfo.record.avail_ports & sourcePorts[i]); +#else + TRACE4("Source %d %s: avail=%d mod=%d\n", i, sourcePortNames[i], + info->audioInfo.record.avail_ports & sourcePorts[i], + info->audioInfo.record.mod_ports & sourcePorts[i]); +#endif + } + } + } + ret = info->targetPortCount + info->sourcePortCount; + } + return ret; +} + +int isSourcePort(PortInfo* info, INT32 portIndex) { + return (portIndex >= info->targetPortCount); +} + +INT32 PORT_GetPortType(void* id, INT32 portIndex) { + PortInfo* info = (PortInfo*) id; + if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { + if (isSourcePort(info, portIndex)) { + return sourcePortJavaSoundMapping[info->ports[portIndex]]; + } else { + return targetPortJavaSoundMapping[info->ports[portIndex]]; + } + } + return 0; +} + +// pre-condition: portIndex must have been verified! +char* getPortName(PortInfo* info, INT32 portIndex) { + char* ret = NULL; + + if (isSourcePort(info, portIndex)) { + ret = sourcePortNames[info->ports[portIndex]]; + } else { + ret = targetPortNames[info->ports[portIndex]]; + } + return ret; +} + +INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) { + PortInfo* info = (PortInfo*) id; + char* n; + + if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) { + n = getPortName(info, portIndex); + if (n) { + strncpy(name, n, len-1); + name[len-1] = 0; + return TRUE; + } + } + return FALSE; +} + +void createPortControl(PortInfo* info, PortControlCreator* creator, INT32 portIndex, + INT32 type, void** controlObjects, int* controlCount) { + PortControlID* controlID; + void* newControl = NULL; + int controlIndex; + char* jsType = NULL; + int isBoolean = FALSE; + + TRACE0(">createPortControl\n"); + + // fill the ControlID structure and add this control + if (info->usedControlIDs >= info->maxControlCount) { + ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount); + return; + } + controlID = &(info->controlIDs[info->usedControlIDs]); + controlID->portInfo = info; + controlID->controlType = type; + controlIndex = info->ports[portIndex]; + if (isSourcePort(info, portIndex)) { + controlID->port = sourcePorts[controlIndex]; + } else { + controlID->port = targetPorts[controlIndex]; + } + switch (type & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_SELECT_PORT: + jsType = CONTROL_TYPE_SELECT; isBoolean = TRUE; break; + case PORT_CONTROL_TYPE_GAIN: + jsType = CONTROL_TYPE_VOLUME; break; + case PORT_CONTROL_TYPE_BALANCE: + jsType = CONTROL_TYPE_BALANCE; break; + case PORT_CONTROL_TYPE_MONITOR_GAIN: + jsType = CONTROL_TYPE_VOLUME; break; + case PORT_CONTROL_TYPE_OUTPUT_MUTED: + jsType = CONTROL_TYPE_MUTE; isBoolean = TRUE; break; + } + if (isBoolean) { + TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n"); + newControl = (creator->newBooleanControl)(creator, controlID, jsType); + } + else if (jsType == CONTROL_TYPE_BALANCE) { + TRACE0(" PORT_CONTROL_TYPE_BALANCE\n"); + newControl = (creator->newFloatControl)(creator, controlID, jsType, + -1.0f, 1.0f, 2.0f / 65.0f, ""); + } else { + TRACE0(" PORT_CONTROL_TYPE_FLOAT\n"); + newControl = (creator->newFloatControl)(creator, controlID, jsType, + 0.0f, 1.0f, 1.0f / 256.0f, ""); + } + if (newControl) { + controlObjects[*controlCount] = newControl; + (*controlCount)++; + info->usedControlIDs++; + } + TRACE0("addCompoundControl %d controls\n", *controlCount); + if (*controlCount) { + // create compound control and add it to the vector + compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount); + if (compControl) { + TRACE1(" addCompoundControl: calling addControl %p\n", compControl); + (creator->addControl)(creator, compControl); + } + *controlCount = 0; + } + TRACE0("addAllControl\n"); + // go through all controls and add them to the vector + for (i = 0; i < *controlCount; i++) { + (creator->addControl)(creator, controlObjects[i]); + } + *controlCount = 0; + TRACE0("PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n", + id, portIndex, info->controlIDs, info->maxControlCount); + if ((portIndex >= 0) && (portIndex < portCount)) { + // if the memory isn't reserved for the control structures, allocate it + if (!info->controlIDs) { + int maxCount = 0; + TRACE0("getControl: allocate mem\n"); + // get a maximum number of controls: + // each port has a select, balance, and volume control. + maxCount = 3 * portCount; + // then there is monitorGain and outputMuted + maxCount += (2 * info->targetPortCount); + info->maxControlCount = maxCount; + info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount); + } + if (!isSourcePort(info, portIndex)) { + type = PORT_CONTROL_TYPE_PLAY; + // add master mute control + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_OUTPUT_MUTED, + controls, &controlCount); + addAllControls(info, creator, controls, &controlCount); +#ifdef SOLARIS7_COMPATIBLE + selectable = info->audioInfo.play.avail_ports & targetPorts[info->ports[portIndex]]; +#else + selectable = info->audioInfo.play.mod_ports & targetPorts[info->ports[portIndex]]; +#endif + } else { + type = PORT_CONTROL_TYPE_RECORD; +#ifdef SOLARIS7_COMPATIBLE + selectable = info->audioInfo.record.avail_ports & sourcePorts[info->ports[portIndex]]; +#else + selectable = info->audioInfo.record.mod_ports & sourcePorts[info->ports[portIndex]]; +#endif + } + // add a mixer strip with volume, ... + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_GAIN, + controls, &controlCount); + // ... balance, ... + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_BALANCE, + controls, &controlCount); + // ... and select control (if not always on)... + if (selectable) { + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_SELECT_PORT, + controls, &controlCount); + } + // ... packaged in a compound control. + addCompoundControl(info, creator, getPortName(info, portIndex), controls, &controlCount); + + if (type == PORT_CONTROL_TYPE_PLAY) { + // add a single strip for source ports with monitor gain + createPortControl(info, creator, portIndex, + type | PORT_CONTROL_TYPE_MONITOR_GAIN, + controls, &controlCount); + // also in a compound control + addCompoundControl(info, creator, MONITOR_GAIN_STRING, controls, &controlCount); + } + } + TRACE0("< PORT_getControls\n"); +} + +INT32 PORT_GetIntValue(void* controlIDV) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + + AUDIO_INITINFO(&audioInfo); + if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_SELECT_PORT: + return (prinfo->port & controlID->port)?TRUE:FALSE; + case PORT_CONTROL_TYPE_OUTPUT_MUTED: + return (audioInfo.output_muted)?TRUE:FALSE; + default: + ERROR1("PORT_GetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + } + } + ERROR0("PORT_GetIntValue: Could not ioctl!\n"); + return 0; +} + +void PORT_SetIntValue(void* controlIDV, INT32 value) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + int setPort; + + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_SELECT_PORT: + // first try to just add this port. if that fails, set ONLY to this port. + AUDIO_INITINFO(&audioInfo); + if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { + if (value) { + setPort = (prinfo->port | controlID->port); + } else { + setPort = (prinfo->port - controlID->port); + } + AUDIO_INITINFO(&audioInfo); + prinfo->port = setPort; + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + // didn't work. Either this line doesn't support to select several + // ports at once (e.g. record), or a real error + if (value) { + // set to ONLY this port (and disable any other currently selected ports) + AUDIO_INITINFO(&audioInfo); + prinfo->port = controlID->port; + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + ERROR2("Error setting output select port %d to port %d!\n", controlID->port, controlID->port); + } + } else { + // assume it's an error + ERROR2("Error setting output select port %d to port %d!\n", controlID->port, setPort); + } + } + break; + case PORT_CONTROL_TYPE_OUTPUT_MUTED: + AUDIO_INITINFO(&audioInfo); + audioInfo.output_muted = (value?TRUE:FALSE); + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + ERROR2("Error setting output muted on port %d to %d!\n", controlID->port, value); + } + break; + default: + ERROR1("PORT_SetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + } + } +} + +float PORT_GetFloatValue(void* controlIDV) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + + AUDIO_INITINFO(&audioInfo); + if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) { + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_GAIN: + return ((float) (prinfo->gain - AUDIO_MIN_GAIN)) + / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)); + case PORT_CONTROL_TYPE_BALANCE: + return ((float) ((prinfo->balance - AUDIO_LEFT_BALANCE - AUDIO_MID_BALANCE) << 1)) + / ((float) (AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE)); + case PORT_CONTROL_TYPE_MONITOR_GAIN: + return ((float) (audioInfo.monitor_gain - AUDIO_MIN_GAIN)) + / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN)); + default: + ERROR1("PORT_GetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + } + } + ERROR0("PORT_GetFloatValue: Could not ioctl!\n"); + return 0.0f; +} + +void PORT_SetFloatValue(void* controlIDV, float value) { + PortControlID* controlID = (PortControlID*) controlIDV; + audio_info_t audioInfo; + audio_prinfo_t* prinfo; + + AUDIO_INITINFO(&audioInfo); + + if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) { + prinfo = &(audioInfo.play); + } else { + prinfo = &(audioInfo.record); + } + switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) { + case PORT_CONTROL_TYPE_GAIN: + prinfo->gain = AUDIO_MIN_GAIN + + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f); + break; + case PORT_CONTROL_TYPE_BALANCE: + prinfo->balance = AUDIO_LEFT_BALANCE + AUDIO_MID_BALANCE + + ((int) (value * ((float) ((AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE) >> 1))) + 0.5f); + break; + case PORT_CONTROL_TYPE_MONITOR_GAIN: + audioInfo.monitor_gain = AUDIO_MIN_GAIN + + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f); + break; + default: + ERROR1("PORT_SetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK); + return; + } + if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) { + ERROR0("PORT_SetFloatValue: Could not ioctl!\n"); + } +} + +#endif // USE_PORTS diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c 2024-01-27 14:37:30.307640885 +0100 @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2002, 2007, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +#define USE_ERROR +#define USE_TRACE + +#include "PLATFORM_API_SolarisOS_Utils.h" + +#define MAX_AUDIO_DEVICES 20 + +// not thread safe... +static AudioDevicePath globalADPaths[MAX_AUDIO_DEVICES]; +static int globalADCount = -1; +static int globalADCacheTime = -1; +/* how many seconds do we cache devices */ +#define AD_CACHE_TIME 30 + +// return seconds +long getTimeInSeconds() { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec; +} + + +int getAudioDeviceCount() { + int count = MAX_AUDIO_DEVICES; + + getAudioDevices(globalADPaths, &count); + return count; +} + +/* returns TRUE if the path exists at all */ +int addAudioDevice(char* path, AudioDevicePath* adPath, int* count) { + int i; + int found = 0; + int fileExists = 0; + // not thread safe... + static struct stat statBuf; + + // get stats on the file + if (stat(path, &statBuf) == 0) { + // file exists. + fileExists = 1; + // If it is not yet in the adPath array, add it to the array + for (i = 0; i < *count; i++) { + if (adPath[i].st_ino == statBuf.st_ino + && adPath[i].st_dev == statBuf.st_dev) { + found = 1; + break; + } + } + if (!found) { + adPath[*count].st_ino = statBuf.st_ino; + adPath[*count].st_dev = statBuf.st_dev; + strncpy(adPath[*count].path, path, MAX_NAME_LENGTH); + adPath[*count].path[MAX_NAME_LENGTH - 1] = 0; + (*count)++; + TRACE1("Added audio device %s\n", path); + } + } + return fileExists; +} + + +void getAudioDevices(AudioDevicePath* adPath, int* count) { + int maxCount = *count; + char* audiodev; + char devsound[15]; + int i; + long timeInSeconds = getTimeInSeconds(); + + if (globalADCount < 0 + || (getTimeInSeconds() - globalADCacheTime) > AD_CACHE_TIME + || (adPath != globalADPaths)) { + *count = 0; + // first device, if set, is AUDIODEV variable + audiodev = getenv("AUDIODEV"); + if (audiodev != NULL && audiodev[0] != 0) { + addAudioDevice(audiodev, adPath, count); + } + // then try /dev/audio + addAudioDevice("/dev/audio", adPath, count); + // then go through all of the /dev/sound/? devices + for (i = 0; i < 100; i++) { + sprintf(devsound, "/dev/sound/%d", i); + if (!addAudioDevice(devsound, adPath, count)) { + break; + } + } + if (adPath == globalADPaths) { + /* commit cache */ + globalADCount = *count; + /* set cache time */ + globalADCacheTime = timeInSeconds; + } + } else { + /* return cache */ + *count = globalADCount; + } + // that's it +} + +int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames) { + int count = MAX_AUDIO_DEVICES; + int ret = 0; + + getAudioDevices(globalADPaths, &count); + if (index>=0 && index < count) { + ret = getAudioDeviceDescription(globalADPaths[index].path, adDesc, getNames); + } + return ret; +} + +int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames) { + int fd; + int mixerMode; + int len; + audio_info_t info; + audio_device_t deviceInfo; + + strncpy(adDesc->path, path, MAX_NAME_LENGTH); + adDesc->path[MAX_NAME_LENGTH] = 0; + strcpy(adDesc->pathctl, adDesc->path); + strcat(adDesc->pathctl, "ctl"); + strcpy(adDesc->name, adDesc->path); + adDesc->vendor[0] = 0; + adDesc->version[0] = 0; + adDesc->description[0] = 0; + adDesc->maxSimulLines = 1; + + // try to open the pseudo device and get more information + fd = open(adDesc->pathctl, O_WRONLY | O_NONBLOCK); + if (fd >= 0) { + close(fd); + if (getNames) { + fd = open(adDesc->pathctl, O_RDONLY); + if (fd >= 0) { + if (ioctl(fd, AUDIO_GETDEV, &deviceInfo) >= 0) { + strncpy(adDesc->vendor, deviceInfo.name, MAX_AUDIO_DEV_LEN); + adDesc->vendor[MAX_AUDIO_DEV_LEN] = 0; + strncpy(adDesc->version, deviceInfo.version, MAX_AUDIO_DEV_LEN); + adDesc->version[MAX_AUDIO_DEV_LEN] = 0; + /* add config string to the dev name + * creates a string like "/dev/audio (onboard1)" + */ + len = strlen(adDesc->name) + 1; + if (MAX_NAME_LENGTH - len > 3) { + strcat(adDesc->name, " ("); + strncat(adDesc->name, deviceInfo.config, MAX_NAME_LENGTH - len); + strcat(adDesc->name, ")"); + } + adDesc->name[MAX_NAME_LENGTH-1] = 0; + } + if (ioctl(fd, AUDIO_MIXERCTL_GET_MODE, &mixerMode) >= 0) { + if (mixerMode == AM_MIXER_MODE) { + TRACE1(" getAudioDeviceDescription: %s is in mixer mode\n", adDesc->path); + adDesc->maxSimulLines = -1; + } + } else { + ERROR1("ioctl AUDIO_MIXERCTL_GET_MODE failed on %s!\n", adDesc->path); + } + close(fd); + } else { + ERROR1("could not open %s!\n", adDesc->pathctl); + } + } + return 1; + } + return 0; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h 2024-01-27 14:37:30.307877338 +0100 @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2002, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 +#include +#include +#include +/* does not work on Solaris 2.7 */ +#include +#include +#include +#ifndef __linux__ +#include +#endif +#include +#include +#include + +#ifndef PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED +#define PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED + +/* defines for Solaris 2.7 + #ifndef AUDIO_AUX1_OUT + #define AUDIO_AUX1_OUT (0x08) // output to aux1 out + #define AUDIO_AUX2_OUT (0x10) // output to aux2 out + #define AUDIO_SPDIF_OUT (0x20) // output to SPDIF port + #define AUDIO_AUX1_IN (0x08) // input from aux1 in + #define AUDIO_AUX2_IN (0x10) // input from aux2 in + #define AUDIO_SPDIF_IN (0x20) // input from SPDIF port + #endif +*/ + +/* input from Codec inter. loopback */ +#ifndef AUDIO_CODEC_LOOPB_IN +#define AUDIO_CODEC_LOOPB_IN (0x40) +#endif + + +#define MAX_NAME_LENGTH 300 + +typedef struct tag_AudioDevicePath { + char path[MAX_NAME_LENGTH]; + ino_t st_ino; // inode number to detect duplicate devices + dev_t st_dev; // device ID to detect duplicate audio devices +} AudioDevicePath; + +typedef struct tag_AudioDeviceDescription { + INT32 maxSimulLines; + char path[MAX_NAME_LENGTH+1]; + char pathctl[MAX_NAME_LENGTH+4]; + char name[MAX_NAME_LENGTH+1]; + char vendor[MAX_NAME_LENGTH+1]; + char version[MAX_NAME_LENGTH+1]; + char description[MAX_NAME_LENGTH+1]; +} AudioDeviceDescription; + +int getAudioDeviceCount(); + +/* + * adPath is an array of AudioDevicePath structures + * count contains initially the number of elements in adPath + * and will be set to the returned number of paths. + */ +void getAudioDevices(AudioDevicePath* adPath, int* count); + +/* + * fills adDesc from the audio device given in path + * returns 0 if an error occurred + * if getNames is 0, only path and pathctl are filled + */ +int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames); +int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames); + + +#endif // PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/awt/X11FontManager.java jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/awt/X11FontManager.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/awt/X11FontManager.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/awt/X11FontManager.java 2024-01-27 14:37:30.268323825 +0100 @@ -686,7 +686,8 @@ * and do the best we can. */ FontConfiguration mFontConfig = new MFontConfiguration(this); - if ((FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile())) { + if ((FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile()) || + (FontUtilities.isSolaris && !mFontConfig.fontFilesArePresent())) { FcFontConfiguration fcFontConfig = new FcFontConfiguration(this); if (fcFontConfig.init()) { diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java 2024-01-27 14:37:30.268901108 +0100 @@ -68,7 +68,59 @@ */ protected void initReorderMap() { reorderMap = new HashMap<>(); + if (osName == null) { /* null means SunOS */ + initReorderMapForSolaris(); + } else { + initReorderMapForLinux(); + } + } + + private void initReorderMapForSolaris() { + /* Don't create a no-op entry, so we can optimize this case + * i.e. we don't need to do anything so can avoid slower paths in + * the code. + */ +// reorderMap.put("UTF-8", "latin-1"); + reorderMap.put("UTF-8.hi", "devanagari"); // NB is in Lucida. + reorderMap.put("UTF-8.ja", + new String[] {"japanese-x0201", "japanese-x0208", "japanese-x0212"}); + reorderMap.put("UTF-8.ko", "korean-johab"); + reorderMap.put("UTF-8.th", "thai"); + reorderMap.put("UTF-8.zh.TW", "chinese-big5"); + reorderMap.put("UTF-8.zh.HK", new String[] {"chinese-big5", "chinese-hkscs"}); + reorderMap.put("UTF-8.zh.CN", + new String[] {"chinese-gb18030-0", "chinese-gb18030-1"}); + reorderMap.put("UTF-8.zh", + new String[] {"chinese-big5", "chinese-hkscs", "chinese-gb18030-0,chinese-gb18030-1"}); + reorderMap.put("Big5", "chinese-big5"); + reorderMap.put("Big5-HKSCS", new String[] {"chinese-big5", "chinese-hkscs"}); + reorderMap.put("GB2312", new String[] {"chinese-gbk", "chinese-gb2312"}); + reorderMap.put("x-EUC-TW", + new String[] {"chinese-cns11643-1", "chinese-cns11643-2", "chinese-cns11643-3"}); + reorderMap.put("GBK", "chinese-gbk"); + reorderMap.put("GB18030",new String[] {"chinese-gb18030-0", "chinese-gb18030-1"}); + + reorderMap.put("TIS-620", "thai"); + reorderMap.put("x-PCK", + new String[] {"japanese-x0201", "japanese-x0208", "japanese-x0212"}); + reorderMap.put("x-eucJP-Open", + new String[] {"japanese-x0201", "japanese-x0208", "japanese-x0212"}); + reorderMap.put("EUC-KR", "korean"); + /* Don't create a no-op entry, so we can optimize this case */ +// reorderMap.put("ISO-8859-1", "latin-1"); + reorderMap.put("ISO-8859-2", "latin-2"); + reorderMap.put("ISO-8859-5", "cyrillic-iso8859-5"); + reorderMap.put("windows-1251", "cyrillic-cp1251"); + reorderMap.put("KOI8-R", "cyrillic-koi8-r"); + reorderMap.put("ISO-8859-6", "arabic"); + reorderMap.put("ISO-8859-7", "greek"); + reorderMap.put("ISO-8859-8", "hebrew"); + reorderMap.put("ISO-8859-9", "latin-5"); + reorderMap.put("ISO-8859-13", "latin-7"); + reorderMap.put("ISO-8859-15", "latin-9"); + } + private void initReorderMapForLinux() { reorderMap.put("UTF-8.ja.JP", "japanese-iso10646"); reorderMap.put("UTF-8.ko.KR", "korean-iso10646"); reorderMap.put("UTF-8.zh.TW", "chinese-tw-iso10646"); @@ -78,7 +130,12 @@ reorderMap.put("GB2312", "chinese-gb18030"); reorderMap.put("Big5", "chinese-big5"); reorderMap.put("EUC-KR", "korean"); - reorderMap.put("GB18030", "chinese-gb18030"); + if (osName.equals("Sun")){ + reorderMap.put("GB18030", "chinese-cn-iso10646"); + } + else { + reorderMap.put("GB18030", "chinese-gb18030"); + } } /** @@ -87,7 +144,10 @@ protected void setOsNameAndVersion(){ super.setOsNameAndVersion(); - if (osName.equals("Linux")) { + if (osName.equals("SunOS")) { + //don't care os name on Solaris + osName = null; + } else if (osName.equals("Linux")) { try { File f; if ((f = new File("/etc/fedora-release")).canRead()) { diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java 2024-01-27 14:37:30.269567104 +0100 @@ -150,6 +150,10 @@ return OSInfo.getOSType() == OSInfo.OSType.MACOSX; } + static boolean isSysV() { + return OSInfo.getOSType() == OSInfo.OSType.SOLARIS; + } + static boolean isLinux() { return OSInfo.getOSType() == OSInfo.OSType.LINUX; } @@ -301,7 +305,7 @@ } } } else { - if (isMac()) { + if (isMac() || isSysV()) { printers = getAllPrinterNamesSysV(); } else if (isAIX()) { printers = getAllPrinterNamesAIX(); @@ -485,7 +489,7 @@ } /* fallback if nothing not having a printer at this point */ PrintService printer = null; - if (isMac()) { + if (isMac() || isSysV()) { printer = getNamedPrinterNameSysV(name); } else if (isAIX()) { printer = getNamedPrinterNameAIX(name); @@ -656,7 +660,7 @@ psuri = printerInfo[1]; } } else { - if (isMac()) { + if (isMac() || isSysV()) { defaultPrinter = getDefaultPrinterNameSysV(); } else if (isAIX()) { defaultPrinter = getDefaultPrinterNameAIX(); @@ -876,7 +880,7 @@ ArrayList results = null; try { final String[] cmd = new String[3]; - if (isAIX()) { + if (isSysV() || isAIX()) { cmd[0] = "/usr/bin/sh"; cmd[1] = "-c"; cmd[2] = "env LC_ALL=C " + command; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java 2024-01-27 14:37:30.270511950 +0100 @@ -872,25 +872,51 @@ isAttributeCategorySupported(JobSheets.class)) { ncomps+=1; } - execCmd = new String[ncomps]; - execCmd[n++] = "/usr/bin/lpr"; - if ((pFlags & PRINTER) != 0) { - execCmd[n++] = "-P" + printer; - } - if ((pFlags & JOBTITLE) != 0) { - execCmd[n++] = "-J " + jobTitle; - } - if ((pFlags & COPIES) != 0) { - execCmd[n++] = "-#" + copies; - } - if ((pFlags & NOSHEET) != 0) { - execCmd[n++] = "-h"; - } else if (getPrintService(). - isAttributeCategorySupported(JobSheets.class)) { - execCmd[n++] = "-o job-sheets=standard"; - } - if ((pFlags & OPTIONS) != 0) { - execCmd[n++] = "-o" + options; + if (PrintServiceLookupProvider.isSysV()) { + ncomps+=1; // lp uses 1 more arg than lpr (make a copy) + execCmd = new String[ncomps]; + execCmd[n++] = "/usr/bin/lp"; + execCmd[n++] = "-c"; // make a copy of the spool file + if ((pFlags & PRINTER) != 0) { + execCmd[n++] = "-d" + printer; + } + if ((pFlags & JOBTITLE) != 0) { + String quoteChar = "\""; + execCmd[n++] = "-t " + quoteChar+jobTitle+quoteChar; + } + if ((pFlags & COPIES) != 0) { + execCmd[n++] = "-n " + copies; + } + if ((pFlags & NOSHEET) != 0) { + execCmd[n++] = "-o nobanner"; + } else if (getPrintService(). + isAttributeCategorySupported(JobSheets.class)) { + execCmd[n++] = "-o job-sheets=standard"; + } + if ((pFlags & OPTIONS) != 0) { + execCmd[n++] = "-o " + options; + } + } else { + execCmd = new String[ncomps]; + execCmd[n++] = "/usr/bin/lpr"; + if ((pFlags & PRINTER) != 0) { + execCmd[n++] = "-P" + printer; + } + if ((pFlags & JOBTITLE) != 0) { + execCmd[n++] = "-J " + jobTitle; + } + if ((pFlags & COPIES) != 0) { + execCmd[n++] = "-#" + copies; + } + if ((pFlags & NOSHEET) != 0) { + execCmd[n++] = "-h"; + } else if (getPrintService(). + isAttributeCategorySupported(JobSheets.class)) { + execCmd[n++] = "-o job-sheets=standard"; + } + if ((pFlags & OPTIONS) != 0) { + execCmd[n++] = "-o" + options; + } } execCmd[n++] = spoolFile; if (IPPPrintService.debugPrint) { diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintService.java jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/print/UnixPrintService.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintService.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/classes/sun/print/UnixPrintService.java 2024-01-27 14:37:30.271195909 +0100 @@ -220,6 +220,31 @@ return name; } + private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsSysV() { + String command = "/usr/bin/lpstat -a " + printer; + String[] results= PrintServiceLookupProvider.execCmd(command); + + if (results != null && results.length > 0) { + if (results[0].startsWith(printer + " accepting requests")) { + return PrinterIsAcceptingJobs.ACCEPTING_JOBS; + } + else if (results[0].startsWith(printer)) { + /* As well as "myprinter accepting requests", look for + * "myprinter@somehost accepting requests". + */ + int index = printer.length(); + String str = results[0]; + if (str.length() > index && + str.charAt(index) == '@' && + str.indexOf(" accepting requests", index) > 0 && + str.indexOf(" not accepting requests", index) == -1) { + return PrinterIsAcceptingJobs.ACCEPTING_JOBS; + } + } + } + return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS ; + } + private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsBSD() { if (PrintServiceLookupProvider.cmdIndex == PrintServiceLookupProvider.UNINITIALIZED) { @@ -297,7 +322,9 @@ } private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() { - if (PrintServiceLookupProvider.isBSD()) { + if (PrintServiceLookupProvider.isSysV()) { + return getPrinterIsAcceptingJobsSysV(); + } else if (PrintServiceLookupProvider.isBSD()) { return getPrinterIsAcceptingJobsBSD(); } else if (PrintServiceLookupProvider.isAIX()) { return getPrinterIsAcceptingJobsAIX(); @@ -324,6 +351,14 @@ } } + private QueuedJobCount getQueuedJobCountSysV() { + String command = "/usr/bin/lpstat -R " + printer; + String[] results= PrintServiceLookupProvider.execCmd(command); + int qlen = (results == null) ? 0 : results.length; + + return new QueuedJobCount(qlen); + } + private QueuedJobCount getQueuedJobCountBSD() { if (PrintServiceLookupProvider.cmdIndex == PrintServiceLookupProvider.UNINITIALIZED) { @@ -380,7 +415,9 @@ } private QueuedJobCount getQueuedJobCount() { - if (PrintServiceLookupProvider.isBSD()) { + if (PrintServiceLookupProvider.isSysV()) { + return getQueuedJobCountSysV(); + } else if (PrintServiceLookupProvider.isBSD()) { return getQueuedJobCountBSD(); } else if (PrintServiceLookupProvider.isAIX()) { return getQueuedJobCountAIX(); @@ -389,6 +426,13 @@ } } + private PrintServiceAttributeSet getSysVServiceAttributes() { + PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet(); + attrs.add(getQueuedJobCountSysV()); + attrs.add(getPrinterIsAcceptingJobsSysV()); + return attrs; + } + private PrintServiceAttributeSet getBSDServiceAttributes() { PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet(); attrs.add(getQueuedJobCountBSD()); @@ -427,7 +471,9 @@ } private PrintServiceAttributeSet getDynamicAttributes() { - if (PrintServiceLookupProvider.isAIX()) { + if (PrintServiceLookupProvider.isSysV()) { + return getSysVServiceAttributes(); + } else if (PrintServiceLookupProvider.isAIX()) { return getAIXServiceAttributes(); } else { return getBSDServiceAttributes(); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/native/common/awt/fontpath.c jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/native/common/awt/fontpath.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/native/common/awt/fontpath.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/native/common/awt/fontpath.c 2024-01-27 14:37:30.271841656 +0100 @@ -57,7 +57,57 @@ #define MAXFDIRS 512 /* Max number of directories that contain fonts */ -#if defined( __linux__) +#if defined(__solaris__) +/* + * This can be set in the makefile to "/usr/X11" if so desired. + */ +#ifndef OPENWINHOMELIB +#define OPENWINHOMELIB "/usr/openwin/lib/" +#endif + +/* This is all known Solaris X11 directories on Solaris 8, 9 and 10. + * It is ordered to give precedence to TrueType directories. + * It is needed if fontconfig is not installed or configured properly. + */ +static char *fullSolarisFontPath[] = { + OPENWINHOMELIB "X11/fonts/TrueType", + OPENWINHOMELIB "locale/euro_fonts/X11/fonts/TrueType", + OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/TrueType", + OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/TrueType", + OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/TrueType", + OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/TrueType", + OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/TrueType", + OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/TrueType", + OPENWINHOMELIB "locale/iso_8859_15/X11/fonts/TrueType", + OPENWINHOMELIB "locale/ar/X11/fonts/TrueType", + OPENWINHOMELIB "locale/hi_IN.UTF-8/X11/fonts/TrueType", + OPENWINHOMELIB "locale/ja/X11/fonts/TT", + OPENWINHOMELIB "locale/ko/X11/fonts/TrueType", + OPENWINHOMELIB "locale/ko.UTF-8/X11/fonts/TrueType", + OPENWINHOMELIB "locale/KOI8-R/X11/fonts/TrueType", + OPENWINHOMELIB "locale/ru.ansi-1251/X11/fonts/TrueType", + OPENWINHOMELIB "locale/th_TH/X11/fonts/TrueType", + OPENWINHOMELIB "locale/zh_TW/X11/fonts/TrueType", + OPENWINHOMELIB "locale/zh_TW.BIG5/X11/fonts/TT", + OPENWINHOMELIB "locale/zh_HK.BIG5HK/X11/fonts/TT", + OPENWINHOMELIB "locale/zh_CN.GB18030/X11/fonts/TrueType", + OPENWINHOMELIB "locale/zh/X11/fonts/TrueType", + OPENWINHOMELIB "locale/zh.GBK/X11/fonts/TrueType", + OPENWINHOMELIB "X11/fonts/Type1", + OPENWINHOMELIB "X11/fonts/Type1/sun", + OPENWINHOMELIB "X11/fonts/Type1/sun/outline", + OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/Type1", + OPENWINHOMELIB "locale/iso_8859_4/X11/fonts/Type1", + OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/Type1", + OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/Type1", + OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/Type1", + OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/Type1", + OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/Type1", + OPENWINHOMELIB "locale/ar/X11/fonts/Type1", + NULL, /* terminates the list */ +}; + +#elif defined( __linux__) /* All the known interesting locations we have discovered on * various flavors of Linux */ @@ -173,6 +223,14 @@ if (strstr(x11Path[i], ".gnome") != NULL) { continue; } +#ifdef __solaris__ + if (strstr(x11Path[i], "/F3/") != NULL) { + continue; + } + if (strstr(x11Path[i], "bitmap") != NULL) { + continue; + } +#endif fontdirs[pos] = strdup(x11Path[i]); slen = strlen(fontdirs[pos]); if (slen > 0 && fontdirs[pos][slen-1] == '/') { @@ -322,6 +380,8 @@ #if defined(__linux__) knowndirs = fullLinuxFontPath; +#elif defined(__solaris__) + knowndirs = fullSolarisFontPath; #elif defined(_AIX) knowndirs = fullAixFontPath; #endif diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c 2024-01-27 14:37:30.272488211 +0100 @@ -402,7 +402,12 @@ xrenderLibHandle = dlopen("libXrender.so", RTLD_LAZY | RTLD_GLOBAL); } -#if defined(_AIX) +#if defined(__solaris__) + if (xrenderLibHandle == NULL) { + xrenderLibHandle = dlopen("libXrender.so.1", + RTLD_LAZY | RTLD_GLOBAL); + } +#elif defined(_AIX) if (xrenderLibHandle == NULL) { xrenderLibHandle = dlopen("libXrender.a(libXrender.so.0)", RTLD_MEMBER | RTLD_LAZY | RTLD_GLOBAL); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c --- jdk21u-jdk-21.0.2-ga.orig/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c 2024-01-27 14:37:30.273146556 +0100 @@ -61,6 +61,29 @@ #include +#if defined(__solaris__) +/* Solaris 10 will not have these symbols at compile time */ + +typedef Picture (*XRenderCreateLinearGradientFuncType) + (Display *dpy, + const XLinearGradient *gradient, + const XFixed *stops, + const XRenderColor *colors, + int nstops); + +typedef Picture (*XRenderCreateRadialGradientFuncType) + (Display *dpy, + const XRadialGradient *gradient, + const XFixed *stops, + const XRenderColor *colors, + int nstops); + +static +XRenderCreateLinearGradientFuncType XRenderCreateLinearGradientFunc = NULL; +static + XRenderCreateRadialGradientFuncType XRenderCreateRadialGradientFunc = NULL; +#endif + #define BUILD_TRANSFORM_MATRIX(TRANSFORM, M00, M01, M02, M10, M11, M12) \ { \ TRANSFORM.matrix[0][0] = M00; \ @@ -128,6 +151,27 @@ } else { available = JNI_FALSE; } +#elif defined(__solaris__) + xrenderlib = dlopen("libXrender.so",RTLD_GLOBAL|RTLD_LAZY); + if (xrenderlib != NULL) { + + XRenderCreateLinearGradientFunc = + (XRenderCreateLinearGradientFuncType) + dlsym(xrenderlib, "XRenderCreateLinearGradient"); + + XRenderCreateRadialGradientFunc = + (XRenderCreateRadialGradientFuncType) + dlsym(xrenderlib, "XRenderCreateRadialGradient"); + + if (XRenderCreateLinearGradientFunc == NULL || + XRenderCreateRadialGradientFunc == NULL) + { + available = JNI_FALSE; + } + dlclose(xrenderlib); + } else { + available = JNI_FALSE; + } #else Dl_info info; jboolean versionInfoIsFound = JNI_FALSE; @@ -534,7 +578,13 @@ colors[i].green = pixels[i*4 + 2]; colors[i].blue = pixels[i*4 + 3]; } +#ifdef __solaris__ + if (XRenderCreateLinearGradientFunc!=NULL) { + gradient = (*XRenderCreateLinearGradientFunc)(awt_display, &grad, stops, colors, numStops); + } +#else gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops); +#endif free(colors); free(stops); @@ -612,7 +662,13 @@ colors[i].green = pixels[i*4 + 2]; colors[i].blue = pixels[i*4 + 3]; } +#ifdef __solaris__ + if (XRenderCreateRadialGradientFunc != NULL) { + gradient = (jint) (*XRenderCreateRadialGradientFunc)(awt_display, &grad, stops, colors, numStops); + } +#else gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops); +#endif free(colors); free(stops); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java jdk21u-jdk-21.0.2-ga/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java 2024-01-27 14:37:30.273579611 +0100 @@ -91,6 +91,9 @@ = System.getProperty("sun.security.jgss.lib"); if (defaultLib == null || defaultLib.trim().equals("")) { gssLibs = switch (OperatingSystem.current()) { + case SOLARIS -> new String[]{ + "libgss.so", + }; case LINUX -> new String[]{ "libgssapi.so", "libgssapi_krb5.so", diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/Config.java jdk21u-jdk-21.0.2-ga/src/java.security.jgss/share/classes/sun/security/krb5/Config.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/Config.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.security.jgss/share/classes/sun/security/krb5/Config.java 2024-01-27 14:37:30.274195091 +0100 @@ -931,6 +931,8 @@ if (name == null) { name = "c:\\winnt\\krb5.ini"; } + } else if (OperatingSystem.isSolaris()) { + name = "/etc/krb5/krb5.conf"; } else if (OperatingSystem.isMacOS()) { name = findMacosConfigFile(); } else { diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java jdk21u-jdk-21.0.2-ga/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java 2024-01-27 14:37:30.274635861 +0100 @@ -107,7 +107,7 @@ private static long uid; static { - // Available on Linux and Mac. Otherwise, -1 and no _euid suffix + // Available on Solaris, Linux and Mac. Otherwise, -1 and no _euid suffix uid = jdk.internal.misc.VM.geteuid(); } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java jdk21u-jdk-21.0.2-ga/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java 2024-01-27 14:37:30.275020167 +0100 @@ -82,8 +82,12 @@ String s2 = lib.substring(k + 7); String libDir; if ("64".equals(System.getProperty("sun.arch.data.model"))) { - // assume Linux convention - libDir = "lib64"; + if ("SunOS".equals(System.getProperty("os.name"))) { + libDir = "lib/64"; + } else { + // assume Linux convention + libDir = "lib64"; + } } else { // must be 32-bit libDir = "lib"; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java jdk21u-jdk-21.0.2-ga/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java --- jdk21u-jdk-21.0.2-ga.orig/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java 2024-01-27 14:37:30.275494206 +0100 @@ -33,12 +33,21 @@ private static final int KB = 1024; private static int BUFFER_SIZE = 4 * KB; + static { + // Set a larger buffer size for Solaris + final String osName = SecuritySupport.getSystemProperty("os.name"); + if (osName.equalsIgnoreCase("solaris")) { + BUFFER_SIZE = 32 * KB; + } + } + private Writer _writer; /** * Initializes a WriterOutputBuffer by creating an instance of a * BufferedWriter. The size of the buffer in this writer may have - * a significant impact on throughput. + * a significant impact on throughput. Solaris prefers a larger + * buffer, while Linux works better with a smaller one. */ public WriterOutputBuffer(Writer writer) { _writer = new BufferedWriter(writer, BUFFER_SIZE); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java jdk21u-jdk-21.0.2-ga/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java 2024-01-27 14:37:30.308317671 +0100 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2005, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package sun.tools.attach; + +import com.sun.tools.attach.VirtualMachine; +import com.sun.tools.attach.VirtualMachineDescriptor; +import com.sun.tools.attach.AttachNotSupportedException; +import java.io.IOException; + +/* + * An AttachProvider implementation for Solaris that use the doors + * interface to the VM. + */ +public class AttachProviderImpl extends HotSpotAttachProvider { + + public AttachProviderImpl() { + } + + public String name() { + return "sun"; + } + + public String type() { + return "doors"; + } + + public VirtualMachine attachVirtualMachine(String vmid) + throws AttachNotSupportedException, IOException + { + checkAttachPermission(); + + // AttachNotSupportedException will be thrown if the target VM can be determined + // to be not attachable. + testAttachable(vmid); + + return new VirtualMachineImpl(this, vmid); + } + + public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd) + throws AttachNotSupportedException, IOException + { + if (vmd.provider() != this) { + throw new AttachNotSupportedException("provider mismatch"); + } + // To avoid re-checking if the VM if attachable, we check if the descriptor + // is for a hotspot VM - these descriptors are created by the listVirtualMachines + // implementation which only returns a list of attachable VMs. + if (vmd instanceof HotSpotVirtualMachineDescriptor) { + assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable(); + checkAttachPermission(); + return new VirtualMachineImpl(this, vmd.id()); + } else { + return attachVirtualMachine(vmd.id()); + } + } + +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java jdk21u-jdk-21.0.2-ga/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java 2024-01-27 14:37:30.308642750 +0100 @@ -0,0 +1,272 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ +package sun.tools.attach; + +import com.sun.tools.attach.AttachOperationFailedException; +import com.sun.tools.attach.AgentLoadException; +import com.sun.tools.attach.AttachNotSupportedException; +import com.sun.tools.attach.spi.AttachProvider; + +import java.io.InputStream; +import java.io.IOException; +import java.io.File; +import java.io.FileNotFoundException; + +/* + * Solaris implementation of HotSpotVirtualMachine. + */ +public class VirtualMachineImpl extends HotSpotVirtualMachine { + // "/tmp" is used as a global well-known location for the files + // .java_pid. and .attach_pid. It is important that this + // location is the same for all processes, otherwise the tools + // will not be able to find all Hotspot processes. + // Any changes to this needs to be synchronized with HotSpot. + private static final String tmpdir = "/tmp"; + + // door descriptor; + private int fd = -1; + String socket_path; + + /** + * Attaches to the target VM + */ + VirtualMachineImpl(AttachProvider provider, String vmid) + throws AttachNotSupportedException, IOException + { + super(provider, vmid); + // This provider only understands process-ids (pids). + int pid; + try { + pid = Integer.parseInt(vmid); + if (pid < 1) { + throw new NumberFormatException(); + } + } catch (NumberFormatException x) { + throw new AttachNotSupportedException("Invalid process identifier: " + vmid); + } + + // Opens the door file to the target VM. If the file is not + // found it might mean that the attach mechanism isn't started in the + // target VM so we attempt to start it and retry. + try { + fd = openDoor(pid); + } catch (FileNotFoundException fnf1) { + File f = createAttachFile(pid); + try { + sigquit(pid); + + // give the target VM time to start the attach mechanism + final int delay_step = 100; + final long timeout = attachTimeout(); + long time_spend = 0; + long delay = 0; + do { + // Increase timeout on each attempt to reduce polling + delay += delay_step; + try { + Thread.sleep(delay); + } catch (InterruptedException x) { } + try { + fd = openDoor(pid); + } catch (FileNotFoundException fnf2) { + // pass + } + + time_spend += delay; + if (time_spend > timeout/2 && fd == -1) { + // Send QUIT again to give target VM the last chance to react + sigquit(pid); + } + } while (time_spend <= timeout && fd == -1); + if (fd == -1) { + throw new AttachNotSupportedException( + String.format("Unable to open door %s: " + + "target process %d doesn't respond within %dms " + + "or HotSpot VM not loaded", socket_path, pid, time_spend)); + } + } finally { + f.delete(); + } + } + assert fd >= 0; + } + + /** + * Detach from the target VM + */ + public void detach() throws IOException { + synchronized (this) { + if (fd != -1) { + close(fd); + fd = -1; + } + } + } + + /** + * Execute the given command in the target VM. + */ + InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException { + assert args.length <= 3; // includes null + + // first check that we are still attached + int door; + synchronized (this) { + if (fd == -1) { + throw new IOException("Detached from target VM"); + } + door = fd; + } + + // enqueue the command via a door call + int s = enqueue(door, cmd, args); + assert s >= 0; // valid file descriptor + + // The door call returns a file descriptor (one end of a socket pair). + // Create an input stream around it. + SocketInputStream sis = new SocketInputStream(s); + + // Read the command completion status + int completionStatus; + try { + completionStatus = readInt(sis); + } catch (IOException ioe) { + sis.close(); + throw ioe; + } + + // If non-0 it means an error but we need to special-case the + // "load" command to ensure that the right exception is thrown. + if (completionStatus != 0) { + // read from the stream and use that as the error message + String message = readErrorMessage(sis); + sis.close(); + if (cmd.equals("load")) { + String msg = "Failed to load agent library"; + if (!message.isEmpty()) + msg += ": " + message; + throw new AgentLoadException(msg); + } else { + if (message.isEmpty()) + message = "Command failed in target VM"; + throw new AttachOperationFailedException(message); + } + } + + // Return the input stream so that the command output can be read + return sis; + } + + // InputStream over a socket + private class SocketInputStream extends InputStream { + int s; + + public SocketInputStream(int s) { + this.s = s; + } + + public synchronized int read() throws IOException { + byte b[] = new byte[1]; + int n = this.read(b, 0, 1); + if (n == 1) { + return b[0] & 0xff; + } else { + return -1; + } + } + + public synchronized int read(byte[] bs, int off, int len) throws IOException { + if ((off < 0) || (off > bs.length) || (len < 0) || + ((off + len) > bs.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) + return 0; + + return VirtualMachineImpl.read(s, bs, off, len); + } + + public synchronized void close() throws IOException { + if (s != -1) { + int toClose = s; + s = -1; + VirtualMachineImpl.close(toClose); + } + } + } + + // The door is attached to .java_pid in the temporary directory. + private int openDoor(int pid) throws IOException { + socket_path = tmpdir + "/.java_pid" + pid; + fd = open(socket_path); + + // Check that the file owner/permission to avoid attaching to + // bogus process + try { + checkPermissions(socket_path); + } catch (IOException ioe) { + close(fd); + throw ioe; + } + return fd; + } + + // On Solaris a simple handshake is used to start the attach mechanism + // if not already started. The client creates a .attach_pid file in the + // target VM's working directory (or temporary directory), and the SIGQUIT + // handler checks for the file. + private File createAttachFile(int pid) throws IOException { + String fn = ".attach_pid" + pid; + String path = "/proc/" + pid + "/cwd/" + fn; + File f = new File(path); + try { + f = f.getCanonicalFile(); + f.createNewFile(); + } catch (IOException x) { + f = new File(tmpdir, fn); + f.createNewFile(); + } + return f; + } + + //-- native methods + + static native int open(String path) throws IOException; + + static native void close(int fd) throws IOException; + + static native int read(int fd, byte buf[], int off, int buflen) throws IOException; + + static native void checkPermissions(String path) throws IOException; + + static native void sigquit(int pid) throws IOException; + + // enqueue a command (and arguments) to the given door + static native int enqueue(int fd, String cmd, Object ... args) + throws IOException; + + static { + System.loadLibrary("attach"); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c jdk21u-jdk-21.0.2-ga/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c 2024-01-27 14:37:30.309075251 +0100 @@ -0,0 +1,389 @@ +/* + * Copyright (c) 2005, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 "jni_util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sun_tools_attach_VirtualMachineImpl.h" + +#define ROOT_UID 0 + +#define RESTARTABLE(_cmd, _result) do { \ + do { \ + _result = _cmd; \ + } while((_result == -1) && (errno == EINTR)); \ +} while(0) + +/* + * Declare library specific JNI_Onload entry if static build + */ +DEF_STATIC_JNI_OnLoad + +/* + * Class: sun_tools_attach_VirtualMachineImpl + * Method: open + * Signature: (Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_open + (JNIEnv *env, jclass cls, jstring path) +{ + jboolean isCopy; + const char* p = GetStringPlatformChars(env, path, &isCopy); + if (p == NULL) { + return 0; + } else { + int fd; + int err = 0; + + fd = open(p, O_RDWR); + if (fd == -1) { + err = errno; + } + + if (isCopy) { + JNU_ReleaseStringPlatformChars(env, path, p); + } + + if (fd == -1) { + if (err == ENOENT) { + JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL); + } else { + char* msg = strdup(strerror(err)); + JNU_ThrowIOException(env, msg); + if (msg != NULL) { + free(msg); + } + } + } + return fd; + } +} + +/* + * Class: sun_tools_attach_VirtualMachineImpl + * Method: checkPermissions + * Signature: (Ljava/lang/String;)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions + (JNIEnv *env, jclass cls, jstring path) +{ + jboolean isCopy; + const char* p = GetStringPlatformChars(env, path, &isCopy); + if (p != NULL) { + struct stat64 sb; + uid_t uid, gid; + int res; + + memset(&sb, 0, sizeof(struct stat64)); + + /* + * Check that the path is owned by the effective uid/gid of this + * process. Also check that group/other access is not allowed. + */ + uid = geteuid(); + gid = getegid(); + + res = stat64(p, &sb); + if (res != 0) { + /* save errno */ + res = errno; + } + + if (res == 0) { + char msg[100]; + jboolean isError = JNI_FALSE; + if (sb.st_uid != uid && uid != ROOT_UID) { + snprintf(msg, sizeof(msg), + "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid); + isError = JNI_TRUE; + } else if (sb.st_gid != gid && uid != ROOT_UID) { + snprintf(msg, sizeof(msg), + "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid); + isError = JNI_TRUE; + } else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) { + snprintf(msg, sizeof(msg), + "file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777); + isError = JNI_TRUE; + } + if (isError) { + char buf[256]; + snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg); + JNU_ThrowIOException(env, buf); + } + } else { + char* msg = strdup(strerror(res)); + JNU_ThrowIOException(env, msg); + if (msg != NULL) { + free(msg); + } + } + + if (isCopy) { + JNU_ReleaseStringPlatformChars(env, path, p); + } + } +} + +/* + * Class: sun_tools_attach_VirtualMachineImpl + * Method: close + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close + (JNIEnv *env, jclass cls, jint fd) +{ + int ret; + RESTARTABLE(close(fd), ret); +} + +/* + * Class: sun_tools_attach_VirtualMachineImpl + * Method: read + * Signature: (I[BI)I + */ +JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read + (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen) +{ + unsigned char buf[128]; + size_t len = sizeof(buf); + ssize_t n; + + size_t remaining = (size_t)(baLen - off); + if (len > remaining) { + len = remaining; + } + + RESTARTABLE(read(fd, buf, len), n); + if (n == -1) { + JNU_ThrowIOExceptionWithLastError(env, "read"); + } else { + if (n == 0) { + n = -1; // EOF + } else { + (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf)); + } + } + return n; +} + +/* + * Class: sun_tools_attach_VirtualMachineImpl + * Method: sigquit + * Signature: (I)V + */ +JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sigquit + (JNIEnv *env, jclass cls, jint pid) +{ + if (kill((pid_t)pid, SIGQUIT) == -1) { + JNU_ThrowIOExceptionWithLastError(env, "kill"); + } +} + +/* + * A simple table to translate some known errors into reasonable + * error messages + */ +static struct { + jint err; + const char* msg; +} const error_messages[] = { + { 100, "Bad request" }, + { 101, "Protocol mismatch" }, + { 102, "Resource failure" }, + { 103, "Internal error" }, + { 104, "Permission denied" }, +}; + +/* + * Lookup the given error code and return the appropriate + * message. If not found return NULL. + */ +static const char* translate_error(jint err) { + int table_size = sizeof(error_messages) / sizeof(error_messages[0]); + int i; + + for (i = 0; i < table_size; i++) { + if (err == error_messages[i].err) { + return error_messages[i].msg; + } + } + return NULL; +} + +/* + * Current protocol version + */ +static const char* PROTOCOL_VERSION = "1"; + +/* + * Class: sun_tools_attach_VirtualMachineImpl + * Method: enqueue + * Signature: (JILjava/lang/String;[Ljava/lang/Object;)V + */ +JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue + (JNIEnv *env, jclass cls, jint fd, jstring cmd, jobjectArray args) +{ + jint arg_count, i; + size_t size; + jboolean isCopy; + door_arg_t door_args; + char res_buffer[128]; + jint result = -1; + int rc; + const char* cstr; + char* buf; + + /* + * First we get the command string and create the start of the + * argument string to send to the target VM: + * \0\0 + */ + cstr = JNU_GetStringPlatformChars(env, cmd, &isCopy); + if (cstr == NULL) { + return -1; /* pending exception */ + } + size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2; + buf = (char*)malloc(size); + if (buf != NULL) { + char* pos = buf; + strcpy(buf, PROTOCOL_VERSION); + pos += strlen(PROTOCOL_VERSION)+1; + strcpy(pos, cstr); + } + if (isCopy) { + JNU_ReleaseStringPlatformChars(env, cmd, cstr); + } + if (buf == NULL) { + JNU_ThrowOutOfMemoryError(env, "malloc failed"); + return -1; + } + + /* + * Next we iterate over the arguments and extend the buffer + * to include them. + */ + arg_count = (*env)->GetArrayLength(env, args); + + for (i = 0; i < arg_count; i++) { + jobject obj = (*env)->GetObjectArrayElement(env, args, i); + if (obj != NULL) { + cstr = JNU_GetStringPlatformChars(env, obj, &isCopy); + if (cstr != NULL) { + size_t len = strlen(cstr); + char* newbuf = (char*)realloc(buf, size+len+1); + if (newbuf != NULL) { + buf = newbuf; + strcpy(buf+size, cstr); + size += len+1; + } + if (isCopy) { + JNU_ReleaseStringPlatformChars(env, obj, cstr); + } + if (newbuf == NULL) { + free(buf); + JNU_ThrowOutOfMemoryError(env, "realloc failed"); + return -1; + } + } + } else { + char* newbuf = (char*)realloc(buf, size + 1); + if (newbuf == NULL) { + free(buf); + JNU_ThrowOutOfMemoryError(env, "realloc failed"); + return -1; + } + buf = newbuf; + buf[size++] = 0; + } + if ((*env)->ExceptionOccurred(env)) { + free(buf); + return -1; + } + } + + /* + * The arguments to the door function are in 'buf' so we now + * do the door call + */ + door_args.data_ptr = buf; + door_args.data_size = size; + door_args.desc_ptr = NULL; + door_args.desc_num = 0; + door_args.rbuf = (char*)&res_buffer; + door_args.rsize = sizeof(res_buffer); + + RESTARTABLE(door_call(fd, &door_args), rc); + + /* + * door_call failed + */ + if (rc == -1) { + JNU_ThrowIOExceptionWithLastError(env, "door_call"); + } else { + /* + * door_call succeeded but the call didn't return the expected jint. + */ + if (door_args.data_size < sizeof(jint)) { + JNU_ThrowIOException(env, "Enqueue error - reason unknown as result is truncated!"); + } else { + jint* res = (jint*)(door_args.data_ptr); + if (*res != JNI_OK) { + const char* msg = translate_error(*res); + char buf[255]; + if (msg == NULL) { + sprintf(buf, "Unable to enqueue command to target VM: %d", *res); + } else { + sprintf(buf, "Unable to enqueue command to target VM: %s", msg); + } + JNU_ThrowIOException(env, buf); + } else { + /* + * The door call should return a file descriptor to one end of + * a socket pair + */ + if ((door_args.desc_ptr != NULL) && + (door_args.desc_num == 1) && + (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) { + result = door_args.desc_ptr->d_data.d_desc.d_descriptor; + } else { + JNU_ThrowIOException(env, "Reply from enqueue missing descriptor!"); + } + } + } + } + + free(buf); + return result; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java jdk21u-jdk-21.0.2-ga/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java 2024-01-27 14:37:30.275956829 +0100 @@ -94,7 +94,7 @@ private static class Decoder extends CharsetDecoder { private static final String SJISName = getSJISName(); - private static final String EUCJPName = "EUC_JP"; + private static final String EUCJPName = getEUCJPName(); private DelegatableDecoder detectedDecoder = null; public Decoder(Charset cs) { @@ -222,11 +222,24 @@ * Returned Shift_JIS Charset name is OS dependent */ private static String getSJISName() { - if (OperatingSystem.isWindows()) + if (OperatingSystem.isSolaris()) + return("PCK"); + else if (OperatingSystem.isWindows()) return("windows-31J"); else return("Shift_JIS"); } + /** + * Returned EUC-JP Charset name is OS dependent + */ + + private static String getEUCJPName() { + if (OperatingSystem.isSolaris()) + return("x-eucjp-open"); + else + return("EUC_JP"); + } + } } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java jdk21u-jdk-21.0.2-ga/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java 2024-01-27 14:37:30.276436666 +0100 @@ -711,10 +711,15 @@ lib = expand(lib); int i = lib.indexOf("/$ISA/"); if (i != -1) { - // replace "/$ISA/" with "/" + // replace "/$ISA/" with "/amd64/" on Solaris AMD64. + // On all other platforms, just turn it into a "/" String prefix = lib.substring(0, i); String suffix = lib.substring(i + 5); - lib = prefix + suffix; + if (osName.equals("SunOS") && osArch.equals("amd64")) { + lib = prefix + "/amd64" + suffix; + } else { + lib = prefix + suffix; + } } if (DEBUG) { System.out.println(keyword + ": " + lib); diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg jdk21u-jdk-21.0.2-ga/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg 2024-01-27 14:37:30.309418712 +0100 @@ -0,0 +1,23 @@ +# +# Configuration file to allow the SunPKCS11 provider to utilize +# the Solaris Cryptographic Framework, if it is available +# + +name = Solaris + +description = SunPKCS11 accessing Solaris Cryptographic Framework + +library = /usr/lib/$ISA/libpkcs11.so + +handleStartupErrors = ignoreAll + +# Use the X9.63 encoding for EC points (do not wrap in an ASN.1 OctetString). +useEcX963Encoding = true + +attributes = compatibility + +disabledMechanisms = { + CKM_DSA_KEY_PAIR_GEN + SecureRandom +} + diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java 2024-01-27 14:37:30.309688751 +0100 @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2000, 2005, 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. + * + */ + +package sun.jvm.hotspot; + +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.types.basic.*; + +/** This class implements the compiler-specific access to the vtbl for + a given C++ type. */ +public class HotSpotSolarisVtblAccess extends BasicVtblAccess { + + public HotSpotSolarisVtblAccess(SymbolLookup symbolLookup, + String[] jvmLibNames) { + super(symbolLookup, jvmLibNames); + } + + protected String vtblSymbolForType(Type type) { + String demangledSymbol = type.getName() + "::__vtbl"; + return mangle(demangledSymbol); + } + + //-------------------------------------------------------------------------------- + // Internals only below this point + // + + private String mangle(String symbol) { + String[] parts = symbol.split("::"); + StringBuffer mangled = new StringBuffer("__1c"); + for (int i = 0; i < parts.length; i++) { + int len = parts[i].length(); + if (len >= 26) { + mangled.append((char)('a' + (len / 26))); + len = len % 26; + } + mangled.append((char)('A' + len)); + mangled.append(parts[i]); + } + mangled.append("_"); + return mangled.toString(); + } +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java 2024-01-27 14:37:30.310037084 +0100 @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2004, 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. + * + */ + +package sun.jvm.hotspot.runtime.solaris_amd64; + +import java.io.*; +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.amd64.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.amd64.*; +import sun.jvm.hotspot.runtime.x86.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +public class SolarisAMD64JavaThreadPDAccess implements JavaThreadPDAccess { + private static AddressField lastJavaFPField; + private static AddressField osThreadField; + private static AddressField baseOfStackPointerField; + + // Field from OSThread + private static CIntegerField osThreadThreadIDField; + + // This is currently unneeded but is being kept in case we change + // the currentFrameGuess algorithm + private static final long GUESS_SCAN_RANGE = 128 * 1024; + + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("JavaThread"); + Type anchorType = db.lookupType("JavaFrameAnchor"); + + lastJavaFPField = anchorType.getAddressField("_last_Java_fp"); + osThreadField = type.getAddressField("_osthread"); + + type = db.lookupType("OSThread"); + osThreadThreadIDField = type.getCIntegerField("_thread_id"); + } + + public Address getLastJavaFP(Address addr) { + return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset())); + } + + public Address getLastJavaPC(Address addr) { + return null; + } + + public Address getBaseOfStackPointer(Address addr) { + return null; + } + + public Frame getLastFramePD(JavaThread thread, Address addr) { + Address fp = thread.getLastJavaFP(); + if (fp == null) { + return null; // no information + } + Address pc = thread.getLastJavaPC(); + if ( pc != null ) { + return new X86Frame(thread.getLastJavaSP(), fp, pc); + } else { + return new X86Frame(thread.getLastJavaSP(), fp); + } + } + + public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) { + return new X86RegisterMap(thread, updateMap); + } + + public Frame getCurrentFrameGuess(JavaThread thread, Address addr) { + ThreadProxy t = getThreadProxy(addr); + AMD64ThreadContext context = (AMD64ThreadContext) t.getContext(); + AMD64CurrentFrameGuess guesser = new AMD64CurrentFrameGuess(context, thread); + if (!guesser.run(GUESS_SCAN_RANGE)) { + return null; + } + if (guesser.getPC() == null) { + return new X86Frame(guesser.getSP(), guesser.getFP()); + } else { + return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC()); + } + } + + + public void printThreadIDOn(Address addr, PrintStream tty) { + tty.print(getThreadProxy(addr)); + } + + + public void printInfoOn(Address threadAddr, PrintStream tty) { + } + + public Address getLastSP(Address addr) { + ThreadProxy t = getThreadProxy(addr); + AMD64ThreadContext context = (AMD64ThreadContext) t.getContext(); + return context.getRegisterAsAddress(AMD64ThreadContext.RSP); + } + + public ThreadProxy getThreadProxy(Address addr) { + // Fetch the OSThread (for now and for simplicity, not making a + // separate "OSThread" class in this package) + Address osThreadAddr = osThreadField.getValue(addr); + // Get the address of the thread ID from the OSThread + Address tidAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset()); + + JVMDebugger debugger = VM.getVM().getDebugger(); + return debugger.getThreadForIdentifierAddress(tidAddr); + } + +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java 2024-01-27 14:37:30.310388763 +0100 @@ -0,0 +1,142 @@ +/* + * Copyright (c) 2000, 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. + * + */ + +package sun.jvm.hotspot.runtime.solaris_x86; + +import java.io.*; +import java.util.*; +import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.debugger.x86.*; +import sun.jvm.hotspot.runtime.*; +import sun.jvm.hotspot.runtime.x86.*; +import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.utilities.*; +import sun.jvm.hotspot.utilities.Observable; +import sun.jvm.hotspot.utilities.Observer; + +/** Placeholder for now to allow us to start the SA without support + for stack traces */ + +public class SolarisX86JavaThreadPDAccess implements JavaThreadPDAccess { + private static AddressField lastJavaFPField; + private static AddressField osThreadField; + private static AddressField baseOfStackPointerField; + + // Field from OSThread + private static CIntegerField osThreadThreadIDField; + + // This is currently unneeded but is being kept in case we change + // the currentFrameGuess algorithm + private static final long GUESS_SCAN_RANGE = 128 * 1024; + + + static { + VM.registerVMInitializedObserver(new Observer() { + public void update(Observable o, Object data) { + initialize(VM.getVM().getTypeDataBase()); + } + }); + } + + private static synchronized void initialize(TypeDataBase db) { + Type type = db.lookupType("JavaThread"); + Type anchorType = db.lookupType("JavaFrameAnchor"); + + lastJavaFPField = anchorType.getAddressField("_last_Java_fp"); + osThreadField = type.getAddressField("_osthread"); + + type = db.lookupType("OSThread"); + osThreadThreadIDField = type.getCIntegerField("_thread_id"); + } + + public Address getLastJavaFP(Address addr) { + return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset())); + } + + public Address getLastJavaPC(Address addr) { + return null; + } + + public Address getBaseOfStackPointer(Address addr) { + return null; + } + + public Frame getLastFramePD(JavaThread thread, Address addr) { + Address fp = thread.getLastJavaFP(); + if (fp == null) { + return null; // no information + } + Address pc = thread.getLastJavaPC(); + if ( pc != null ) { + return new X86Frame(thread.getLastJavaSP(), fp, pc); + } else { + return new X86Frame(thread.getLastJavaSP(), fp); + } + } + + public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) { + return new X86RegisterMap(thread, updateMap); + } + + public Frame getCurrentFrameGuess(JavaThread thread, Address addr) { + ThreadProxy t = getThreadProxy(addr); + X86ThreadContext context = (X86ThreadContext) t.getContext(); + X86CurrentFrameGuess guesser = new X86CurrentFrameGuess(context, thread); + if (!guesser.run(GUESS_SCAN_RANGE)) { + return null; + } + if (guesser.getPC() == null) { + return new X86Frame(guesser.getSP(), guesser.getFP()); + } else { + return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC()); + } + } + + + public void printThreadIDOn(Address addr, PrintStream tty) { + tty.print(getThreadProxy(addr)); + } + + + public void printInfoOn(Address threadAddr, PrintStream tty) { + } + + public Address getLastSP(Address addr) { + ThreadProxy t = getThreadProxy(addr); + X86ThreadContext context = (X86ThreadContext) t.getContext(); + return context.getRegisterAsAddress(X86ThreadContext.ESP); + } + + public ThreadProxy getThreadProxy(Address addr) { + // Fetch the OSThread (for now and for simplicity, not making a + // separate "OSThread" class in this package) + Address osThreadAddr = osThreadField.getValue(addr); + // Get the address of the thread ID from the OSThread + Address tidAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset()); + + JVMDebugger debugger = VM.getVM().getDebugger(); + return debugger.getThreadForIdentifierAddress(tidAddr); + } + +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java 2024-01-27 14:37:30.276869837 +0100 @@ -28,6 +28,8 @@ import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.types.*; +import sun.jvm.hotspot.runtime.solaris_x86.SolarisX86JavaThreadPDAccess; +import sun.jvm.hotspot.runtime.solaris_amd64.SolarisAMD64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess; import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess; import sun.jvm.hotspot.runtime.win32_aarch64.Win32AARCH64JavaThreadPDAccess; @@ -97,7 +99,13 @@ access = null; // FIXME: find the platform specific PD class by reflection? - if (os.equals("win32")) { + if (os.equals("solaris")) { + if (cpu.equals("x86")) { + access = new SolarisX86JavaThreadPDAccess(); + } else if (cpu.equals("amd64")) { + access = new SolarisAMD64JavaThreadPDAccess(); + } + } else if (os.equals("win32")) { if (cpu.equals("x86")) { access = new Win32X86JavaThreadPDAccess(); } else if (cpu.equals("amd64")) { diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java 2024-01-27 14:37:30.277255100 +0100 @@ -28,10 +28,14 @@ system. */ public class PlatformInfo { - /* Returns "win32" if Windows; "linux" if Linux. */ + /* Returns "solaris" if on Solaris; "win32" if Windows; "linux" if + Linux. Used to determine location of dbx and import module, or + possible debugger agent on win32. */ public static String getOS() throws UnsupportedPlatformException { String os = System.getProperty("os.name"); - if (os.equals("Linux")) { + if (os.equals("SunOS")) { + return "solaris"; + } else if (os.equals("Linux")) { return "linux"; } else if (os.equals("FreeBSD")) { return "bsd"; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c 2024-01-27 14:37:30.277694745 +0100 @@ -22,6 +22,8 @@ * */ +#include // just include something, or else solaris compiler will complain that this file is empty + #if defined(LINUX) || defined(__APPLE__) #include #include diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/test/libproc/libproctest.sh jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/test/libproc/libproctest.sh --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.hotspot.agent/test/libproc/libproctest.sh 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.hotspot.agent/test/libproc/libproctest.sh 2024-01-27 14:37:30.278089122 +0100 @@ -59,8 +59,10 @@ kill -9 $pid +OPTIONS="-Djava.library.path=$STARTDIR/../src/os/solaris/proc/`uname -p`:$STARTDIR/../solaris/`uname -p`" + # run libproc client -$SA_JAVA -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid +$SA_JAVA -showversion ${OPTIONS} -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid # delete core rm -f core.$pid diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c jdk21u-jdk-21.0.2-ga/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c 2024-01-27 14:37:30.278579164 +0100 @@ -33,8 +33,12 @@ #include #include #include +#ifdef __solaris__ +#include +#else #include #include +#endif #include "socket_md.h" #include "sysSocket.h" @@ -271,6 +275,35 @@ return 0; } +#ifdef __solaris__ +int +dbgsysTlsAlloc() { + thread_key_t tk; + if (thr_keycreate(&tk, NULL)) { + perror("thr_keycreate"); + exit(-1); + } + return (int)tk; +} + +void +dbgsysTlsFree(int index) { + /* no-op */ +} + +void +dbgsysTlsPut(int index, void *value) { + thr_setspecific((thread_key_t)index, value) ; +} + +void * +dbgsysTlsGet(int index) { + void* r = NULL; + thr_getspecific((thread_key_t)index, &r); + return r; +} + +#else int dbgsysTlsAlloc() { pthread_key_t key; @@ -296,6 +329,8 @@ return pthread_getspecific((pthread_key_t)index); } +#endif + long dbgsysCurrentTimeMillis() { struct timeval t; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c jdk21u-jdk-21.0.2-ga/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c 1970-01-01 01:00:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c 2024-01-27 14:37:30.310811602 +0100 @@ -0,0 +1,254 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jvm.h" +#include "com_sun_management_internal_OperatingSystemImpl.h" + +typedef struct { + kstat_t *kstat; + uint64_t last_idle; + uint64_t last_total; + double last_ratio; +} cpuload_t; + +static cpuload_t *cpu_loads = NULL; +static unsigned int num_cpus; +static kstat_ctl_t *kstat_ctrl = NULL; + +static void map_cpu_kstat_counters() { + kstat_t *kstat; + int i; + + // Get number of CPU(s) + if ((num_cpus = sysconf(_SC_NPROCESSORS_ONLN)) == -1) { + num_cpus = 1; + } + + // Data structure for saving CPU load + if ((cpu_loads = calloc(num_cpus,sizeof(cpuload_t))) == NULL) { + return; + } + + // Get kstat cpu_stat counters for every CPU + // (loop over kstat to find our cpu_stat(s) + i = 0; + for (kstat = kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) { + if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) { + + if (kstat_read(kstat_ctrl, kstat, NULL) == -1) { + // Failed to initialize kstat for this CPU so ignore it + continue; + } + + if (i == num_cpus) { + // Found more cpu_stats than reported CPUs + break; + } + + cpu_loads[i++].kstat = kstat; + } + } +} + +static int init_cpu_kstat_counters() { + static int initialized = 0; + + // Concurrence in this method is prevented by the lock in + // the calling method get_cpu_load(); + if(!initialized) { + if ((kstat_ctrl = kstat_open()) != NULL) { + map_cpu_kstat_counters(); + initialized = 1; + } + } + return initialized ? 0 : -1; +} + +static void update_cpu_kstat_counters() { + if(kstat_chain_update(kstat_ctrl) != 0) { + free(cpu_loads); + map_cpu_kstat_counters(); + } +} + +int read_cpustat(cpuload_t *load, cpu_stat_t *cpu_stat) { + if (load->kstat == NULL) { + // no handle. + return -1; + } + if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == -1) { + // disabling for now, a kstat chain update is likely to happen next time + load->kstat = NULL; + return -1; + } + return 0; +} + +double get_single_cpu_load(unsigned int n) { + cpuload_t *load; + cpu_stat_t cpu_stat; + uint_t *usage; + uint64_t c_idle; + uint64_t c_total; + uint64_t d_idle; + uint64_t d_total; + int i; + + if (n >= num_cpus) { + return -1.0; + } + + load = &cpu_loads[n]; + if (read_cpustat(load, &cpu_stat) < 0) { + return -1.0; + } + + usage = cpu_stat.cpu_sysinfo.cpu; + c_idle = usage[CPU_IDLE]; + + for (c_total = 0, i = 0; i < CPU_STATES; i++) { + c_total += usage[i]; + } + + // Calculate diff against previous snapshot + d_idle = c_idle - load->last_idle; + 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; +} + +int get_info(const char *path, void *info, size_t s, off_t o) { + int fd; + int ret = 0; + if ((fd = open(path, O_RDONLY)) < 0) { + return -1; + } + if (pread(fd, info, s, o) != s) { + ret = -1; + } + close(fd); + return ret; +} + +#define MIN(a, b) ((a < b) ? a : b) + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +/** + * Return the cpu load (0-1) for proc number 'which' (or average all if which == -1) + */ +double get_cpu_load(int which) { + double load =.0; + + pthread_mutex_lock(&lock); + if(init_cpu_kstat_counters()==0) { + + update_cpu_kstat_counters(); + + if (which == -1) { + unsigned int i; + double t; + + for (t = .0, i = 0; i < num_cpus; i++) { + t += get_single_cpu_load(i); + } + + // Cap total systemload to 1.0 + load = MIN((t / num_cpus), 1.0); + } else { + load = MIN(get_single_cpu_load(which), 1.0); + } + } else { + load = -1.0; + } + pthread_mutex_unlock(&lock); + + return load; +} + +/** + * Return the cpu load (0-1) for the current process (i.e the JVM) + * or -1.0 if the get_info() call failed + */ +double get_process_load(void) { + 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_info("/proc/self/psinfo",&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) == 0) { + return (double) info.pr_pctcpu / 0x8000; + } + return -1.0; +} + +JNIEXPORT jdouble JNICALL +Java_com_sun_management_internal_OperatingSystemImpl_getCpuLoad0 +(JNIEnv *env, jobject dummy) +{ + return get_cpu_load(-1); +} + +JNIEXPORT jdouble JNICALL +Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuLoad0 +(JNIEnv *env, jobject dummy) +{ + return get_process_load(); +} + +JNIEXPORT jdouble JNICALL +Java_com_sun_management_internal_OperatingSystemImpl_getSingleCpuLoad0 +(JNIEnv *env, jobject mbean, jint cpu_number) +{ + return -1.0; +} + +JNIEXPORT jint JNICALL +Java_com_sun_management_internal_OperatingSystemImpl_getHostConfiguredCpuCount0 +(JNIEnv *env, jobject mbean) +{ + return -1; +} diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c jdk21u-jdk-21.0.2-ga/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c 2024-01-27 14:37:30.279084086 +0100 @@ -85,7 +85,63 @@ // true = get available swap in bytes // false = get total swap in bytes static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean available) { -#if defined(__linux__) +#ifdef __solaris__ + long total, avail; + int nswap, i, count; + swaptbl_t *stbl; + char *strtab; + + // First get the number of swap resource entries + if ((nswap = swapctl(SC_GETNSWP, NULL)) == -1) { + throw_internal_error(env, "swapctl failed to get nswap"); + return -1; + } + if (nswap == 0) { + return 0; + } + + // Allocate storage for resource entries + stbl = (swaptbl_t*) malloc(nswap * sizeof(swapent_t) + + sizeof(struct swaptable)); + if (stbl == NULL) { + JNU_ThrowOutOfMemoryError(env, 0); + return -1; + } + + // Allocate storage for the table + strtab = (char*) malloc((nswap + 1) * MAXPATHLEN); + if (strtab == NULL) { + free(stbl); + JNU_ThrowOutOfMemoryError(env, 0); + return -1; + } + + for (i = 0; i < (nswap + 1); i++) { + stbl->swt_ent[i].ste_path = strtab + (i * MAXPATHLEN); + } + stbl->swt_n = nswap + 1; + + // Get the entries + if ((count = swapctl(SC_LIST, stbl)) < 0) { + free(stbl); + free(strtab); + throw_internal_error(env, "swapctl failed to get swap list"); + return -1; + } + + // Sum the entries to get total and free swap + total = 0; + avail = 0; + for (i = 0; i < count; i++) { + total += stbl->swt_ent[i].ste_pages; + avail += stbl->swt_ent[i].ste_free; + } + + free(stbl); + free(strtab); + return available ? ((jlong)avail * page_size) : + ((jlong)total * page_size); +#elif defined(__linux__) int ret; jlong total = 0, avail = 0; @@ -128,7 +184,37 @@ Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0 (JNIEnv *env, jobject mbean) { -#if defined(__APPLE__) +#ifdef __solaris__ + psinfo_t psinfo; + ssize_t result; + size_t remaining; + char* addr; + int fd; + + fd = open64("/proc/self/psinfo", O_RDONLY, 0); + if (fd < 0) { + throw_internal_error(env, "Unable to open /proc/self/psinfo"); + return -1; + } + + addr = (char *)&psinfo; + for (remaining = sizeof(psinfo_t); remaining > 0;) { + result = read(fd, addr, remaining); + if (result < 0) { + if (errno != EINTR) { + close(fd); + throw_internal_error(env, "Unable to read /proc/self/psinfo"); + return -1; + } + } else { + remaining -= result; + addr += result; + } + } + + close(fd); + return (jlong) psinfo.pr_size * 1024; +#elif defined(__APPLE__) struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; @@ -184,7 +270,7 @@ * BSDNOTE: FreeBSD implements _SC_CLK_TCK since FreeBSD 5, so * add a magic to handle it */ -#if defined(_SC_CLK_TCK) +#if defined(__solaris__) || defined(_SC_CLK_TCK) clk_tck = (jlong) sysconf(_SC_CLK_TCK); #elif defined(__linux__) || defined(_ALLBSD_SOURCE) clk_tck = 100; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java 2024-01-27 14:37:30.279488397 +0100 @@ -44,6 +44,12 @@ /* -- Miscellaneous SCTP utilities -- */ private static boolean IPv4MappedAddresses() { + if (true) { + /* FIXME - nonportable hack */ + /* Solaris supports IPv4Mapped Addresses with bindx */ + return true; + } /* else { //other OS/implementations */ + /* lksctp/linux requires Ipv4 addresses */ return false; } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/native/libsctp/Sctp.h jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/native/libsctp/Sctp.h --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/native/libsctp/Sctp.h 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/native/libsctp/Sctp.h 2024-01-27 14:37:30.279911901 +0100 @@ -26,6 +26,48 @@ #ifndef SUN_NIO_CH_SCTP_H #define SUN_NIO_CH_SCTP_H +#ifdef __solaris__ + +#define _XPG4_2 +#define __EXTENSIONS__ +#include +#include +#include "jni.h" + +/* Current Solaris headers don't comply with draft rfc */ +#ifndef SCTP_EOF +#define SCTP_EOF MSG_EOF +#endif + +#ifndef SCTP_UNORDERED +#define SCTP_UNORDERED MSG_UNORDERED +#endif + +/* The current version of the socket API extension shipped with Solaris does + * not define the following options that the Java API (optionally) supports */ +#ifndef SCTP_EXPLICIT_EOR +#define SCTP_EXPLICIT_EOR -1 +#endif +#ifndef SCTP_FRAGMENT_INTERLEAVE +#define SCTP_FRAGMENT_INTERLEAVE -1 +#endif +#ifndef SCTP_SET_PEER_PRIMARY_ADDR +#define SCTP_SET_PEER_PRIMARY_ADDR -1 +#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 + * runtime for libsctp.*/ +typedef int sctp_getladdrs_func(int sock, sctp_assoc_t id, void **addrs); +typedef int sctp_freeladdrs_func(void* addrs); +typedef int sctp_getpaddrs_func(int sock, sctp_assoc_t id, void **addrs); +typedef int sctp_freepaddrs_func(void *addrs); +typedef int sctp_bindx_func(int sock, void *addrs, int addrcnt, int flags); +typedef int sctp_peeloff_func(int sock, sctp_assoc_t id); + + + +#else /* __linux__ */ #include #include #include @@ -278,6 +320,8 @@ typedef int sctp_peeloff_func(int sock, sctp_assoc_t id); +#endif /* __linux__ */ + extern sctp_getladdrs_func* nio_sctp_getladdrs; extern sctp_freeladdrs_func* nio_sctp_freeladdrs; extern sctp_getpaddrs_func* nio_sctp_getpaddrs; diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c 2024-01-27 14:37:30.280290360 +0100 @@ -331,11 +331,10 @@ break; case SCTP_ADDR_MADE_PRIM : event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_MADE_PRIM; +#ifdef __linux__ /* Solaris currently doesn't support SCTP_ADDR_CONFIRMED */ break; -#ifdef __linux__ case SCTP_ADDR_CONFIRMED : event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_CONFIRMED; - break; #endif /* __linux__ */ } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpNet.c jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/native/libsctp/SctpNet.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpNet.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.sctp/unix/native/libsctp/SctpNet.c 2024-01-27 14:37:30.280744204 +0100 @@ -371,7 +371,11 @@ int i, addrCount; jobjectArray isaa; +#ifdef __solaris__ + if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) { +#else /* __linux__ */ if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) { +#endif sctpHandleSocketError(env, errno); return NULL; } @@ -416,7 +420,11 @@ int i, addrCount; jobjectArray isaa; +#if defined(__solaris__) + if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) { +#else /* __linux__ */ if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr **)&addr_buf)) == -1) { +#endif sctpHandleSocketError(env, errno); return NULL; } diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java jdk21u-jdk-21.0.2-ga/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java 2024-01-27 14:37:30.281313814 +0100 @@ -104,7 +104,7 @@ * to false if you do not want this module to use the ticket cache. * (Default is False). * This module will search for the ticket - * cache in the following locations: On Linux + * cache in the following locations: On Solaris and Linux * it will look for the ticket cache in /tmp/krb5cc_{@code uid} * where the uid is numeric user identifier. If the ticket cache is * not available in the above location, or if we are on a diff -Nru jdk21u-jdk-21.0.2-ga.orig/src/jdk.security.auth/unix/native/libjaas/Unix.c jdk21u-jdk-21.0.2-ga/src/jdk.security.auth/unix/native/libjaas/Unix.c --- jdk21u-jdk-21.0.2-ga.orig/src/jdk.security.auth/unix/native/libjaas/Unix.c 2024-01-16 17:19:00.000000000 +0100 +++ jdk21u-jdk-21.0.2-ga/src/jdk.security.auth/unix/native/libjaas/Unix.c 2024-01-27 14:37:30.281670663 +0100 @@ -32,6 +32,10 @@ #include #include +/* For POSIX-compliant getpwuid_r on Solaris */ +#if defined(__solaris__) +#define _POSIX_PTHREAD_SEMANTICS +#endif #include /*