From 1f886f94bdc908cf32bcf86fc69615c851db3c53 Mon Sep 17 00:00:00 2001 From: Timur Sultanov Date: Sat, 11 Jun 2022 14:22:22 -0600 Subject: [PATCH] Ports: Add OpenJDK port Port of OpenJDK 17.0.2, zero VM only. More work needed to get the full hotspot VM up and running :^) Co-Authored-By: Andrew Kaster --- Ports/AvailablePorts.md | 1 + Ports/OpenJDK/package.sh | 57 + ...y-support-masquerading-as-BSD-when-n.patch | 152 ++ ...ld-with-c-20-when-targeting-serenity.patch | 98 + .../0003-make-Remove-CUPS-dependency.patch | 22 + ...arounds-for-BSD-differences-from-ser.patch | 400 +++ ...-non-BSD-native-modules-for-Serenity.patch | 268 ++ ...cific-modules-to-java.base-and-jdk.a.patch | 2394 +++++++++++++++++ ...e-native-modules-to-support-Serenity.patch | 606 +++++ ...Enable-java.lang.Process-on-serenity.patch | 259 ++ Ports/OpenJDK/patches/ReadMe.md | 51 + 11 files changed, 4308 insertions(+) create mode 100755 Ports/OpenJDK/package.sh create mode 100644 Ports/OpenJDK/patches/0001-make-Add-Serenity-support-masquerading-as-BSD-when-n.patch create mode 100644 Ports/OpenJDK/patches/0002-make-Build-with-c-20-when-targeting-serenity.patch create mode 100644 Ports/OpenJDK/patches/0003-make-Remove-CUPS-dependency.patch create mode 100644 Ports/OpenJDK/patches/0004-hotspot-Add-workarounds-for-BSD-differences-from-ser.patch create mode 100644 Ports/OpenJDK/patches/0005-hotspot-Update-non-BSD-native-modules-for-Serenity.patch create mode 100644 Ports/OpenJDK/patches/0006-Add-serenity-specific-modules-to-java.base-and-jdk.a.patch create mode 100644 Ports/OpenJDK/patches/0007-java.base-Update-native-modules-to-support-Serenity.patch create mode 100644 Ports/OpenJDK/patches/0008-java.base-Enable-java.lang.Process-on-serenity.patch create mode 100644 Ports/OpenJDK/patches/ReadMe.md diff --git a/Ports/AvailablePorts.md b/Ports/AvailablePorts.md index d25ff22de4a..fb4881cf11a 100644 --- a/Ports/AvailablePorts.md +++ b/Ports/AvailablePorts.md @@ -162,6 +162,7 @@ This list is also available at [ports.serenityos.net](https://ports.serenityos.n | [`ntbtls`](ntbtls/) | The Not Too Bad TLS Library | 0.2.0 | https://gnupg.org/software/ntbtls/index.html | | [`nyancat`](nyancat/) | Nyancat | | https://github.com/klange/nyancat | | [`oksh`](oksh/) | oksh | 7.1 | https://github.com/ibara/oksh | +| [`OpenJDK`](OpenJDK/) | OpenJDK | 17.0.2 | https://openjdk.java.net/ | | [`openssh`](openssh/) | OpenSSH | 9.0-94eb685 | https://github.com/openssh/openssh-portable | | [`openssl`](openssl/) | OpenSSL | 1.1.1o | https://www.openssl.org/ | | [`openttd`](openttd/) | OpenTTD | 12.2 | https://www.openttd.org/ | diff --git a/Ports/OpenJDK/package.sh b/Ports/OpenJDK/package.sh new file mode 100755 index 00000000000..adcd73b8903 --- /dev/null +++ b/Ports/OpenJDK/package.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env -S USE_CCACHE=false bash ../.port_include.sh + +port='OpenJDK' +version='17.0.2' +workdir="jdk17u-dev-jdk-${version}-ga" +useconfigure='true' +use_fresh_config_guess='true' +config_guess_paths=("make/autoconf/build-aux/autoconf-config.guess") +use_fresh_config_sub='true' +config_sub_paths=("make/autoconf/build-aux/autoconf-config.sub") +auth_type='sha256' +files="https://github.com/openjdk/jdk17u-dev/archive/refs/tags/jdk-${version}-ga.tar.gz jdk-${version}-ga.tar.gz cb5b2a5d0916723d340f2c5bacd4607f8b8dc3a18dc8019fcfabf5306e2a4112" +depends=("fontconfig" "libffi") + +configure() { + TOOLCHAIN_ARGS=() + WARNING_IGNORE_FLAGS='-Wno-error=switch -Wno-maybe-uninitialized' + if [ $SERENITY_TOOLCHAIN = 'Clang' ]; then + # We need the build CC and CXX to actually be clang when using clang to cross-compile + # ... for some reason. + TOOLCHAIN_ARGS=("--with-toolchain-type=clang" + "BUILD_CC=clang" + "BUILD_CXX=clang++") + WARNING_IGNORE_FLAGS="${WARNING_IGNORE_FLAGS} -Wno-error=bitwise-instead-of-logical" + fi + + # Note: To use ccache with OpenJDK, pass --enable-ccache + # It rejects the ccache symlinks. + + run bash configure \ + AR=${AR} \ + READELF=${READELF} \ + STRIP=${STRIP} \ + CXXFILT=${CXXFILT} \ + BUILD_AR=${HOST_AR} \ + BUILD_OBJCOPY=${HOST_OBJCOPY} \ + BUILD_STRIP=${HOST_STRIP} \ + --openjdk-target=${SERENITY_ARCH}-pc-serenity \ + --with-sysroot=${SERENITY_INSTALL_ROOT} \ + --with-jvm-variants=zero \ + --enable-headless-only \ + --with-debug-level=fastdebug \ + --with-native-debug-symbols=internal \ + --with-tools-dir=${SERENITY_TOOLCHAIN_BINDIR} \ + --with-extra-cflags="${WARNING_IGNORE_FLAGS}" \ + --with-extra-cxxflags="${WARNING_IGNORE_FLAGS}" \ + "${TOOLCHAIN_ARGS[@]}" +} + +build() { + run make java.base jdk.compiler java.logging +} + +install() { + run mkdir -p ${SERENITY_INSTALL_ROOT}/usr/local/lib/jvm/ + run sh -c "cp ./build/serenity-* ${SERENITY_INSTALL_ROOT}/usr/local/lib/jvm/ -rf" +} diff --git a/Ports/OpenJDK/patches/0001-make-Add-Serenity-support-masquerading-as-BSD-when-n.patch b/Ports/OpenJDK/patches/0001-make-Add-Serenity-support-masquerading-as-BSD-when-n.patch new file mode 100644 index 00000000000..d1756e6a9f0 --- /dev/null +++ b/Ports/OpenJDK/patches/0001-make-Add-Serenity-support-masquerading-as-BSD-when-n.patch @@ -0,0 +1,152 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Timur Sultanov +Date: Wed, 16 Feb 2022 21:04:18 +0300 +Subject: [PATCH] make: Add Serenity support, masquerading as BSD when + necessary + +Co-Authored-By: Andrew Kaster +--- + make/autoconf/flags-cflags.m4 | 3 +++ + make/autoconf/flags-ldflags.m4 | 11 +++++++++++ + make/autoconf/platform.m4 | 8 ++++++++ + make/autoconf/toolchain.m4 | 1 + + make/common/modules/LauncherCommon.gmk | 3 +++ + make/hotspot/lib/JvmMapfile.gmk | 12 ++++++++++++ + make/modules/java.base/lib/CoreLibraries.gmk | 1 + + 7 files changed, 39 insertions(+) + +diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 +index 5eed1138f..62e53a1c4 100644 +--- a/make/autoconf/flags-cflags.m4 ++++ b/make/autoconf/flags-cflags.m4 +@@ -382,6 +382,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], + CFLAGS_OS_DEF_JVM="-DAIX" + elif test "x$OPENJDK_TARGET_OS" = xbsd; then + CFLAGS_OS_DEF_JDK="-D_ALLBSD_SOURCE" ++ elif test "x$OPENJDK_TARGET_OS" = xserenity; then ++ CFLAGS_OS_DEF_JDK="-DSERENITY" ++ CFLAGS_OS_DEF_JVM="-DSERENITY" + elif test "x$OPENJDK_TARGET_OS" = xwindows; then + CFLAGS_OS_DEF_JVM="-D_WINDOWS -DWIN32 -D_JNI_IMPLEMENTATION_" + fi +diff --git a/make/autoconf/flags-ldflags.m4 b/make/autoconf/flags-ldflags.m4 +index 23bb33e87..e3deb0c3f 100644 +--- a/make/autoconf/flags-ldflags.m4 ++++ b/make/autoconf/flags-ldflags.m4 +@@ -110,6 +110,17 @@ AC_DEFUN([FLAGS_SETUP_LDFLAGS_HELPER], + fi + fi + ++ if test "x$OPENJDK_TARGET_OS" = xserenity; then ++ if test "x$TOOLCHAIN_TYPE" = xgcc; then ++ # FIXME: -lgcc_s should not be required, toolchain spec file issue ++ OS_LDFLAGS_JVM_ONLY="$OS_LDFLAGS_JVM_ONLY -ldl -lpthread -lgcc_s" ++ OS_LDFLAGS="$OS_LDFLAGS -ldl -lpthread -lgcc_s" ++ elif test "x$TOOLCHAIN_TYPE" = xclang; then ++ OS_LDFLAGS_JVM_ONLY="$OS_LDFLAGS_JVM_ONLY -ldl -lpthread" ++ OS_LDFLAGS="$OS_LDFLAGS -ldl -lpthread" ++ fi ++ fi ++ + # Setup debug level-dependent LDFLAGS + if test "x$TOOLCHAIN_TYPE" = xgcc; then + if test "x$OPENJDK_TARGET_OS" = xlinux; then +diff --git a/make/autoconf/platform.m4 b/make/autoconf/platform.m4 +index 205d64f56..6e668edc4 100644 +--- a/make/autoconf/platform.m4 ++++ b/make/autoconf/platform.m4 +@@ -220,6 +220,10 @@ AC_DEFUN([PLATFORM_EXTRACT_VARS_FROM_OS], + VAR_OS=aix + VAR_OS_TYPE=unix + ;; ++ *serenity*) ++ VAR_OS=serenity ++ VAR_OS_TYPE=unix ++ ;; + *) + AC_MSG_ERROR([unsupported operating system $1]) + ;; +@@ -521,6 +525,8 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], + HOTSPOT_$1_OS=${OPENJDK_$1_OS} + if test "x$OPENJDK_$1_OS" = xmacosx; then + HOTSPOT_$1_OS=bsd ++ elif test "x$OPENJDK_$1_OS" = xserenity; then ++ HOTSPOT_$1_OS=bsd + fi + AC_SUBST(HOTSPOT_$1_OS) + +@@ -587,6 +593,8 @@ AC_DEFUN([PLATFORM_SETUP_LEGACY_VARS_HELPER], + OPENJDK_$1_OS_INCLUDE_SUBDIR="win32" + elif test "x$OPENJDK_TARGET_OS" = "xmacosx"; then + OPENJDK_$1_OS_INCLUDE_SUBDIR="darwin" ++ elif test "x$OPENJDK_TARGET_OS" = "xserenity"; then ++ OPENJDK_$1_OS_INCLUDE_SUBDIR="bsd" + fi + AC_SUBST(OPENJDK_$1_OS_INCLUDE_SUBDIR) + ]) +diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 +index 69540e160..badd84a50 100644 +--- a/make/autoconf/toolchain.m4 ++++ b/make/autoconf/toolchain.m4 +@@ -42,6 +42,7 @@ VALID_TOOLCHAINS_linux="gcc clang" + VALID_TOOLCHAINS_macosx="gcc clang" + VALID_TOOLCHAINS_aix="xlc" + VALID_TOOLCHAINS_windows="microsoft" ++VALID_TOOLCHAINS_serenity="gcc clang" + + # Toolchain descriptions + TOOLCHAIN_DESCRIPTION_clang="clang/LLVM" +diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk +index 7ad0375e2..8100f655e 100644 +--- a/make/common/modules/LauncherCommon.gmk ++++ b/make/common/modules/LauncherCommon.gmk +@@ -157,11 +157,14 @@ define SetupBuildLauncherBody + $$($1_LDFLAGS), \ + LDFLAGS_linux := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \ + -L$(call FindLibDirForModule, java.base), \ ++ LDFLAGS_serenity := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \ ++ -L$(call FindLibDirForModule, java.base), \ + LDFLAGS_macosx := $$(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_serenity := -ljli -lpthread $(LIBDL), \ + LIBS_macosx := -ljli -framework Cocoa -framework Security \ + -framework ApplicationServices, \ + LIBS_aix := -ljli_static, \ +diff --git a/make/hotspot/lib/JvmMapfile.gmk b/make/hotspot/lib/JvmMapfile.gmk +index 5cba93178..752727d0d 100644 +--- a/make/hotspot/lib/JvmMapfile.gmk ++++ b/make/hotspot/lib/JvmMapfile.gmk +@@ -64,6 +64,18 @@ ifeq ($(call isTargetOs, linux), true) + if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \ + }' + ++else ifeq ($(call isTargetOs, serenity), true) ++ DUMP_SYMBOLS_CMD := $(NM) --defined-only *.o ++ ifneq ($(FILTER_SYMBOLS_PATTERN), ) ++ FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)| ++ endif ++ FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)^_ZTV|^gHotSpotVM|^UseSharedSpaces$$ ++ FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^_ZN9Arguments17SharedArchivePathE$$ ++ FILTER_SYMBOLS_AWK_SCRIPT := \ ++ '{ \ ++ 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 --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk +index 1d5fede2a..0a61d009f 100644 +--- a/make/modules/java.base/lib/CoreLibraries.gmk ++++ b/make/modules/java.base/lib/CoreLibraries.gmk +@@ -209,6 +209,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJLI, \ + LIBS_unix := $(LIBZ_LIBS), \ + LIBS_linux := $(LIBDL) -lpthread, \ + LIBS_aix := $(LIBDL),\ ++ LIBS_serenity := $(LIBDL) -lpthread, \ + LIBS_macosx := -framework Cocoa -framework Security -framework ApplicationServices, \ + LIBS_windows := advapi32.lib comctl32.lib user32.lib, \ + )) diff --git a/Ports/OpenJDK/patches/0002-make-Build-with-c-20-when-targeting-serenity.patch b/Ports/OpenJDK/patches/0002-make-Build-with-c-20-when-targeting-serenity.patch new file mode 100644 index 00000000000..63deaa8e894 --- /dev/null +++ b/Ports/OpenJDK/patches/0002-make-Build-with-c-20-when-targeting-serenity.patch @@ -0,0 +1,98 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Kaster +Date: Sun, 12 Jun 2022 23:13:56 -0600 +Subject: [PATCH] make: Build with c++20 when targeting serenity + +--- + make/autoconf/flags-cflags.m4 | 8 ++++++-- + src/hotspot/share/utilities/chunkedList.hpp | 2 +- + src/hotspot/share/utilities/events.hpp | 2 +- + src/hotspot/share/utilities/growableArray.hpp | 2 +- + src/hotspot/share/utilities/linkedlist.hpp | 2 +- + 5 files changed, 10 insertions(+), 6 deletions(-) + +diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 +index 62e53a1c4..9239dfb43 100644 +--- a/make/autoconf/flags-cflags.m4 ++++ b/make/autoconf/flags-cflags.m4 +@@ -154,7 +154,8 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS], + WARNINGS_ENABLE_ALL_CFLAGS="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL" + WARNINGS_ENABLE_ALL_CXXFLAGS="$WARNINGS_ENABLE_ALL_CFLAGS $WARNINGS_ENABLE_ADDITIONAL_CXX" + +- DISABLED_WARNINGS="unused-parameter unused" ++ DISABLED_WARNINGS="unused-parameter unused address stringop-overflow stringop-truncation format-truncation use-after-free" ++ DISABLED_WARNINGS_CXX="volatile deprecated-enum-enum-conversion deprecated-enum-float-conversion" + ;; + + clang) +@@ -166,7 +167,7 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS], + -Wunused-function -Wundef -Wunused-value -Woverloaded-virtual" + WARNINGS_ENABLE_ALL="-Wall -Wextra -Wformat=2 $WARNINGS_ENABLE_ADDITIONAL" + +- DISABLED_WARNINGS="unknown-warning-option unused-parameter unused" ++ DISABLED_WARNINGS="unknown-warning-option unused-parameter unused deprecated-volatile deprecated-anon-enum-enum-conversion deprecated-enum-float-conversion ambiguous-reversed-operator" + + ;; + +@@ -529,6 +530,9 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], + else + AC_MSG_ERROR([Don't know how to enable C++14 for this toolchain]) + fi ++ if test "x$OPENJDK_TARGET_OS" = xserenity; then ++ LANGSTD_CXXFLAGS="-std=c++20" ++ fi + TOOLCHAIN_CFLAGS_JDK_CXXONLY="$TOOLCHAIN_CFLAGS_JDK_CXXONLY $LANGSTD_CXXFLAGS" + TOOLCHAIN_CFLAGS_JVM="$TOOLCHAIN_CFLAGS_JVM $LANGSTD_CXXFLAGS" + ADLC_LANGSTD_CXXFLAGS="$LANGSTD_CXXFLAGS" +diff --git a/src/hotspot/share/utilities/chunkedList.hpp b/src/hotspot/share/utilities/chunkedList.hpp +index 1a899ee2b..13f05cd3a 100644 +--- a/src/hotspot/share/utilities/chunkedList.hpp ++++ b/src/hotspot/share/utilities/chunkedList.hpp +@@ -44,7 +44,7 @@ template class ChunkedList : public CHeapObj { + } + + public: +- ChunkedList() : _top(_values), _next_used(NULL), _next_free(NULL) {} ++ ChunkedList() : _top(_values), _next_used(NULL), _next_free(NULL) {} + + bool is_full() const { + return _top == end(); +diff --git a/src/hotspot/share/utilities/events.hpp b/src/hotspot/share/utilities/events.hpp +index b5d67bd6a..3cf3b399f 100644 +--- a/src/hotspot/share/utilities/events.hpp ++++ b/src/hotspot/share/utilities/events.hpp +@@ -99,7 +99,7 @@ template class EventLogBase : public EventLog { + EventRecord* _records; + + public: +- EventLogBase(const char* name, const char* handle, int length = LogEventsBufferEntries): ++ EventLogBase(const char* name, const char* handle, int length = LogEventsBufferEntries): + _mutex(Mutex::event, name, true, Mutex::_safepoint_check_never), + _name(name), + _handle(handle), +diff --git a/src/hotspot/share/utilities/growableArray.hpp b/src/hotspot/share/utilities/growableArray.hpp +index b75283843..67074b86f 100644 +--- a/src/hotspot/share/utilities/growableArray.hpp ++++ b/src/hotspot/share/utilities/growableArray.hpp +@@ -118,7 +118,7 @@ class GrowableArrayView : public GrowableArrayBase { + protected: + E* _data; // data array + +- GrowableArrayView(E* data, int initial_max, int initial_len) : ++ GrowableArrayView(E* data, int initial_max, int initial_len) : + GrowableArrayBase(initial_max, initial_len), _data(data) {} + + ~GrowableArrayView() {} +diff --git a/src/hotspot/share/utilities/linkedlist.hpp b/src/hotspot/share/utilities/linkedlist.hpp +index 16ee6a844..2c5ffe6cb 100644 +--- a/src/hotspot/share/utilities/linkedlist.hpp ++++ b/src/hotspot/share/utilities/linkedlist.hpp +@@ -82,7 +82,7 @@ template class LinkedListNode : public ResourceObj { + template class LinkedList : public ResourceObj { + protected: + LinkedListNode* _head; +- NONCOPYABLE(LinkedList); ++ NONCOPYABLE(LinkedList); + + public: + LinkedList() : _head(NULL) { } diff --git a/Ports/OpenJDK/patches/0003-make-Remove-CUPS-dependency.patch b/Ports/OpenJDK/patches/0003-make-Remove-CUPS-dependency.patch new file mode 100644 index 00000000000..4f2c46f7e32 --- /dev/null +++ b/Ports/OpenJDK/patches/0003-make-Remove-CUPS-dependency.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Timur Sultanov +Date: Thu, 17 Feb 2022 09:37:02 +0300 +Subject: [PATCH] make: Remove CUPS dependency + +--- + make/autoconf/libraries.m4 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/make/autoconf/libraries.m4 b/make/autoconf/libraries.m4 +index a65d91ee9..7c779d012 100644 +--- a/make/autoconf/libraries.m4 ++++ b/make/autoconf/libraries.m4 +@@ -26,7 +26,7 @@ + # Major library component reside in separate files. + m4_include([lib-alsa.m4]) + m4_include([lib-bundled.m4]) +-m4_include([lib-cups.m4]) ++# m4_include([lib-cups.m4]) + m4_include([lib-ffi.m4]) + m4_include([lib-freetype.m4]) + m4_include([lib-std.m4]) diff --git a/Ports/OpenJDK/patches/0004-hotspot-Add-workarounds-for-BSD-differences-from-ser.patch b/Ports/OpenJDK/patches/0004-hotspot-Add-workarounds-for-BSD-differences-from-ser.patch new file mode 100644 index 00000000000..f0687e68d9c --- /dev/null +++ b/Ports/OpenJDK/patches/0004-hotspot-Add-workarounds-for-BSD-differences-from-ser.patch @@ -0,0 +1,400 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Kaster +Date: Sun, 12 Jun 2022 15:51:39 -0600 +Subject: [PATCH] hotspot: Add workarounds for BSD differences from serenity + +For the most part, we can pretend to be *BSD. + +However, for some methods, we need to convince hotspot that we're macOS, +and others need serenity-specific ifdefs due to the lack of sysctl in +serenity. + +Co-Authored-By: Timur Sultanov +--- + src/hotspot/os/bsd/attachListener_bsd.cpp | 12 +++ + src/hotspot/os/bsd/osThread_bsd.cpp | 6 +- + src/hotspot/os/bsd/os_bsd.cpp | 76 ++++++++++++++++++- + src/hotspot/os/bsd/os_perf_bsd.cpp | 4 + + .../os_cpu/bsd_zero/bytes_bsd_zero.hpp | 2 + + src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp | 18 ++++- + src/hotspot/share/classfile/classLoader.cpp | 2 +- + 7 files changed, 113 insertions(+), 7 deletions(-) + +diff --git a/src/hotspot/os/bsd/attachListener_bsd.cpp b/src/hotspot/os/bsd/attachListener_bsd.cpp +index 9daad43dc..092b4d94a 100644 +--- a/src/hotspot/os/bsd/attachListener_bsd.cpp ++++ b/src/hotspot/os/bsd/attachListener_bsd.cpp +@@ -358,11 +358,23 @@ BsdAttachOperation* BsdAttachListener::dequeue() { + // get the credentials of the peer and check the effective uid/guid + uid_t puid; + gid_t pgid; ++#if defined(SERENITY) ++ struct ucred creds = {}; ++ socklen_t creds_size = sizeof(creds); ++ if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, &creds, &creds_size) != 0) { ++ log_debug(attach)("Failed to get peer id"); ++ ::close(s); ++ continue; ++ } ++ puid = creds.uid; ++ pgid = creds.gid; ++#else + if (::getpeereid(s, &puid, &pgid) != 0) { + log_debug(attach)("Failed to get peer id"); + ::close(s); + continue; + } ++#endif + + if (!os::Posix::matches_effective_uid_and_gid_or_root(puid, pgid)) { + log_debug(attach)("euid/egid check failed (%d/%d vs %d/%d)", puid, pgid, +diff --git a/src/hotspot/os/bsd/osThread_bsd.cpp b/src/hotspot/os/bsd/osThread_bsd.cpp +index 9eba7288f..d7164e5d5 100644 +--- a/src/hotspot/os/bsd/osThread_bsd.cpp ++++ b/src/hotspot/os/bsd/osThread_bsd.cpp +@@ -31,13 +31,17 @@ + + void OSThread::pd_initialize() { + assert(this != NULL, "check"); +-#ifdef __APPLE__ ++#if defined(__APPLE__) || defined(SERENITY) + _thread_id = 0; + #else + _thread_id = NULL; + #endif + _unique_thread_id = 0; ++#if defined(SERENITY) ++ _pthread_id = 0; ++#else + _pthread_id = NULL; ++#endif + _siginfo = NULL; + _ucontext = NULL; + _expanding_stack = 0; +diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp +index 1896c036c..4452b5e9b 100644 +--- a/src/hotspot/os/bsd/os_bsd.cpp ++++ b/src/hotspot/os/bsd/os_bsd.cpp +@@ -87,8 +87,10 @@ + # include + # include + # include ++#ifndef SERENITY + # include + # include ++#endif + # include + # include + # include +@@ -99,6 +101,12 @@ + #include + #endif + ++#if defined(SERENITY) ++#include "utilities/decoder_elf.hpp" ++#include "utilities/elfFile.hpp" ++#include ++#endif ++ + #ifdef __APPLE__ + #include + #endif +@@ -162,6 +170,9 @@ julong os::Bsd::available_memory() { + // for more info see : + // https://man.openbsd.org/sysctl.2 + void os::Bsd::print_uptime_info(outputStream* st) { ++#ifdef SERENITY ++ st->print("OS uptime: unknown"); // FIXME: Grab uptime ++#else + struct timeval boottime; + size_t len = sizeof(boottime); + int mib[2]; +@@ -173,6 +184,7 @@ void os::Bsd::print_uptime_info(outputStream* st) { + time_t currsec = time(NULL); + os::print_dhm(st, "OS uptime:", (long) difftime(currsec, bootsec)); + } ++#endif + } + + julong os::physical_memory() { +@@ -221,6 +233,10 @@ static char cpu_arch[] = "ppc"; + + + void os::Bsd::initialize_system_info() { ++#if defined (SERENITY) ++ set_processor_count(1); // FIXME ++ _physical_memory = 256 * 1024 * 1024; // FIXME ++#else + int mib[2]; + size_t len; + int cpu_val; +@@ -275,6 +291,7 @@ void os::Bsd::initialize_system_info() { + _physical_memory = MIN2(_physical_memory, (julong)limits.rlim_cur); + } + #endif ++#endif // SERENITY + } + + #ifdef __APPLE__ +@@ -363,12 +380,18 @@ void os::init_system_properties_values() { + if (pslash != NULL) { + pslash = strrchr(buf, '/'); + if (pslash != NULL) { ++#ifdef SERENITY ++ // no dir on serenity ++ *pslash = '\0'; // Get rid of /lib. ++ } ++#else + *pslash = '\0'; // Get rid of /. + pslash = strrchr(buf, '/'); + if (pslash != NULL) { + *pslash = '\0'; // Get rid of /lib. + } + } ++#endif + } + Arguments::set_java_home(buf); + if (!set_boot_path('/', ':')) { +@@ -877,6 +900,10 @@ pid_t os::Bsd::gettid() { + #else + #ifdef __NetBSD__ + retval = (pid_t) syscall(SYS__lwp_self); ++ #else ++ #ifdef SERENITY ++ retval = ::gettid(); ++ #endif + #endif + #endif + #endif +@@ -885,6 +912,7 @@ pid_t os::Bsd::gettid() { + if (retval == -1) { + return getpid(); + } ++ return retval; + } + + intx os::current_thread_id() { +@@ -942,6 +970,25 @@ bool os::address_is_in_vm(address addr) { + return false; + } + ++#ifdef SERENITY ++// We put this here so that we don't need to add an entire file just to dup this method from the linux decoder ++bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) { ++ int status; ++ char* result; ++ size_t size = (size_t)buflen; ++ ++ // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small, ++ // __cxa_demangle will call system "realloc" for additional memory, which ++ // may use different malloc/realloc mechanism that allocates 'buf'. ++ if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) { ++ jio_snprintf(buf, buflen, "%s", result); ++ // call c library's free ++ ::free(result); ++ return true; ++ } ++ return false; ++} ++#endif // SERENITY + + #define MACH_MAXSYMLEN 256 + +@@ -1013,7 +1060,7 @@ bool os::dll_address_to_library_name(address addr, char* buf, + // in case of error it checks if .dll/.so was built for the + // same architecture as Hotspot is running on + +-#ifdef __APPLE__ ++#if defined(__APPLE__) || defined(SERENITY) + void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { + #ifdef STATIC_BUILD + return os::get_default_process_handle(); +@@ -1226,7 +1273,7 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) { + return NULL; + #endif // STATIC_BUILD + } +-#endif // !__APPLE__ ++#endif // !__APPLE__ || !SERENITY + + void* os::get_default_process_handle() { + #ifdef __APPLE__ +@@ -1305,6 +1352,7 @@ int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *pa + } + + void os::get_summary_os_info(char* buf, size_t buflen) { ++#ifndef SERENITY + // These buffers are small because we want this to be brief + // and not use a lot of stack while generating the hs_err file. + char os[100]; +@@ -1342,6 +1390,10 @@ void os::get_summary_os_info(char* buf, size_t buflen) { + snprintf(buf, buflen, "%s %s, macOS %s (%s)", os, release, osproductversion, build); + } + } else ++#endif ++#else ++ const char os[] = "SerenityOS"; ++ const char release[] = "1.0-dev"; + #endif + snprintf(buf, buflen, "%s %s", os, release); + } +@@ -1369,6 +1421,7 @@ void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) { + } + + void os::get_summary_cpu_info(char* buf, size_t buflen) { ++#ifndef SERENITY + unsigned int mhz; + size_t size = sizeof(mhz); + int mib[] = { CTL_HW, HW_CPU_FREQ }; +@@ -1399,9 +1452,13 @@ void os::get_summary_cpu_info(char* buf, size_t buflen) { + } + #endif + snprintf(buf, buflen, "\"%s\" %s%s %d MHz", model, machine, emulated, mhz); ++#else ++ snprintf(buf, buflen, "%s", "FIXME: Implement CPU Info"); ++#endif + } + + void os::print_memory_info(outputStream* st) { ++#ifndef SERENITY + xsw_usage swap_usage; + size_t size = sizeof(swap_usage); + +@@ -1423,6 +1480,9 @@ void os::print_memory_info(outputStream* st) { + } + + st->cr(); ++#else ++ st->print("Memory: FIXME unknown"); ++#endif + } + + static char saved_jvm_path[MAXPATHLEN] = {0}; +@@ -1584,6 +1644,10 @@ bool os::pd_commit_memory(char* addr, size_t size, bool exec) { + } + } + #else ++ #if defined(SERENITY) ++ // FIXME: Mount location of java install with MS_WXALLOWED and MS_AXALLOWED ++ prot &= ~PROT_EXEC; ++ #endif + uintptr_t res = (uintptr_t) ::mmap(addr, size, prot, + MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0); + if (res != (uintptr_t) MAP_FAILED) { +@@ -1994,6 +2058,10 @@ OSReturn os::get_native_priority(const Thread* const thread, int *priority_ptr) + extern void report_error(char* file_name, int line_no, char* title, + char* format, ...); + ++#if defined(SERENITY) && !defined(CLK_TCK) ++#define CLK_TCK 100 ++#endif ++ + // this is called _before_ the most of global arguments have been parsed + void os::init(void) { + char dummy; // used to get a guess on initial stack address +@@ -2535,7 +2603,11 @@ bool os::is_thread_cpu_time_supported() { + // Bsd doesn't yet have a (official) notion of processor sets, + // so just return the system wide load average. + int os::loadavg(double loadavg[], int nelem) { ++#ifdef SERENITY ++ return -1; ++#else + return ::getloadavg(loadavg, nelem); ++#endif + } + + void os::pause() { +diff --git a/src/hotspot/os/bsd/os_perf_bsd.cpp b/src/hotspot/os/bsd/os_perf_bsd.cpp +index e69bfc795..4e67e2e4b 100644 +--- a/src/hotspot/os/bsd/os_perf_bsd.cpp ++++ b/src/hotspot/os/bsd/os_perf_bsd.cpp +@@ -425,6 +425,9 @@ NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() { + } + + int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const { ++#ifdef SERENITY ++ return OS_ERR; // FIXME: Get stats from Network interface daemon ++#else + size_t len; + int mib[] = {CTL_NET, PF_ROUTE, /* protocol number */ 0, /* address family */ 0, NET_RT_IFLIST2, /* NET_RT_FLAGS mask*/ 0}; + if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0) != 0) { +@@ -464,6 +467,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network + *network_interfaces = ret; + + return OS_OK; ++#endif + } + + NetworkPerformanceInterface::NetworkPerformanceInterface() { +diff --git a/src/hotspot/os_cpu/bsd_zero/bytes_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/bytes_bsd_zero.hpp +index 0da7ecc78..bd1ee9a67 100644 +--- a/src/hotspot/os_cpu/bsd_zero/bytes_bsd_zero.hpp ++++ b/src/hotspot/os_cpu/bsd_zero/bytes_bsd_zero.hpp +@@ -30,6 +30,8 @@ + + #ifdef __APPLE__ + # include ++#elif defined(SERENITY) ++# include + #else + # include + #endif +diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +index a9fda1d4b..494f073ac 100644 +--- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp ++++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +@@ -23,11 +23,15 @@ + * + */ + +-#if !defined(__APPLE__) && !defined(__NetBSD__) ++#if !defined(__APPLE__) && !defined(__NetBSD__) && !defined(SERENITY) + #include + # include /* For pthread_attr_get_np */ + #endif + ++#if defined(SERENITY) ++# include ++#endif ++ + // no precompiled headers + #include "jvm.h" + #include "asm/assembler.inline.hpp" +@@ -56,8 +60,7 @@ + #include "utilities/vmError.hpp" + + address os::current_stack_pointer() { +- address dummy = (address) &dummy; +- return dummy; ++ return (address) __builtin_frame_address(0); + } + + frame os::get_sender_for_C_frame(frame* fr) { +@@ -194,6 +197,15 @@ static void current_stack_region(address *bottom, size_t *size) { + stack_top = (address) ss.ss_sp; + stack_bytes = ss.ss_size; + stack_bottom = stack_top - stack_bytes; ++#elif defined(SERENITY) ++ uintptr_t real_stack_bottom = 0; ++ int rslt = get_stack_bounds(&real_stack_bottom, &stack_bytes); ++ ++ if (rslt < 0) ++ fatal("get_stack_bounds failed with error = " INT32_FORMAT, rslt); ++ ++ stack_bottom = (address)real_stack_bottom; ++ stack_top = stack_bottom + stack_bytes; + #else + pthread_attr_t attr; + +diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp +index 0287b73e5..101299b2f 100644 +--- a/src/hotspot/share/classfile/classLoader.cpp ++++ b/src/hotspot/share/classfile/classLoader.cpp +@@ -249,7 +249,7 @@ ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* + struct stat st; + if (os::stat(path, &st) == 0) { + // found file, open it +- int file_handle = os::open(path, 0, 0); ++ int file_handle = os::open(path, O_RDONLY, 0); + if (file_handle != -1) { + // read contents into resource array + u1* buffer = NEW_RESOURCE_ARRAY(u1, st.st_size); diff --git a/Ports/OpenJDK/patches/0005-hotspot-Update-non-BSD-native-modules-for-Serenity.patch b/Ports/OpenJDK/patches/0005-hotspot-Update-non-BSD-native-modules-for-Serenity.patch new file mode 100644 index 00000000000..420eff12824 --- /dev/null +++ b/Ports/OpenJDK/patches/0005-hotspot-Update-non-BSD-native-modules-for-Serenity.patch @@ -0,0 +1,268 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Timur Sultanov +Date: Sun, 12 Jun 2022 13:55:07 -0600 +Subject: [PATCH] hotspot: Update non-BSD native modules for Serenity + +Co-Authored-By: Andrew Kaster +--- + src/hotspot/os/posix/os_posix.cpp | 23 ++++++++++++++++++- + src/hotspot/os/posix/signals_posix.cpp | 12 ++++++++++ + src/hotspot/share/runtime/os.cpp | 6 ++++- + src/hotspot/share/runtime/os.hpp | 2 +- + src/hotspot/share/runtime/semaphore.hpp | 2 +- + .../share/utilities/globalDefinitions.hpp | 4 ++++ + .../share/utilities/globalDefinitions_gcc.hpp | 6 ++--- + src/hotspot/share/utilities/ostream.cpp | 2 +- + 8 files changed, 49 insertions(+), 8 deletions(-) + +diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp +index 9eb1fcbcc..0676cb83d 100644 +--- a/src/hotspot/os/posix/os_posix.cpp ++++ b/src/hotspot/os/posix/os_posix.cpp +@@ -65,7 +65,9 @@ + #include + #include + #include ++#ifndef SERENITY + #include ++#endif + + #ifdef __APPLE__ + #include +@@ -272,7 +274,12 @@ static int util_posix_fallocate(int fd, off_t offset, off_t len) { + } + return -1; + #else ++#ifndef SERENITY + return posix_fallocate(fd, offset, len); ++#else ++ // YOLO ++ return 0; ++#endif + #endif + } + +@@ -418,6 +425,7 @@ void os::Posix::print_load_average(outputStream* st) { + // unfortunately it does not work on macOS and Linux because the utx chain has no entry + // for reboot at least on my test machines + void os::Posix::print_uptime_info(outputStream* st) { ++#ifndef SERENITY + int bootsec = -1; + int currsec = time(NULL); + struct utmpx* ent; +@@ -432,6 +440,9 @@ void os::Posix::print_uptime_info(outputStream* st) { + if (bootsec != -1) { + os::print_dhm(st, "OS uptime:", (long) (currsec-bootsec)); + } ++#else ++ st->print("OS uptime: not implemented"); ++#endif + } + + static void print_rlimit(outputStream* st, const char* msg, +@@ -470,7 +481,9 @@ void os::Posix::print_rlimit_info(outputStream* st) { + + print_rlimit(st, ", THREADS", RLIMIT_THREADS); + #else ++#ifndef SERENITY + print_rlimit(st, ", NPROC", RLIMIT_NPROC); ++#endif + #endif + + print_rlimit(st, ", NOFILE", RLIMIT_NOFILE); +@@ -638,7 +651,11 @@ void os::dll_unload(void *lib) { + } + + jlong os::lseek(int fd, jlong offset, int whence) { ++#ifdef SERENITY ++ return (jlong) ::lseek(fd, offset, whence); ++#else + return (jlong) BSD_ONLY(::lseek) NOT_BSD(::lseek64)(fd, offset, whence); ++#endif + } + + int os::fsync(int fd) { +@@ -646,7 +663,11 @@ int os::fsync(int fd) { + } + + int os::ftruncate(int fd, jlong length) { +- return BSD_ONLY(::ftruncate) NOT_BSD(::ftruncate64)(fd, length); ++#ifdef SERENITY ++ return ::ftruncate(fd, length); ++#else ++ return BSD_ONLY(::ftruncate) NOT_BSD(::ftruncate64)(fd, length); ++#endif + } + + const char* os::get_current_directory(char *buf, size_t buflen) { +diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp +index 2c020a794..9f3316f5b 100644 +--- a/src/hotspot/os/posix/signals_posix.cpp ++++ b/src/hotspot/os/posix/signals_posix.cpp +@@ -552,6 +552,8 @@ public: + #define JVM_HANDLE_XXX_SIGNAL JVM_handle_aix_signal + #elif defined(LINUX) + #define JVM_HANDLE_XXX_SIGNAL JVM_handle_linux_signal ++#elif defined(SERENITY) ++#define JVM_HANDLE_XXX_SIGNAL JVM_handle_serenity_signal + #else + #error who are you? + #endif +@@ -933,8 +935,10 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t + { SIGFPE, FPE_FLTRES, "FPE_FLTRES", "Floating-point inexact result." }, + { SIGFPE, FPE_FLTINV, "FPE_FLTINV", "Invalid floating-point operation." }, + { SIGFPE, FPE_FLTSUB, "FPE_FLTSUB", "Subscript out of range." }, ++#ifndef SERENITY + { SIGSEGV, SEGV_MAPERR, "SEGV_MAPERR", "Address not mapped to object." }, + { SIGSEGV, SEGV_ACCERR, "SEGV_ACCERR", "Invalid permissions for mapped object." }, ++#endif + #if defined(AIX) + // no explanation found what keyerr would be + { SIGSEGV, SEGV_KEYERR, "SEGV_KEYERR", "key error" }, +@@ -942,11 +946,13 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t + #if defined(IA64) && !defined(AIX) + { SIGSEGV, SEGV_PSTKOVF, "SEGV_PSTKOVF", "Paragraph stack overflow" }, + #endif ++#ifndef SERENITY + { SIGBUS, BUS_ADRALN, "BUS_ADRALN", "Invalid address alignment." }, + { SIGBUS, BUS_ADRERR, "BUS_ADRERR", "Nonexistent physical address." }, + { SIGBUS, BUS_OBJERR, "BUS_OBJERR", "Object-specific hardware error." }, + { SIGTRAP, TRAP_BRKPT, "TRAP_BRKPT", "Process breakpoint." }, + { SIGTRAP, TRAP_TRACE, "TRAP_TRACE", "Process trace trap." }, ++#endif + { SIGCHLD, CLD_EXITED, "CLD_EXITED", "Child has exited." }, + { SIGCHLD, CLD_KILLED, "CLD_KILLED", "Child has terminated abnormally and did not create a core file." }, + { SIGCHLD, CLD_DUMPED, "CLD_DUMPED", "Child has terminated abnormally and created a core file." }, +@@ -967,11 +973,17 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t + const struct { + int code; const char* s_code; const char* s_desc; + } t2 [] = { ++ { SIGTRAP, "SIGTRAP", "SIGTRAP FIXME" }, ++ { SIGBUS, "SIGBUS", "SIGBUS FIXME" }, ++ { SIGILL, "SIGILL", "Illegal opcode FIXME." }, ++ { SIGSEGV, "SIGSEGV", "SIGSEGV FIXME" }, ++#ifndef SERENITY + { SI_USER, "SI_USER", "Signal sent by kill()." }, + { SI_QUEUE, "SI_QUEUE", "Signal sent by the sigqueue()." }, + { SI_TIMER, "SI_TIMER", "Signal generated by expiration of a timer set by timer_settime()." }, + { SI_ASYNCIO, "SI_ASYNCIO", "Signal generated by completion of an asynchronous I/O request." }, + { SI_MESGQ, "SI_MESGQ", "Signal generated by arrival of a message on an empty message queue." }, ++#endif + // Linux specific + #ifdef SI_TKILL + { SI_TKILL, "SI_TKILL", "Signal sent by tkill (pthread_kill)" }, +diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp +index 9b8e667f9..4e9a5f0e6 100644 +--- a/src/hotspot/share/runtime/os.cpp ++++ b/src/hotspot/share/runtime/os.cpp +@@ -155,7 +155,7 @@ char* os::iso8601_time(jlong milliseconds_since_19700101, char* buffer, size_t b + // No offset when dealing with UTC + time_t UTC_to_local = 0; + if (!utc) { +-#if defined(_ALLBSD_SOURCE) || defined(_GNU_SOURCE) ++#if (defined(_ALLBSD_SOURCE) || defined(_GNU_SOURCE)) && !defined(SERENITY) + UTC_to_local = -(time_struct.tm_gmtoff); + #elif defined(_WINDOWS) + long zone; +@@ -1502,6 +1502,7 @@ size_t os::page_size_for_region_unaligned(size_t region_size, size_t min_pages) + } + + static const char* errno_to_string (int e, bool short_text) { ++#ifndef SERENITY + #define ALL_SHARED_ENUMS(X) \ + X(E2BIG, "Argument list too long") \ + X(EACCES, "Permission denied") \ +@@ -1579,6 +1580,9 @@ static const char* errno_to_string (int e, bool short_text) { + X(ETXTBSY, "Text file busy") \ + X(EWOULDBLOCK, "Operation would block") \ + X(EXDEV, "Cross-device link") ++#else ++ #define ALL_SHARED_ENUMS(X) ENUMERATE_ERRNO_CODES(X) ++#endif + + #define DEFINE_ENTRY(e, text) { e, #e, text }, + +diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp +index 7eaaa9db9..50591f707 100644 +--- a/src/hotspot/share/runtime/os.hpp ++++ b/src/hotspot/share/runtime/os.hpp +@@ -468,7 +468,7 @@ class os: AllStatic { + // need special-case handling of the primordial thread if it attaches + // to the VM. + static bool is_primordial_thread(void) +-#if defined(_WINDOWS) || defined(BSD) ++#if defined(_WINDOWS) || defined(BSD) || defined(SERENITY) + // No way to identify the primordial thread. + { return false; } + #else +diff --git a/src/hotspot/share/runtime/semaphore.hpp b/src/hotspot/share/runtime/semaphore.hpp +index 0e19c101d..afc007e7a 100644 +--- a/src/hotspot/share/runtime/semaphore.hpp ++++ b/src/hotspot/share/runtime/semaphore.hpp +@@ -28,7 +28,7 @@ + #include "memory/allocation.hpp" + #include "utilities/globalDefinitions.hpp" + +-#if defined(LINUX) || defined(AIX) ++#if defined(LINUX) || defined(AIX) || defined(SERENITY) + # include "semaphore_posix.hpp" + #elif defined(BSD) + # include "semaphore_bsd.hpp" +diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp +index 082a3272c..65157b52e 100644 +--- a/src/hotspot/share/utilities/globalDefinitions.hpp ++++ b/src/hotspot/share/utilities/globalDefinitions.hpp +@@ -1209,5 +1209,9 @@ template bool primitive_equals(const K& k0, const K& k1) { + return k0 == k1; + } + ++#ifdef SERENITY ++#define MAX2(a,b) ((a)>(b)?(a):(b)) ++#define alloca(p) __builtin_alloca(p) ++#endif + + #endif // SHARE_UTILITIES_GLOBALDEFINITIONS_HPP +diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +index 30cca9ee7..7cac45142 100644 +--- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp ++++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +@@ -48,7 +48,7 @@ + #include + #include + +-#if defined(LINUX) || defined(_ALLBSD_SOURCE) ++#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(SERENITY) + #include + #include + #ifndef __OpenBSD__ +@@ -79,7 +79,7 @@ + #define NULL_WORD NULL + #endif + +-#if !defined(LINUX) && !defined(_ALLBSD_SOURCE) ++#if !defined(LINUX) && !defined(_ALLBSD_SOURCE) && !defined(SERENITY) + // Compiler-specific primitive types + typedef unsigned short uint16_t; + #ifndef _UINT32_T +@@ -111,7 +111,7 @@ typedef uint64_t julong; + // checking for nanness + #if defined(__APPLE__) + inline int g_isnan(double f) { return isnan(f); } +-#elif defined(LINUX) || defined(_ALLBSD_SOURCE) ++#elif defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(SERENITY) + inline int g_isnan(float f) { return isnan(f); } + inline int g_isnan(double f) { return isnan(f); } + #else +diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp +index 04995064f..e25c3a429 100644 +--- a/src/hotspot/share/utilities/ostream.cpp ++++ b/src/hotspot/share/utilities/ostream.cpp +@@ -1065,7 +1065,7 @@ bufferedStream::~bufferedStream() { + + #ifndef PRODUCT + +-#if defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE) ++#if defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE) || defined(SERENITY) + #include + #include + #include diff --git a/Ports/OpenJDK/patches/0006-Add-serenity-specific-modules-to-java.base-and-jdk.a.patch b/Ports/OpenJDK/patches/0006-Add-serenity-specific-modules-to-java.base-and-jdk.a.patch new file mode 100644 index 00000000000..eff5bcc8818 --- /dev/null +++ b/Ports/OpenJDK/patches/0006-Add-serenity-specific-modules-to-java.base-and-jdk.a.patch @@ -0,0 +1,2394 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Timur Sultanov +Date: Sun, 12 Jun 2022 15:58:40 -0600 +Subject: [PATCH] Add serenity-specific modules to java.base and jdk.attach + +It would be nice to re-direct the build to the same files *BSD use, but +for now we've got our own copy + +Co-Authored-By: Andrew Kaster +--- + .../DefaultAsynchronousChannelProvider.java | 47 ++ + .../sun/nio/ch/DefaultSelectorProvider.java | 54 ++ + .../SerenityAsynchronousChannelProvider.java | 91 +++ + .../classes/sun/nio/ch/SerenityPollPort.java | 538 ++++++++++++++++++ + .../sun/nio/fs/DefaultFileSystemProvider.java | 53 ++ + .../classes/sun/nio/fs/SerenityFileStore.java | 105 ++++ + .../sun/nio/fs/SerenityFileSystem.java | 94 +++ + .../nio/fs/SerenityFileSystemProvider.java | 52 ++ + .../sun/nio/fs/SerenityNativeDispatcher.java | 49 ++ + .../serenity/native/libnet/serenity_close.c | 458 +++++++++++++++ + .../sun/tools/attach/AttachProviderImpl.java | 82 +++ + .../sun/tools/attach/VirtualMachineImpl.java | 326 +++++++++++ + .../native/libattach/VirtualMachineImpl.c | 328 +++++++++++ + 13 files changed, 2277 insertions(+) + create mode 100644 src/java.base/serenity/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java + create mode 100644 src/java.base/serenity/classes/sun/nio/ch/DefaultSelectorProvider.java + create mode 100644 src/java.base/serenity/classes/sun/nio/ch/SerenityAsynchronousChannelProvider.java + create mode 100644 src/java.base/serenity/classes/sun/nio/ch/SerenityPollPort.java + create mode 100644 src/java.base/serenity/classes/sun/nio/fs/DefaultFileSystemProvider.java + create mode 100644 src/java.base/serenity/classes/sun/nio/fs/SerenityFileStore.java + create mode 100644 src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystem.java + create mode 100644 src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystemProvider.java + create mode 100644 src/java.base/serenity/classes/sun/nio/fs/SerenityNativeDispatcher.java + create mode 100644 src/java.base/serenity/native/libnet/serenity_close.c + create mode 100644 src/jdk.attach/serenity/classes/sun/tools/attach/AttachProviderImpl.java + create mode 100644 src/jdk.attach/serenity/classes/sun/tools/attach/VirtualMachineImpl.java + create mode 100644 src/jdk.attach/serenity/native/libattach/VirtualMachineImpl.c + +diff --git a/src/java.base/serenity/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/src/java.base/serenity/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java +new file mode 100644 +index 000000000..7a7bfe089 +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java +@@ -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 SerenityAsynchronousChannelProvider(); ++ } ++} +diff --git a/src/java.base/serenity/classes/sun/nio/ch/DefaultSelectorProvider.java b/src/java.base/serenity/classes/sun/nio/ch/DefaultSelectorProvider.java +new file mode 100644 +index 000000000..86d3ade19 +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/ch/DefaultSelectorProvider.java +@@ -0,0 +1,54 @@ ++/* ++ * Copyright (c) 2015, 2021, 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 = PollSelectorProvider::new; ++ INSTANCE = AccessController.doPrivileged(pa); ++ } ++ ++ /** ++ * Prevent instantiation. ++ */ ++ private DefaultSelectorProvider() { } ++ ++ /** ++ * Returns the default SelectorProvider implementation. ++ */ ++ public static SelectorProviderImpl get() { ++ return INSTANCE; ++ } ++} +\ No newline at end of file +diff --git a/src/java.base/serenity/classes/sun/nio/ch/SerenityAsynchronousChannelProvider.java b/src/java.base/serenity/classes/sun/nio/ch/SerenityAsynchronousChannelProvider.java +new file mode 100644 +index 000000000..2daa2cca4 +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/ch/SerenityAsynchronousChannelProvider.java +@@ -0,0 +1,91 @@ ++/* ++ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2012 SAP SE. 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 SerenityAsynchronousChannelProvider ++ extends AsynchronousChannelProvider ++{ ++ private static volatile SerenityPollPort defaultPort; ++ ++ private SerenityPollPort defaultEventPort() throws IOException { ++ if (defaultPort == null) { ++ synchronized (SerenityAsynchronousChannelProvider.class) { ++ if (defaultPort == null) { ++ defaultPort = new SerenityPollPort(this, ThreadPool.getDefault()).start(); ++ } ++ } ++ } ++ return defaultPort; ++ } ++ ++ public SerenityAsynchronousChannelProvider() { ++ } ++ ++ @Override ++ public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory) ++ throws IOException ++ { ++ return new SerenityPollPort(this, ThreadPool.create(nThreads, factory)).start(); ++ } ++ ++ @Override ++ public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) ++ throws IOException ++ { ++ return new SerenityPollPort(this, ThreadPool.wrap(executor, initialSize)).start(); ++ } ++ ++ private Port toPort(AsynchronousChannelGroup group) throws IOException { ++ if (group == null) { ++ return defaultEventPort(); ++ } else { ++ if (!(group instanceof SerenityPollPort)) ++ throw new IllegalChannelGroupException(); ++ return (Port)group; ++ } ++ } ++ ++ @Override ++ public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) ++ throws IOException ++ { ++ return new UnixAsynchronousServerSocketChannelImpl(toPort(group)); ++ } ++ ++ @Override ++ public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) ++ throws IOException ++ { ++ return new UnixAsynchronousSocketChannelImpl(toPort(group)); ++ } ++} +diff --git a/src/java.base/serenity/classes/sun/nio/ch/SerenityPollPort.java b/src/java.base/serenity/classes/sun/nio/ch/SerenityPollPort.java +new file mode 100644 +index 000000000..0894d1814 +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/ch/SerenityPollPort.java +@@ -0,0 +1,538 @@ ++/* ++ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2012 SAP SE. 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.io.IOException; ++import java.util.HashSet; ++import java.util.Iterator; ++import java.util.concurrent.ArrayBlockingQueue; ++import java.util.concurrent.RejectedExecutionException; ++import java.util.concurrent.atomic.AtomicInteger; ++import java.util.concurrent.locks.ReentrantLock; ++import jdk.internal.misc.Unsafe; ++ ++/** ++ * AsynchronousChannelGroup implementation based on the AIX pollset framework. ++ */ ++final class SerenityPollPort ++ extends Port ++{ ++ private static final Unsafe unsafe = Unsafe.getUnsafe(); ++ ++ static { ++ IOUtil.load(); ++ init(); ++ } ++ ++ /** ++ * struct pollfd { ++ * int fd; ++ * short events; ++ * short revents; ++ * } ++ */ ++ private static final int SIZEOF_POLLFD = eventSize(); ++ private static final int OFFSETOF_EVENTS = eventsOffset(); ++ private static final int OFFSETOF_REVENTS = reventsOffset(); ++ private static final int OFFSETOF_FD = fdOffset(); ++ ++ // opcodes ++ private static final int PS_ADD = 0x0; ++ private static final int PS_MOD = 0x1; ++ private static final int PS_DELETE = 0x2; ++ ++ // maximum number of events to poll at a time ++ private static final int MAX_POLL_EVENTS = 512; ++ ++ // pollset ID ++ private final int pollset; ++ ++ // true if port is closed ++ private boolean closed; ++ ++ // socket pair used for wakeup ++ private final int sp[]; ++ ++ // socket pair used to indicate pending pollsetCtl calls ++ // Background info: pollsetCtl blocks when another thread is in a pollsetPoll call. ++ private final int ctlSp[]; ++ ++ // number of wakeups pending ++ private final AtomicInteger wakeupCount = new AtomicInteger(); ++ ++ // address of the poll array passed to pollset_poll ++ private final long address; ++ ++ // encapsulates an event for a channel ++ static class Event { ++ final PollableChannel channel; ++ final int events; ++ ++ Event(PollableChannel channel, int events) { ++ this.channel = channel; ++ this.events = events; ++ } ++ ++ PollableChannel channel() { return channel; } ++ int events() { return events; } ++ } ++ ++ // queue of events for cases that a polling thread dequeues more than one ++ // event ++ private final ArrayBlockingQueue queue; ++ private final Event NEED_TO_POLL = new Event(null, 0); ++ private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0); ++ private final Event CONTINUE_AFTER_CTL_EVENT = new Event(null, 0); ++ ++ // encapsulates a pollset control event for a file descriptor ++ static class ControlEvent { ++ final int fd; ++ final int events; ++ final boolean removeOnly; ++ int error = 0; ++ ++ ControlEvent(int fd, int events, boolean removeOnly) { ++ this.fd = fd; ++ this.events = events; ++ this.removeOnly = removeOnly; ++ } ++ ++ int fd() { return fd; } ++ int events() { return events; } ++ boolean removeOnly() { return removeOnly; } ++ int error() { return error; } ++ void setError(int error) { this.error = error; } ++ } ++ ++ // queue of control events that need to be processed ++ // (this object is also used for synchronization) ++ private final HashSet controlQueue = new HashSet(); ++ ++ // lock used to check whether a poll operation is ongoing ++ private final ReentrantLock controlLock = new ReentrantLock(); ++ ++ SerenityPollPort(AsynchronousChannelProvider provider, ThreadPool pool) ++ throws IOException ++ { ++ super(provider, pool); ++ ++ // open pollset ++ this.pollset = pollsetCreate(); ++ ++ // create socket pair for wakeup mechanism ++ int[] sv = new int[2]; ++ try { ++ socketpair(sv); ++ // register one end with pollset ++ pollsetCtl(pollset, PS_ADD, sv[0], Net.POLLIN); ++ } catch (IOException x) { ++ pollsetDestroy(pollset); ++ throw x; ++ } ++ this.sp = sv; ++ ++ // create socket pair for pollset control mechanism ++ sv = new int[2]; ++ try { ++ socketpair(sv); ++ // register one end with pollset ++ pollsetCtl(pollset, PS_ADD, sv[0], Net.POLLIN); ++ } catch (IOException x) { ++ pollsetDestroy(pollset); ++ throw x; ++ } ++ this.ctlSp = sv; ++ ++ // allocate the poll array ++ this.address = allocatePollArray(MAX_POLL_EVENTS); ++ ++ // create the queue and offer the special event to ensure that the first ++ // threads polls ++ this.queue = new ArrayBlockingQueue(MAX_POLL_EVENTS); ++ this.queue.offer(NEED_TO_POLL); ++ } ++ ++ SerenityPollPort start() { ++ startThreads(new EventHandlerTask()); ++ return this; ++ } ++ ++ /** ++ * Release all resources ++ */ ++ private void implClose() { ++ synchronized (this) { ++ if (closed) ++ return; ++ closed = true; ++ } ++ freePollArray(address); ++ close0(sp[0]); ++ close0(sp[1]); ++ close0(ctlSp[0]); ++ close0(ctlSp[1]); ++ pollsetDestroy(pollset); ++ } ++ ++ private void wakeup() { ++ if (wakeupCount.incrementAndGet() == 1) { ++ // write byte to socketpair to force wakeup ++ try { ++ interrupt(sp[1]); ++ } 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 interrupt to each thread ++ while (nThreads-- > 0) { ++ wakeup(); ++ } ++ } ++ } ++ ++ // invoke by clients to register a file descriptor ++ @Override ++ void startPoll(int fd, int events) { ++ queueControlEvent(new ControlEvent(fd, events, false)); ++ } ++ ++ // Callback method for implementations that need special handling when fd is removed ++ @Override ++ protected void preUnregister(int fd) { ++ queueControlEvent(new ControlEvent(fd, 0, true)); ++ } ++ ++ // Add control event into queue and wait for completion. ++ // In case the control lock is free, this method also tries to apply the control change directly. ++ private void queueControlEvent(ControlEvent ev) { ++ // pollsetCtl blocks when a poll call is ongoing. This is very probable. ++ // Therefore we let the polling thread do the pollsetCtl call. ++ synchronized (controlQueue) { ++ controlQueue.add(ev); ++ // write byte to socketpair to force wakeup ++ try { ++ interrupt(ctlSp[1]); ++ } catch (IOException x) { ++ throw new AssertionError(x); ++ } ++ do { ++ // Directly empty queue if no poll call is ongoing. ++ if (controlLock.tryLock()) { ++ try { ++ processControlQueue(); ++ } finally { ++ controlLock.unlock(); ++ } ++ } else { ++ try { ++ // Do not starve in case the polling thread returned before ++ // we could write to ctlSp[1] but the polling thread did not ++ // release the control lock until we checked. Therefore, use ++ // a timed wait for the time being. ++ controlQueue.wait(100); ++ } catch (InterruptedException e) { ++ // ignore exception and try again ++ } ++ } ++ } while (controlQueue.contains(ev)); ++ } ++ if (ev.error() != 0) { ++ throw new AssertionError(); ++ } ++ } ++ ++ // Process all events currently stored in the control queue. ++ private void processControlQueue() { ++ synchronized (controlQueue) { ++ // TODO: this is ripped straight out of AIX implementation, who knows if it will work for Serenity ++ Iterator iter = controlQueue.iterator(); ++ while (iter.hasNext()) { ++ ControlEvent ev = iter.next(); ++ pollsetCtl(pollset, PS_DELETE, ev.fd(), 0); ++ if (!ev.removeOnly()) { ++ ev.setError(pollsetCtl(pollset, PS_MOD, ev.fd(), ev.events())); ++ } ++ iter.remove(); ++ } ++ controlQueue.notifyAll(); ++ } ++ } ++ ++ /* ++ * Task to process events from pollset and dispatch to the channel's ++ * onEvent handler. ++ * ++ * Events are retreived from pollset in batch and offered to a BlockingQueue ++ * where they are consumed by handler threads. A special "NEED_TO_POLL" ++ * event is used to signal one consumer to re-poll when all events have ++ * been consumed. ++ */ ++ private class EventHandlerTask implements Runnable { ++ private Event poll() throws IOException { ++ try { ++ for (;;) { ++ int n; ++ controlLock.lock(); ++ try { ++ n = pollsetPoll(pollset, address, MAX_POLL_EVENTS); ++ } finally { ++ controlLock.unlock(); ++ } ++ /* ++ * 'n' events have been read. Here we map them to their ++ * corresponding channel in batch and queue n-1 so that ++ * they can be handled by other handler threads. The last ++ * event is handled by this thread (and so is not queued). ++ */ ++ fdToChannelLock.readLock().lock(); ++ try { ++ while (n-- > 0) { ++ long eventAddress = getEvent(address, n); ++ int fd = getDescriptor(eventAddress); ++ ++ // To emulate one shot semantic we need to remove ++ // the file descriptor here. ++ if (fd != sp[0] && fd != ctlSp[0]) { ++ synchronized (controlQueue) { ++ pollsetCtl(pollset, PS_DELETE, fd, 0); ++ } ++ } ++ ++ // wakeup ++ if (fd == sp[0]) { ++ if (wakeupCount.decrementAndGet() == 0) { ++ // no more wakeups so drain pipe ++ drain1(sp[0]); ++ } ++ ++ // queue special event if there are more events ++ // to handle. ++ if (n > 0) { ++ queue.offer(EXECUTE_TASK_OR_SHUTDOWN); ++ continue; ++ } ++ return EXECUTE_TASK_OR_SHUTDOWN; ++ } ++ ++ // wakeup to process control event ++ if (fd == ctlSp[0]) { ++ synchronized (controlQueue) { ++ drain1(ctlSp[0]); ++ processControlQueue(); ++ } ++ if (n > 0) { ++ continue; ++ } ++ return CONTINUE_AFTER_CTL_EVENT; ++ } ++ ++ PollableChannel channel = fdToChannel.get(fd); ++ if (channel != null) { ++ int events = getRevents(eventAddress); ++ Event ev = new Event(channel, events); ++ ++ // n-1 events are queued; This thread handles ++ // the last one except for the wakeup ++ if (n > 0) { ++ queue.offer(ev); ++ } else { ++ return ev; ++ } ++ } ++ } ++ } finally { ++ fdToChannelLock.readLock().unlock(); ++ } ++ } ++ } finally { ++ // to ensure that some thread will poll when all events have ++ // been consumed ++ queue.offer(NEED_TO_POLL); ++ } ++ } ++ ++ public void run() { ++ Invoker.GroupAndInvokeCount myGroupAndInvokeCount = ++ Invoker.getGroupAndInvokeCount(); ++ final boolean isPooledThread = (myGroupAndInvokeCount != null); ++ boolean replaceMe = false; ++ Event ev; ++ try { ++ for (;;) { ++ // reset invoke count ++ if (isPooledThread) ++ myGroupAndInvokeCount.resetInvokeCount(); ++ ++ try { ++ replaceMe = false; ++ ev = queue.take(); ++ ++ // no events and this thread has been "selected" to ++ // poll for more. ++ if (ev == NEED_TO_POLL) { ++ try { ++ ev = poll(); ++ } catch (IOException x) { ++ x.printStackTrace(); ++ return; ++ } ++ } ++ } catch (InterruptedException x) { ++ continue; ++ } ++ ++ // contine after we processed a control event ++ if (ev == CONTINUE_AFTER_CTL_EVENT) { ++ continue; ++ } ++ ++ // handle wakeup to execute task or shutdown ++ if (ev == EXECUTE_TASK_OR_SHUTDOWN) { ++ Runnable task = pollTask(); ++ if (task == null) { ++ // shutdown request ++ return; ++ } ++ // run task (may throw error/exception) ++ replaceMe = true; ++ task.run(); ++ continue; ++ } ++ ++ // process event ++ try { ++ ev.channel().onEvent(ev.events(), isPooledThread); ++ } catch (Error x) { ++ replaceMe = true; throw x; ++ } catch (RuntimeException x) { ++ replaceMe = true; throw x; ++ } ++ } ++ } finally { ++ // last handler to exit when shutdown releases resources ++ int remaining = threadExit(this, replaceMe); ++ if (remaining == 0 && isShutdown()) { ++ implClose(); ++ } ++ } ++ } ++ } ++ ++ /** ++ * Allocates a poll array to handle up to {@code count} events. ++ */ ++ private static long allocatePollArray(int count) { ++ return unsafe.allocateMemory(count * SIZEOF_POLLFD); ++ } ++ ++ /** ++ * Free a poll array ++ */ ++ private static void freePollArray(long address) { ++ unsafe.freeMemory(address); ++ } ++ ++ /** ++ * Returns event[i]; ++ */ ++ private static long getEvent(long address, int i) { ++ return address + (SIZEOF_POLLFD*i); ++ } ++ ++ /** ++ * Returns event->fd ++ */ ++ private static int getDescriptor(long eventAddress) { ++ return unsafe.getInt(eventAddress + OFFSETOF_FD); ++ } ++ ++ /** ++ * Returns event->events ++ */ ++ private static int getEvents(long eventAddress) { ++ return unsafe.getChar(eventAddress + OFFSETOF_EVENTS); ++ } ++ ++ /** ++ * Returns event->revents ++ */ ++ private static int getRevents(long eventAddress) { ++ return unsafe.getChar(eventAddress + OFFSETOF_REVENTS); ++ } ++ ++ // -- Native methods -- ++ ++ private static native void init(); ++ ++ private static native int eventSize(); ++ ++ private static native int eventsOffset(); ++ ++ private static native int reventsOffset(); ++ ++ private static native int fdOffset(); ++ ++ private static native int pollsetCreate() throws IOException; ++ ++ private static native int pollsetCtl(int pollset, int opcode, int fd, int events); ++ ++ private static native int pollsetPoll(int pollset, long pollAddress, int numfds) ++ throws IOException; ++ ++ private static native void pollsetDestroy(int pollset); ++ ++ private static native void socketpair(int[] sv) throws IOException; ++ ++ private static native void interrupt(int fd) throws IOException; ++ ++ private static native void drain1(int fd) throws IOException; ++ ++ private static native void close0(int fd); ++} +diff --git a/src/java.base/serenity/classes/sun/nio/fs/DefaultFileSystemProvider.java b/src/java.base/serenity/classes/sun/nio/fs/DefaultFileSystemProvider.java +new file mode 100644 +index 000000000..b24f3de01 +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/fs/DefaultFileSystemProvider.java +@@ -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 SerenityFileSystemProvider INSTANCE ++ = new SerenityFileSystemProvider(); ++ ++ private DefaultFileSystemProvider() { } ++ ++ /** ++ * Returns the platform's default file system provider. ++ */ ++ public static SerenityFileSystemProvider instance() { ++ return INSTANCE; ++ } ++ ++ /** ++ * Returns the platform's default file system. ++ */ ++ public static FileSystem theFileSystem() { ++ return INSTANCE.theFileSystem(); ++ } ++} +diff --git a/src/java.base/serenity/classes/sun/nio/fs/SerenityFileStore.java b/src/java.base/serenity/classes/sun/nio/fs/SerenityFileStore.java +new file mode 100644 +index 000000000..3f408ec9b +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/fs/SerenityFileStore.java +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013 SAP SE. 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.util.*; ++import java.io.IOException; ++ ++/** ++ * AIX implementation of FileStore ++ */ ++ ++class SerenityFileStore ++ extends UnixFileStore ++{ ++ ++ SerenityFileStore(UnixPath file) throws IOException { ++ super(file); ++ } ++ ++ SerenityFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException { ++ super(fs, entry); ++ } ++ ++ /** ++ * Finds, and returns, the mount entry for the file system where the file ++ * resides. ++ */ ++ @Override ++ UnixMountEntry findMountEntry() throws IOException { ++ SerenityFileSystem fs = (SerenityFileSystem)file().getFileSystem(); ++ ++ // step 1: get realpath ++ UnixPath path = null; ++ try { ++ byte[] rp = UnixNativeDispatcher.realpath(file()); ++ path = new UnixPath(fs, rp); ++ } catch (UnixException x) { ++ x.rethrowAsIOException(file()); ++ } ++ ++ // step 2: find mount point ++ UnixPath parent = path.getParent(); ++ while (parent != null) { ++ UnixFileAttributes attrs = null; ++ try { ++ attrs = UnixFileAttributes.get(parent, true); ++ } catch (UnixException x) { ++ x.rethrowAsIOException(parent); ++ } ++ if (attrs.dev() != dev()) ++ break; ++ path = parent; ++ parent = parent.getParent(); ++ } ++ ++ // step 3: lookup mounted file systems ++ byte[] dir = path.asByteArray(); ++ for (UnixMountEntry entry: fs.getMountEntries()) { ++ if (Arrays.equals(dir, entry.dir())) ++ return entry; ++ } ++ ++ throw new IOException("Mount point not found"); ++ } ++ ++ @Override ++ protected boolean isExtendedAttributesEnabled(UnixPath path) { ++ return false; ++ } ++ ++ @Override ++ public boolean supportsFileAttributeView(Class type) { ++ return super.supportsFileAttributeView(type); ++ } ++ ++ @Override ++ public boolean supportsFileAttributeView(String name) { ++ return super.supportsFileAttributeView(name); ++ } ++} +diff --git a/src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystem.java b/src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystem.java +new file mode 100644 +index 000000000..bee588a7e +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystem.java +@@ -0,0 +1,94 @@ ++/* ++ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013 SAP SE. 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.io.IOException; ++import java.util.*; ++import static sun.nio.fs.SerenityNativeDispatcher.*; ++ ++/** ++ * AIX implementation of FileSystem ++ */ ++ ++class SerenityFileSystem extends UnixFileSystem { ++ ++ SerenityFileSystem(UnixFileSystemProvider provider, String dir) { ++ super(provider, dir); ++ } ++ ++ @Override ++ public WatchService newWatchService() ++ throws IOException ++ { ++ 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(UnixFileSystem.standardFileAttributeViews()); ++ return Collections.unmodifiableSet(result); ++ } ++ } ++ ++ @Override ++ public Set supportedFileAttributeViews() { ++ return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews; ++ } ++ ++ @Override ++ void copyNonPosixAttributes(int ofd, int nfd) { ++ // TODO: Implement if needed. ++ } ++ ++ /** ++ * Returns object to iterate over the mount entries returned by mntctl ++ */ ++ @Override ++ Iterable getMountEntries() { ++ UnixMountEntry[] entries = null; ++ try { ++ entries = getmntctl(); ++ } catch (UnixException x) { ++ // nothing we can do ++ } ++ if (entries == null) { ++ return Collections.emptyList(); ++ } ++ return Arrays.asList(entries); ++ } ++ ++ @Override ++ FileStore getFileStore(UnixMountEntry entry) throws IOException { ++ return new SerenityFileStore(this, entry); ++ } ++} +diff --git a/src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystemProvider.java b/src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystemProvider.java +new file mode 100644 +index 000000000..8582190af +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/fs/SerenityFileSystemProvider.java +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013 SAP SE. 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.io.IOException; ++ ++/** ++ * Serenity implementation of FileSystemProvider ++ */ ++ ++class SerenityFileSystemProvider extends UnixFileSystemProvider { ++ public SerenityFileSystemProvider() { ++ super(); ++ } ++ ++ @Override ++ SerenityFileSystem newFileSystem(String dir) { ++ return new SerenityFileSystem(this, dir); ++ } ++ ++ /** ++ * @see sun.nio.fs.UnixFileSystemProvider#getFileStore(sun.nio.fs.UnixPath) ++ */ ++ @Override ++ SerenityFileStore getFileStore(UnixPath path) throws IOException { ++ return new SerenityFileStore(path); ++ } ++} +diff --git a/src/java.base/serenity/classes/sun/nio/fs/SerenityNativeDispatcher.java b/src/java.base/serenity/classes/sun/nio/fs/SerenityNativeDispatcher.java +new file mode 100644 +index 000000000..7c50b719c +--- /dev/null ++++ b/src/java.base/serenity/classes/sun/nio/fs/SerenityNativeDispatcher.java +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013 SAP SE. 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; ++ ++/** ++ * Serenity specific system calls. ++ */ ++ ++class SerenityNativeDispatcher extends UnixNativeDispatcher { ++ private SerenityNativeDispatcher() { } ++ ++ /** ++ * Special implementation of 'getextmntent' (see SolarisNativeDispatcher) ++ * that returns all entries at once. ++ */ ++ static native UnixMountEntry[] getmntctl() throws UnixException; ++ ++ // initialize ++ private static native void init(); ++ ++ static { ++ jdk.internal.loader.BootLoader.loadLibrary("nio"); ++ init(); ++ } ++} +diff --git a/src/java.base/serenity/native/libnet/serenity_close.c b/src/java.base/serenity/native/libnet/serenity_close.c +new file mode 100644 +index 000000000..6a177bbb9 +--- /dev/null ++++ b/src/java.base/serenity/native/libnet/serenity_close.c +@@ -0,0 +1,458 @@ ++/* ++ * Copyright (c) 2001, 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. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "jvm.h" ++#include "net_util.h" ++ ++/* ++ * Stack allocated by thread when doing blocking operation ++ */ ++typedef struct threadEntry { ++ pthread_t thr; /* this thread */ ++ struct threadEntry *next; /* next thread */ ++ int intr; /* interrupted */ ++} threadEntry_t; ++ ++/* ++ * Heap allocated during initialized - one entry per fd ++ */ ++typedef struct { ++ pthread_mutex_t lock; /* fd lock */ ++ threadEntry_t *threads; /* threads blocked on fd */ ++} fdEntry_t; ++ ++/* ++ * Signal to unblock thread ++ */ ++static int sigWakeup = SIGIO; ++ ++/* ++ * fdTable holds one entry per file descriptor, up to a certain ++ * maximum. ++ * Theoretically, the number of possible file descriptors can get ++ * large, though usually it does not. Entries for small value file ++ * descriptors are kept in a simple table, which covers most scenarios. ++ * Entries for large value file descriptors are kept in an overflow ++ * table, which is organized as a sparse two dimensional array whose ++ * slabs are allocated on demand. This covers all corner cases while ++ * keeping memory consumption reasonable. ++ */ ++ ++/* Base table for low value file descriptors */ ++static fdEntry_t* fdTable = NULL; ++/* Maximum size of base table (in number of entries). */ ++static const int fdTableMaxSize = 0x1000; /* 4K */ ++/* Actual size of base table (in number of entries) */ ++static int fdTableLen = 0; ++/* Max. theoretical number of file descriptors on system. */ ++static int fdLimit = 0; ++ ++/* Overflow table, should base table not be large enough. Organized as ++ * an array of n slabs, each holding 64k entries. ++ */ ++static fdEntry_t** fdOverflowTable = NULL; ++/* Number of slabs in the overflow table */ ++static int fdOverflowTableLen = 0; ++/* Number of entries in one slab */ ++static const int fdOverflowTableSlabSize = 0x10000; /* 64k */ ++pthread_mutex_t fdOverflowTableLock = PTHREAD_MUTEX_INITIALIZER; ++ ++/* ++ * Null signal handler ++ */ ++static void sig_wakeup(int sig) { ++} ++ ++/* ++ * Initialization routine (executed when library is loaded) ++ * Allocate fd tables and sets up signal handler. ++ */ ++static void __attribute((constructor)) init() { ++ struct rlimit nbr_files; ++ sigset_t sigset; ++ struct sigaction sa; ++ int i = 0; ++ ++ /* Determine the maximum number of possible file descriptors. */ ++ if (-1 == getrlimit(RLIMIT_NOFILE, &nbr_files)) { ++ fprintf(stderr, "library initialization failed - " ++ "unable to get max # of allocated fds\n"); ++ abort(); ++ } ++ if (nbr_files.rlim_max != RLIM_INFINITY) { ++ fdLimit = nbr_files.rlim_max; ++ } else { ++ /* We just do not know. */ ++ fdLimit = INT_MAX; ++ } ++ ++ /* Allocate table for low value file descriptors. */ ++ fdTableLen = fdLimit < fdTableMaxSize ? fdLimit : fdTableMaxSize; ++ fdTable = (fdEntry_t*) calloc(fdTableLen, sizeof(fdEntry_t)); ++ if (fdTable == NULL) { ++ fprintf(stderr, "library initialization failed - " ++ "unable to allocate file descriptor table - out of memory"); ++ abort(); ++ } else { ++ for (i = 0; i < fdTableLen; i ++) { ++ pthread_mutex_init(&fdTable[i].lock, NULL); ++ } ++ } ++ ++ /* Allocate overflow table, if needed */ ++ if (fdLimit > fdTableMaxSize) { ++ fdOverflowTableLen = ((fdLimit - fdTableMaxSize) / fdOverflowTableSlabSize) + 1; ++ fdOverflowTable = (fdEntry_t**) calloc(fdOverflowTableLen, sizeof(fdEntry_t*)); ++ if (fdOverflowTable == NULL) { ++ fprintf(stderr, "library initialization failed - " ++ "unable to allocate file descriptor overflow table - out of memory"); ++ abort(); ++ } ++ } ++ ++ /* ++ * Setup the signal handler ++ */ ++ sa.sa_handler = sig_wakeup; ++ sa.sa_flags = 0; ++ sigemptyset(&sa.sa_mask); ++ sigaction(sigWakeup, &sa, NULL); ++ ++ sigemptyset(&sigset); ++ sigaddset(&sigset, sigWakeup); ++ sigprocmask(SIG_UNBLOCK, &sigset, NULL); ++} ++ ++/* ++ * Return the fd table for this fd. ++ */ ++static inline fdEntry_t *getFdEntry(int fd) ++{ ++ fdEntry_t* result = NULL; ++ ++ if (fd < 0) { ++ return NULL; ++ } ++ ++ /* This should not happen. If it does, our assumption about ++ * max. fd value was wrong. */ ++ assert(fd < fdLimit); ++ ++ if (fd < fdTableMaxSize) { ++ /* fd is in base table. */ ++ assert(fd < fdTableLen); ++ result = &fdTable[fd]; ++ } else { ++ /* fd is in overflow table. */ ++ const int indexInOverflowTable = fd - fdTableMaxSize; ++ const int rootindex = indexInOverflowTable / fdOverflowTableSlabSize; ++ const int slabindex = indexInOverflowTable % fdOverflowTableSlabSize; ++ fdEntry_t* slab = NULL; ++ assert(rootindex < fdOverflowTableLen); ++ assert(slabindex < fdOverflowTableSlabSize); ++ pthread_mutex_lock(&fdOverflowTableLock); ++ /* Allocate new slab in overflow table if needed */ ++ if (fdOverflowTable[rootindex] == NULL) { ++ fdEntry_t* const newSlab = ++ (fdEntry_t*)calloc(fdOverflowTableSlabSize, sizeof(fdEntry_t)); ++ if (newSlab == NULL) { ++ fprintf(stderr, "Unable to allocate file descriptor overflow" ++ " table slab - out of memory"); ++ pthread_mutex_unlock(&fdOverflowTableLock); ++ abort(); ++ } else { ++ int i; ++ for (i = 0; i < fdOverflowTableSlabSize; i ++) { ++ pthread_mutex_init(&newSlab[i].lock, NULL); ++ } ++ fdOverflowTable[rootindex] = newSlab; ++ } ++ } ++ pthread_mutex_unlock(&fdOverflowTableLock); ++ slab = fdOverflowTable[rootindex]; ++ result = &slab[slabindex]; ++ } ++ ++ return result; ++ ++} ++ ++ ++/* ++ * Start a blocking operation :- ++ * Insert thread onto thread list for the fd. ++ */ ++static inline void startOp(fdEntry_t *fdEntry, threadEntry_t *self) ++{ ++ self->thr = pthread_self(); ++ self->intr = 0; ++ ++ pthread_mutex_lock(&(fdEntry->lock)); ++ { ++ self->next = fdEntry->threads; ++ fdEntry->threads = self; ++ } ++ pthread_mutex_unlock(&(fdEntry->lock)); ++} ++ ++/* ++ * End a blocking operation :- ++ * Remove thread from thread list for the fd ++ * If fd has been interrupted then set errno to EBADF ++ */ ++static inline void endOp ++ (fdEntry_t *fdEntry, threadEntry_t *self) ++{ ++ int orig_errno = errno; ++ pthread_mutex_lock(&(fdEntry->lock)); ++ { ++ threadEntry_t *curr, *prev=NULL; ++ curr = fdEntry->threads; ++ while (curr != NULL) { ++ if (curr == self) { ++ if (curr->intr) { ++ orig_errno = EBADF; ++ } ++ if (prev == NULL) { ++ fdEntry->threads = curr->next; ++ } else { ++ prev->next = curr->next; ++ } ++ break; ++ } ++ prev = curr; ++ curr = curr->next; ++ } ++ } ++ pthread_mutex_unlock(&(fdEntry->lock)); ++ errno = orig_errno; ++} ++ ++/* ++ * Close or dup2 a file descriptor ensuring that all threads blocked on ++ * the file descriptor are notified via a wakeup signal. ++ * ++ * fd1 < 0 => close(fd2) ++ * fd1 >= 0 => dup2(fd1, fd2) ++ * ++ * Returns -1 with errno set if operation fails. ++ */ ++static int closefd(int fd1, int fd2) { ++ int rv, orig_errno; ++ fdEntry_t *fdEntry = getFdEntry(fd2); ++ if (fdEntry == NULL) { ++ errno = EBADF; ++ return -1; ++ } ++ ++ /* ++ * Lock the fd to hold-off additional I/O on this fd. ++ */ ++ pthread_mutex_lock(&(fdEntry->lock)); ++ ++ { ++ /* ++ * Send a wakeup signal to all threads blocked on this ++ * file descriptor. ++ */ ++ threadEntry_t *curr = fdEntry->threads; ++ while (curr != NULL) { ++ curr->intr = 1; ++ pthread_kill( curr->thr, sigWakeup ); ++ curr = curr->next; ++ } ++ ++ /* ++ * And close/dup the file descriptor ++ * (restart if interrupted by signal) ++ */ ++ do { ++ if (fd1 < 0) { ++ rv = close(fd2); ++ } else { ++ rv = dup2(fd1, fd2); ++ } ++ } while (rv == -1 && errno == EINTR); ++ ++ } ++ ++ /* ++ * Unlock without destroying errno ++ */ ++ orig_errno = errno; ++ pthread_mutex_unlock(&(fdEntry->lock)); ++ errno = orig_errno; ++ ++ return rv; ++} ++ ++/* ++ * Wrapper for dup2 - same semantics as dup2 system call except ++ * that any threads blocked in an I/O system call on fd2 will be ++ * preempted and return -1/EBADF; ++ */ ++int NET_Dup2(int fd, int fd2) { ++ if (fd < 0) { ++ errno = EBADF; ++ return -1; ++ } ++ return closefd(fd, fd2); ++} ++ ++/* ++ * Wrapper for close - same semantics as close system call ++ * except that any threads blocked in an I/O on fd will be ++ * preempted and the I/O system call will return -1/EBADF. ++ */ ++int NET_SocketClose(int fd) { ++ return closefd(-1, fd); ++} ++ ++/************** Basic I/O operations here ***************/ ++ ++/* ++ * Macro to perform a blocking IO operation. Restarts ++ * automatically if interrupted by signal (other than ++ * our wakeup signal) ++ */ ++#define BLOCKING_IO_RETURN_INT(FD, FUNC) { \ ++ int ret; \ ++ threadEntry_t self; \ ++ fdEntry_t *fdEntry = getFdEntry(FD); \ ++ if (fdEntry == NULL) { \ ++ errno = EBADF; \ ++ return -1; \ ++ } \ ++ do { \ ++ startOp(fdEntry, &self); \ ++ ret = FUNC; \ ++ endOp(fdEntry, &self); \ ++ } while (ret == -1 && errno == EINTR); \ ++ return ret; \ ++} ++ ++int NET_Read(int s, void* buf, size_t len) { ++ BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) ); ++} ++ ++int NET_NonBlockingRead(int s, void* buf, size_t len) { ++ BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, MSG_DONTWAIT)); ++} ++ ++int NET_RecvFrom(int s, void *buf, int len, unsigned int flags, ++ struct sockaddr *from, socklen_t *fromlen) { ++ BLOCKING_IO_RETURN_INT( s, recvfrom(s, buf, len, flags, from, fromlen) ); ++} ++ ++int NET_Send(int s, void *msg, int len, unsigned int flags) { ++ BLOCKING_IO_RETURN_INT( s, send(s, msg, len, flags) ); ++} ++ ++int NET_SendTo(int s, const void *msg, int len, unsigned int ++ flags, const struct sockaddr *to, int tolen) { ++ BLOCKING_IO_RETURN_INT( s, sendto(s, msg, len, flags, to, tolen) ); ++} ++ ++int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) { ++ BLOCKING_IO_RETURN_INT( s, accept(s, addr, addrlen) ); ++} ++ ++int NET_Connect(int s, struct sockaddr *addr, int addrlen) { ++ BLOCKING_IO_RETURN_INT( s, connect(s, addr, addrlen) ); ++} ++ ++int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) { ++ BLOCKING_IO_RETURN_INT( ufds[0].fd, poll(ufds, nfds, timeout) ); ++} ++ ++/* ++ * Wrapper for poll(s, timeout). ++ * Auto restarts with adjusted timeout if interrupted by ++ * signal other than our wakeup signal. ++ */ ++int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) { ++ jlong prevNanoTime = nanoTimeStamp; ++ jlong nanoTimeout = (jlong)timeout * NET_NSEC_PER_MSEC; ++ fdEntry_t *fdEntry = getFdEntry(s); ++ ++ /* ++ * Check that fd hasn't been closed. ++ */ ++ if (fdEntry == NULL) { ++ errno = EBADF; ++ return -1; ++ } ++ ++ for(;;) { ++ struct pollfd pfd; ++ int rv; ++ threadEntry_t self; ++ ++ /* ++ * Poll the fd. If interrupted by our wakeup signal ++ * errno will be set to EBADF. ++ */ ++ pfd.fd = s; ++ pfd.events = POLLIN | POLLERR; ++ ++ startOp(fdEntry, &self); ++ rv = poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC); ++ endOp(fdEntry, &self); ++ /* ++ * If interrupted then adjust timeout. If timeout ++ * has expired return 0 (indicating timeout expired). ++ */ ++ if (rv < 0 && errno == EINTR) { ++ if (timeout > 0) { ++ jlong newNanoTime = JVM_NanoTime(env, 0); ++ nanoTimeout -= newNanoTime - prevNanoTime; ++ if (nanoTimeout < NET_NSEC_PER_MSEC) { ++ return 0; ++ } ++ prevNanoTime = newNanoTime; ++ } else { ++ continue; // timeout is -1, so loop again. ++ } ++ } else { ++ return rv; ++ } ++ } ++} +diff --git a/src/jdk.attach/serenity/classes/sun/tools/attach/AttachProviderImpl.java b/src/jdk.attach/serenity/classes/sun/tools/attach/AttachProviderImpl.java +new file mode 100644 +index 000000000..2f6fc4d4d +--- /dev/null ++++ b/src/jdk.attach/serenity/classes/sun/tools/attach/AttachProviderImpl.java +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2013 SAP SE. 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; ++ ++// Based on linux/classes/sun/tools/attach/AttachProviderImpl.java. ++ ++/* ++ * An AttachProvider implementation for Aix that uses a UNIX domain ++ * socket. ++ */ ++public class AttachProviderImpl extends HotSpotAttachProvider { ++ ++ public AttachProviderImpl() { ++ } ++ ++ public String name() { ++ return "sun"; ++ } ++ ++ public String type() { ++ return "socket"; ++ } ++ ++ 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 --git a/src/jdk.attach/serenity/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/serenity/classes/sun/tools/attach/VirtualMachineImpl.java +new file mode 100644 +index 000000000..0c432edee +--- /dev/null ++++ b/src/jdk.attach/serenity/classes/sun/tools/attach/VirtualMachineImpl.java +@@ -0,0 +1,326 @@ ++/* ++ * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2015, 2019 SAP SE. 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; ++ ++/* ++ * Aix 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"; ++ String socket_path; ++ ++ /** ++ * Attaches to the target VM ++ */ ++ VirtualMachineImpl(AttachProvider provider, String vmid) ++ throws AttachNotSupportedException, IOException ++ { ++ super(provider, vmid); ++ ++ // This provider only understands pids ++ int pid; ++ try { ++ pid = Integer.parseInt(vmid); ++ if (pid < 1) { ++ throw new NumberFormatException(); ++ } ++ } catch (NumberFormatException x) { ++ throw new AttachNotSupportedException("Invalid process identifier: " + vmid); ++ } ++ ++ // Find the socket file. If not found then we attempt to start the ++ // attach mechanism in the target VM by sending it a QUIT signal. ++ // Then we attempt to find the socket file again. ++ File socket_file = new File(tmpdir, ".java_pid" + pid); ++ socket_path = socket_file.getPath(); ++ if (!socket_file.exists()) { ++ // Keep canonical version of File, to delete, in case target process ends and /proc link has gone: ++ File f = createAttachFile(pid).getCanonicalFile(); ++ try { ++ sendQuitTo(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) { } ++ ++ time_spend += delay; ++ if (time_spend > timeout/2 && !socket_file.exists()) { ++ // Send QUIT again to give target VM the last chance to react ++ sendQuitTo(pid); ++ } ++ } while (time_spend <= timeout && !socket_file.exists()); ++ if (!socket_file.exists()) { ++ throw new AttachNotSupportedException( ++ String.format("Unable to open socket file %s: " + ++ "target process %d doesn't respond within %dms " + ++ "or HotSpot VM not loaded", socket_path, pid, ++ time_spend)); ++ } ++ } finally { ++ f.delete(); ++ } ++ } ++ ++ // Check that the file owner/permission to avoid attaching to ++ // bogus process ++ checkPermissions(socket_path); ++ ++ // Check that we can connect to the process ++ // - this ensures we throw the permission denied error now rather than ++ // later when we attempt to enqueue a command. ++ int s = socket(); ++ try { ++ connect(s, socket_path); ++ } finally { ++ close(s); ++ } ++ } ++ ++ /** ++ * Detach from the target VM ++ */ ++ public void detach() throws IOException { ++ synchronized (this) { ++ if (socket_path != null) { ++ socket_path = null; ++ } ++ } ++ } ++ ++ // protocol version ++ private final static String PROTOCOL_VERSION = "1"; ++ ++ // known errors ++ private final static int ATTACH_ERROR_BADVERSION = 101; ++ ++ /** ++ * Execute the given command in the target VM. ++ */ ++ InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException { ++ assert args.length <= 3; // includes null ++ ++ // did we detach? ++ synchronized (this) { ++ if (socket_path == null) { ++ throw new IOException("Detached from target VM"); ++ } ++ } ++ ++ // create UNIX socket ++ int s = socket(); ++ ++ // connect to target VM ++ try { ++ connect(s, socket_path); ++ } catch (IOException x) { ++ close(s); ++ throw x; ++ } ++ ++ IOException ioe = null; ++ ++ // connected - write request ++ // ++ try { ++ writeString(s, PROTOCOL_VERSION); ++ writeString(s, cmd); ++ ++ for (int i = 0; i < 3; i++) { ++ if (i < args.length && args[i] != null) { ++ writeString(s, (String)args[i]); ++ } else { ++ writeString(s, ""); ++ } ++ } ++ } catch (IOException x) { ++ ioe = x; ++ } ++ ++ ++ // Create an input stream to read reply ++ SocketInputStream sis = new SocketInputStream(s); ++ ++ // Read the command completion status ++ int completionStatus; ++ try { ++ completionStatus = readInt(sis); ++ } catch (IOException x) { ++ sis.close(); ++ if (ioe != null) { ++ throw ioe; ++ } else { ++ throw x; ++ } ++ } ++ ++ if (completionStatus != 0) { ++ // read from the stream and use that as the error message ++ String message = readErrorMessage(sis); ++ sis.close(); ++ ++ // In the event of a protocol mismatch then the target VM ++ // returns a known error so that we can throw a reasonable ++ // error. ++ if (completionStatus == ATTACH_ERROR_BADVERSION) { ++ throw new IOException("Protocol mismatch with target VM"); ++ } ++ ++ // Special-case the "load" command so that the right exception is ++ // thrown. ++ 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 for the socket connection to get target VM ++ */ ++ 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); ++ } ++ } ++ } ++ ++ // On Aix 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 temp 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.createNewFile(); ++ } catch (IOException x) { ++ f = new File(tmpdir, fn); ++ f.createNewFile(); ++ } ++ return f; ++ } ++ ++ /* ++ * Write/sends the given to the target VM. String is transmitted in ++ * UTF-8 encoding. ++ */ ++ private void writeString(int fd, String s) throws IOException { ++ if (s.length() > 0) { ++ byte b[]; ++ try { ++ b = s.getBytes("UTF-8"); ++ } catch (java.io.UnsupportedEncodingException x) { ++ throw new InternalError(x); ++ } ++ VirtualMachineImpl.write(fd, b, 0, b.length); ++ } ++ byte b[] = new byte[1]; ++ b[0] = 0; ++ write(fd, b, 0, 1); ++ } ++ ++ ++ //-- native methods ++ ++ static native void sendQuitTo(int pid) throws IOException; ++ ++ static native void checkPermissions(String path) throws IOException; ++ ++ static native int socket() throws IOException; ++ ++ static native void connect(int fd, 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 write(int fd, byte buf[], int off, int bufLen) throws IOException; ++ ++ static { ++ System.loadLibrary("attach"); ++ } ++} +diff --git a/src/jdk.attach/serenity/native/libattach/VirtualMachineImpl.c b/src/jdk.attach/serenity/native/libattach/VirtualMachineImpl.c +new file mode 100644 +index 000000000..d20a6f012 +--- /dev/null ++++ b/src/jdk.attach/serenity/native/libattach/VirtualMachineImpl.c +@@ -0,0 +1,328 @@ ++/* ++ * Copyright (c) 2005, 2021, 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 ++#include ++ ++#include "sun_tools_attach_VirtualMachineImpl.h" ++ ++#define RESTARTABLE(_cmd, _result) do { \ ++ do { \ ++ _result = _cmd; \ ++ } while((_result == -1) && (errno == EINTR)); \ ++} while(0) ++ ++#define ROOT_UID 0 ++ ++/* ++ * Declare library specific JNI_Onload entry if static build ++ */ ++DEF_STATIC_JNI_OnLoad ++ ++/* ++ * Class: sun_tools_attach_VirtualMachineImpl ++ * Method: socket ++ * Signature: ()I ++ */ ++JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_socket ++ (JNIEnv *env, jclass cls) ++{ ++ int fd = socket(PF_UNIX, SOCK_STREAM, 0); ++ if (fd == -1) { ++ JNU_ThrowIOExceptionWithLastError(env, "socket"); ++ } ++ return (jint)fd; ++} ++ ++/* ++ * Class: sun_tools_attach_VirtualMachineImpl ++ * Method: connect ++ * Signature: (ILjava/lang/String;)I ++ */ ++JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_connect ++ (JNIEnv *env, jclass cls, jint fd, jstring path) ++{ ++ jboolean isCopy; ++ const char* p = GetStringPlatformChars(env, path, &isCopy); ++ if (p != NULL) { ++ struct sockaddr_un addr; ++ int err = 0; ++ ++ memset(&addr, 0, sizeof(addr)); ++ addr.sun_family = AF_UNIX; ++ /* strncpy is safe because addr.sun_path was zero-initialized before. */ ++ strncpy(addr.sun_path, p, sizeof(addr.sun_path) - 1); ++ ++ if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) { ++ err = errno; ++ } ++ ++ if (isCopy) { ++ JNU_ReleaseStringPlatformChars(env, path, p); ++ } ++ ++ /* ++ * If the connect failed then we throw the appropriate exception ++ * here (can't throw it before releasing the string as can't call ++ * JNI with pending exception) ++ */ ++ if (err != 0) { ++ 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); ++ } ++ } ++ } ++ } ++} ++ ++/* ++ * Class: sun_tools_attach_VirtualMachineImpl ++ * Method: sendQuitTo ++ * Signature: (I)V ++ */ ++JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sendQuitTo ++ (JNIEnv *env, jclass cls, jint pid) ++{ ++ if (kill((pid_t)pid, SIGQUIT)) { ++ JNU_ThrowIOExceptionWithLastError(env, "kill"); ++ } ++} ++ ++/* ++ * 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 stat sb; ++ uid_t uid, gid; ++ int res; ++ ++ memset(&sb, 0, sizeof(struct stat)); ++ ++ /* ++ * 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 = stat(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 res; ++ shutdown(fd, SHUT_RDWR); ++ RESTARTABLE(close(fd), res); ++} ++ ++/* ++ * 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: write ++ * Signature: (I[B)V ++ */ ++JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_write ++ (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint bufLen) ++{ ++ size_t remaining = bufLen; ++ do { ++ unsigned char buf[128]; ++ size_t len = sizeof(buf); ++ int n; ++ ++ if (len > remaining) { ++ len = remaining; ++ } ++ (*env)->GetByteArrayRegion(env, ba, off, len, (jbyte *)buf); ++ ++ RESTARTABLE(write(fd, buf, len), n); ++ if (n > 0) { ++ off += n; ++ remaining -= n; ++ } else { ++ JNU_ThrowIOExceptionWithLastError(env, "write"); ++ return; ++ } ++ ++ } while (remaining > 0); ++} ++ ++/* ++ * Class: sun_tools_attach_BSDVirtualMachine ++ * Method: createAttachFile ++ * Signature: (Ljava.lang.String;)V ++ */ ++JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_createAttachFile0(JNIEnv *env, jclass cls, jstring path) ++{ ++ const char* _path; ++ jboolean isCopy; ++ int fd, rc; ++ ++ _path = GetStringPlatformChars(env, path, &isCopy); ++ if (_path == NULL) { ++ JNU_ThrowIOException(env, "Must specify a path"); ++ return; ++ } ++ ++ RESTARTABLE(open(_path, O_CREAT | O_EXCL, S_IWUSR | S_IRUSR), fd); ++ if (fd == -1) { ++ /* release p here before we throw an I/O exception */ ++ if (isCopy) { ++ JNU_ReleaseStringPlatformChars(env, path, _path); ++ } ++ JNU_ThrowIOExceptionWithLastError(env, "open"); ++ return; ++ } ++ ++ RESTARTABLE(chown(_path, geteuid(), getegid()), rc); ++ ++ RESTARTABLE(close(fd), rc); ++ ++ /* release p here */ ++ if (isCopy) { ++ JNU_ReleaseStringPlatformChars(env, path, _path); ++ } ++} ++ ++/* ++ * Class: sun_tools_attach_BSDVirtualMachine ++ * Method: getTempDir ++ * Signature: (V)Ljava.lang.String; ++ */ ++JNIEXPORT jstring JNICALL Java_sun_tools_attach_VirtualMachineImpl_getTempDir(JNIEnv *env, jclass cls) ++{ ++ // This must be hard coded because it's the system's temporary ++ // directory not the java application's temp directory, ala java.io.tmpdir. ++ ++#ifdef __APPLE__ ++ // macosx has a secure per-user temporary directory. ++ // Don't cache the result as this is only called once. ++ char path[PATH_MAX]; ++ int pathSize = confstr(_CS_DARWIN_USER_TEMP_DIR, path, PATH_MAX); ++ if (pathSize == 0 || pathSize > PATH_MAX) { ++ strlcpy(path, "/tmp", sizeof(path)); ++ } ++ return JNU_NewStringPlatform(env, path); ++#else /* __APPLE__ */ ++ return (*env)->NewStringUTF(env, "/tmp"); ++#endif /* __APPLE__ */ ++} diff --git a/Ports/OpenJDK/patches/0007-java.base-Update-native-modules-to-support-Serenity.patch b/Ports/OpenJDK/patches/0007-java.base-Update-native-modules-to-support-Serenity.patch new file mode 100644 index 00000000000..271a7e01205 --- /dev/null +++ b/Ports/OpenJDK/patches/0007-java.base-Update-native-modules-to-support-Serenity.patch @@ -0,0 +1,606 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Timur Sultanov +Date: Wed, 16 Feb 2022 21:06:23 +0300 +Subject: [PATCH] java.base: Update native modules to support Serenity + +--- + .../nio/ch/SocketOptionRegistry.java.template | 21 +++++ + src/java.base/share/native/libjava/io_util.h | 5 +- + src/java.base/share/native/libjli/jli_util.h | 3 + + src/java.base/share/native/libzip/zip_util.c | 2 +- + .../sun/nio/fs/UnixConstants.java.template | 92 ++++++++++++++++++- + .../native/libjava/ProcessHandleImpl_unix.c | 2 +- + .../unix/native/libjava/TimeZone_md.c | 4 +- + .../unix/native/libjava/io_util_md.c | 2 +- + .../unix/native/libjava/io_util_md.h | 6 +- + src/java.base/unix/native/libjsig/jsig.c | 4 + + .../unix/native/libnet/Inet4AddressImpl.c | 3 + + .../unix/native/libnet/Inet6AddressImpl.c | 4 + + .../unix/native/libnet/NetworkInterface.c | 11 ++- + .../unix/native/libnet/net_util_md.h | 4 + + .../unix/native/libnio/MappedMemoryUtils.c | 4 + + .../native/libnio/ch/DatagramDispatcher.c | 1 + + .../unix/native/libnio/ch/FileChannelImpl.c | 3 + + .../native/libnio/ch/FileDispatcherImpl.c | 7 +- + src/java.base/unix/native/libnio/ch/FileKey.c | 2 +- + .../unix/native/libnio/ch/NativeThread.c | 2 +- + src/java.base/unix/native/libnio/ch/Net.c | 2 +- + .../native/libnio/fs/UnixNativeDispatcher.c | 39 +++++++- + 22 files changed, 207 insertions(+), 16 deletions(-) + +diff --git a/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template b/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template +index 0672ced15..55bde3569 100644 +--- a/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template ++++ b/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template +@@ -50,6 +50,24 @@ + #endif + #endif + ++#define SO_RCVTIMEO 0 ++#define SO_SNDTIMEO 1 ++#define SO_TYPE 2 ++#define SO_ERROR 3 ++#define SO_PEERCRED 4 ++#define SO_SNDBUF 5 ++#define SO_RCVBUF 6 ++#define SO_DEBUG 7 ++#define SO_REUSEADDR 8 ++#define SO_BINDTODEVICE 9 ++#define SO_KEEPALIVE 10 ++#define SO_TIMESTAMP 11 ++#define SO_BROADCAST 12 ++#define SO_LINGER 13 ++#define SO_ACCEPTCONN 14 ++#define SO_DONTROUTE 15 ++#define SO_OOBINLINE 16 ++ + /* 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 +@@ -125,6 +143,9 @@ class SocketOptionRegistry { + + #ifdef AF_INET6 + // IPPROTO_IPV6 is 41 ++#ifdef SERENITY ++#define IPV6_TCLASS 1 ++#endif + map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_TOS, + StandardProtocolFamily.INET6), new OptionKey(41, IPV6_TCLASS)); + map.put(new RegistryKey(StandardSocketOptions.PREFIX_IP_MULTICAST_IF, +diff --git a/src/java.base/share/native/libjava/io_util.h b/src/java.base/share/native/libjava/io_util.h +index 6e960c034..cbd1d087e 100644 +--- a/src/java.base/share/native/libjava/io_util.h ++++ b/src/java.base/share/native/libjava/io_util.h +@@ -30,11 +30,14 @@ extern jfieldID IO_fd_fdID; + extern jfieldID IO_handle_fdID; + extern jfieldID IO_append_fdID; + +-#ifdef _ALLBSD_SOURCE ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + #include + #ifndef O_SYNC + #define O_SYNC O_FSYNC + #endif ++#if defined(SERENITY) ++#define O_DSYNC O_SYNC ++#endif + #ifndef O_DSYNC + #define O_DSYNC O_FSYNC + #endif +diff --git a/src/java.base/share/native/libjli/jli_util.h b/src/java.base/share/native/libjli/jli_util.h +index 3512b1e96..e60f7581f 100644 +--- a/src/java.base/share/native/libjli/jli_util.h ++++ b/src/java.base/share/native/libjli/jli_util.h +@@ -108,6 +108,9 @@ JLI_CmdToArgs(char *cmdline); + #define _LARGFILE64_SOURCE + #define JLI_Lseek lseek64 + #endif ++#ifdef SERENITY ++#define JLI_Lseek lseek ++#endif + #ifdef MACOSX + #define JLI_Lseek lseek + #endif +diff --git a/src/java.base/share/native/libzip/zip_util.c b/src/java.base/share/native/libzip/zip_util.c +index fbbd9d850..eef30b9e4 100644 +--- a/src/java.base/share/native/libzip/zip_util.c ++++ b/src/java.base/share/native/libzip/zip_util.c +@@ -46,7 +46,7 @@ + #include "zip_util.h" + #include + +-#ifdef _ALLBSD_SOURCE ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + #define off64_t off_t + #define mmap64 mmap + #endif +diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template +index d60283d24..5d428521b 100644 +--- a/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template ++++ b/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template +@@ -31,6 +31,95 @@ + #include + #include + ++#ifdef SERENITY ++ ++#define ESUCCESS 0 ++#define EPERM 1 ++#define ENOENT 2 ++#define ESRCH 3 ++#define EINTR 4 ++#define EIO 5 ++#define ENXIO 6 ++#define E2BIG 7 ++#define ENOEXEC 8 ++#define EBADF 9 ++#define ECHILD 10 ++#define EAGAIN 12 ++#define ENOMEM 12 ++#define EACCES 13 ++#define EFAULT 14 ++#define ENOTBLK 15 ++#define EBUSY 16 ++#define EEXIST 17 ++#define EXDEV 18 ++#define ENODEV 19 ++#define ENOTDIR 20 ++#define EISDIR 21 ++#define EINVAL 22 ++#define ENFILE 23 ++#define EMFILE 24 ++#define ENOTTY 25 ++#define ETXTBSY 26 ++#define EFBIG 27 ++#define ENOSPC 28 ++#define ESPIPE 29 ++#define EROFS 30 ++#define EMLINK 31 ++#define EPIPE 32 ++#define ERANGE 33 ++#define ENAMETOOLONG 34 ++#define ELOOP 35 ++#define EOVERFLOW 36 ++#define EOPNOTSUPP 37 ++#define ENOSYS 38 ++#define ENOTIMPL 39 ++#define EAFNOSUPPORT 40 ++#define ENOTSOCK 41 ++#define EADDRINUSE 42 ++#define ENOTEMPTY 43 ++#define EDOM 44 ++#define ECONNREFUSED 45 ++#define EHOSTDOWN 46 ++#define EADDRNOTAVAIL 47 ++#define EISCONN 48 ++#define ECONNABORTED 49 ++#define EALREADY 50 ++#define ECONNRESET 51 ++#define EDESTADDRREQ 52 ++#define EHOSTUNREACH 53 ++#define EILSEQ 54 ++#define EMSGSIZE 55 ++#define ENETDOWN 56 ++#define ENETUNREACH 57 ++#define ENETRESET 58 ++#define ENOBUFS 59 ++#define ENOLCK 60 ++#define ENOMSG 61 ++#define ENOPROTOOPT 62 ++#define ENOTCONN 63 ++#define ESHUTDOWN 64 ++#define ETOOMANYREFS 65 ++#define EPROTONOSUPPORT 66 ++#define ESOCKTNOSUPPORT 67 ++#define EDEADLK 68 ++#define ETIMEDOUT 69 ++#define EPROTOTYPE 70 ++#define EINPROGRESS 71 ++#define ENOTHREAD 72 ++#define EPROTO 73 ++#define ENOTSUP 74 ++#define EPFNOSUPPORT 75 ++#define EDQUOT 76 ++#define EDIRINTOSELF 77 ++#define ENOTRECOVERABLE 78 ++#define ECANCELED 79 ++#define EMAXERRNO 80 ++ ++ ++#define EWOULDBLOCK EAGAIN //Serenity doesn't define it ++#define ENODATA EMAXERRNO ++#endif ++ + /* 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 +@@ -120,7 +210,7 @@ class UnixConstants { + // fgetxattr error codes for absent attributes depend on the OS: + #ifdef _ALLBSD_SOURCE + static final int PREFIX_XATTR_NOT_FOUND = ENOATTR; +-#elif __linux__ ++#elif defined(__linux__) + static final int PREFIX_XATTR_NOT_FOUND = ENODATA; + #else + // not supported (dummy values will not be used at runtime). +diff --git a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c +index d53e88764..eddb5f169 100644 +--- a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c ++++ b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c +@@ -488,7 +488,7 @@ void unix_getUserInfo(JNIEnv* env, jobject jinfo, uid_t uid) { + * The following functions are common on Solaris, Linux and AIX. + */ + +-#if defined (__linux__) || defined(_AIX) ++#if defined (__linux__) || defined(_AIX) || defined(SERENITY) + + /* + * Returns the children of the requested pid and optionally each parent and +diff --git a/src/java.base/unix/native/libjava/TimeZone_md.c b/src/java.base/unix/native/libjava/TimeZone_md.c +index 94dfc207f..2a6c3851a 100644 +--- a/src/java.base/unix/native/libjava/TimeZone_md.c ++++ b/src/java.base/unix/native/libjava/TimeZone_md.c +@@ -53,7 +53,7 @@ static char *isFileIdentical(char* buf, size_t size, char *pathname); + #define filegets fgets + #define fileclose fclose + +-#if defined(_ALLBSD_SOURCE) ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + #define stat64 stat + #define lstat64 lstat + #define fstat64 fstat +@@ -75,7 +75,7 @@ static const char popularZones[][4] = {"UTC", "GMT"}; + static const char *ETC_ENVIRONMENT_FILE = "/etc/environment"; + #endif + +-#if defined(__linux__) || defined(MACOSX) ++#if defined(__linux__) || defined(MACOSX) || defined(SERENITY) + + /* + * Returns a pointer to the zone ID portion of the given zoneinfo file +diff --git a/src/java.base/unix/native/libjava/io_util_md.c b/src/java.base/unix/native/libjava/io_util_md.c +index e207c57d4..8afabc544 100644 +--- a/src/java.base/unix/native/libjava/io_util_md.c ++++ b/src/java.base/unix/native/libjava/io_util_md.c +@@ -30,7 +30,7 @@ + #include + #include + +-#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX) ++#if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX) || defined(SERENITY) + #include + #endif + +diff --git a/src/java.base/unix/native/libjava/io_util_md.h b/src/java.base/unix/native/libjava/io_util_md.h +index 3dccf64f4..3e9e7d3b0 100644 +--- a/src/java.base/unix/native/libjava/io_util_md.h ++++ b/src/java.base/unix/native/libjava/io_util_md.h +@@ -66,7 +66,7 @@ FD getFD(JNIEnv *env, jobject cur, jfieldID fid); + #define IO_SetLength handleSetLength + #define IO_GetLength handleGetLength + +-#ifdef _ALLBSD_SOURCE ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + #define open64 open + #define fstat64 fstat + #define stat64 stat +@@ -77,6 +77,10 @@ FD getFD(JNIEnv *env, jobject cur, jfieldID fid); + #define IO_Lseek lseek64 + #endif + ++#ifdef SERENITY ++#define statvfs64 statvfs ++#endif ++ + /* + * On Solaris, the handle field is unused + */ +diff --git a/src/java.base/unix/native/libjsig/jsig.c b/src/java.base/unix/native/libjsig/jsig.c +index 1108b2f9c..d891aab93 100644 +--- a/src/java.base/unix/native/libjsig/jsig.c ++++ b/src/java.base/unix/native/libjsig/jsig.c +@@ -100,6 +100,10 @@ static sa_handler_t call_os_signal(int sig, sa_handler_t disp, + bool is_sigset) { + sa_handler_t res; + ++#ifdef SERENITY ++#define RTLD_NEXT 0 //stub out RTLD_NEXT ++#endif ++ + if (os_signal == NULL) { + // Deprecation warning first time through + printf(HOTSPOT_VM_DISTRO " VM warning: the use of signal() and sigset() " +diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c +index b165be7ce..a4cd70003 100644 +--- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c ++++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c +@@ -335,6 +335,7 @@ static jboolean + ping4(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, + jint timeout, jint ttl) + { ++#ifndef SERENITY + jint n, size = 60 * 1024, hlen, tmout2, seq = 1; + socklen_t len; + unsigned char sendbuf[1500], recvbuf[1500]; +@@ -438,6 +439,8 @@ ping4(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, + timeout -= 1000; + } while (timeout > 0); + close(fd); ++#endif ++ //FIXME implement setsockopt(IPPROTO_IP) + return JNI_FALSE; + } + +diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c +index 058f3d3a7..61460fda8 100644 +--- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c ++++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c +@@ -29,7 +29,9 @@ + #include + #include + #include ++#ifndef SERENITY + #include ++#endif + + #if defined(_ALLBSD_SOURCE) + #include +@@ -539,6 +541,7 @@ static jboolean + ping6(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, + jint timeout, jint ttl) + { ++#ifndef SERENITY + jint n, size = 60 * 1024, tmout2, seq = 1; + socklen_t len; + unsigned char sendbuf[1500], recvbuf[1500]; +@@ -643,6 +646,7 @@ ping6(JNIEnv *env, jint fd, SOCKETADDRESS *sa, SOCKETADDRESS *netif, + timeout -= 1000; + } while (timeout > 0); + close(fd); ++#endif + return JNI_FALSE; + } + +diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c +index 990bc1bcc..fdeff2bf6 100644 +--- a/src/java.base/unix/native/libnet/NetworkInterface.c ++++ b/src/java.base/unix/native/libnet/NetworkInterface.c +@@ -43,6 +43,10 @@ + #include + #endif + ++#if defined(SERENITY) ++#include ++#endif ++ + #include "net_util.h" + + #include "java_net_InetAddress.h" +@@ -1351,7 +1355,7 @@ static int getMacAddress + static int getMTU(JNIEnv *env, int sock, const char *ifname) { + struct ifreq if2; + memset((char *)&if2, 0, sizeof(if2)); +- strncpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1); ++ memcpy(if2.ifr_name, ifname, sizeof(if2.ifr_name) - 1); + + if (ioctl(sock, SIOCGIFMTU, (char *)&if2) < 0) { + JNU_ThrowByNameWithMessageAndLastError +@@ -1664,7 +1668,7 @@ static int getFlags(int sock, const char *ifname, int *flags) { + #endif /* _AIX */ + + /** BSD **/ +-#if defined(_ALLBSD_SOURCE) ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + + /* + * Opens a socket for further ioctl calls. Tries AF_INET socket first and +@@ -1803,6 +1807,7 @@ static int getMacAddress + (JNIEnv *env, const char *ifname, const struct in_addr *addr, + unsigned char *buf) + { ++#ifndef SERENITY // FIXME: define sockaddr_dl in net/if_dl.h + struct ifaddrs *ifa0, *ifa; + struct sockaddr *saddr; + int i; +@@ -1827,7 +1832,7 @@ static int getMacAddress + } + freeifaddrs(ifa0); + } +- ++#endif + return -1; + } + +diff --git a/src/java.base/unix/native/libnet/net_util_md.h b/src/java.base/unix/native/libnet/net_util_md.h +index 68835987b..f99b11207 100644 +--- a/src/java.base/unix/native/libnet/net_util_md.h ++++ b/src/java.base/unix/native/libnet/net_util_md.h +@@ -30,6 +30,10 @@ + #include + #include + ++#ifdef SERENITY ++#include ++#endif ++ + /************************************************************************ + * Macros and constants + */ +diff --git a/src/java.base/unix/native/libnio/MappedMemoryUtils.c b/src/java.base/unix/native/libnio/MappedMemoryUtils.c +index e90acd286..34787fff4 100644 +--- a/src/java.base/unix/native/libnio/MappedMemoryUtils.c ++++ b/src/java.base/unix/native/libnio/MappedMemoryUtils.c +@@ -58,6 +58,7 @@ JNIEXPORT jboolean JNICALL + Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong address, + jlong len, jlong numPages) + { ++#ifndef SERENITY + jboolean loaded = JNI_TRUE; + int result = 0; + long i = 0; +@@ -100,6 +101,9 @@ Java_java_nio_MappedMemoryUtils_isLoaded0(JNIEnv *env, jobject obj, jlong addres + } + free(vec); + return loaded; ++#else ++ return JNI_FALSE; //FIXME implement mincore() or equivalent ++#endif + } + + +diff --git a/src/java.base/unix/native/libnio/ch/FileChannelImpl.c b/src/java.base/unix/native/libnio/ch/FileChannelImpl.c +index 8cc753e6a..28fa55269 100644 +--- a/src/java.base/unix/native/libnio/ch/FileChannelImpl.c ++++ b/src/java.base/unix/native/libnio/ch/FileChannelImpl.c +@@ -39,6 +39,9 @@ + #include + #define lseek64 lseek + #define mmap64 mmap ++#elif defined(SERENITY) ++#define lseek64 lseek ++#define mmap64 mmap + #endif + + #include "jni.h" +diff --git a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +index c0c31d6ab..3a4d8a632 100644 +--- a/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c ++++ b/src/java.base/unix/native/libnio/ch/FileDispatcherImpl.c +@@ -40,7 +40,7 @@ + #include + #endif + +-#if defined(_ALLBSD_SOURCE) ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + #define lseek64 lseek + #define stat64 stat + #define flock64 flock +@@ -54,6 +54,11 @@ + #define fdatasync fsync + #endif + ++#ifdef SERENITY ++#define statvfs64 statvfs ++#define fstatvfs64 fstatvfs ++#endif ++ + #include "jni.h" + #include "jni_util.h" + #include "jvm.h" +diff --git a/src/java.base/unix/native/libnio/ch/FileKey.c b/src/java.base/unix/native/libnio/ch/FileKey.c +index bdb42a632..a433cdf01 100644 +--- a/src/java.base/unix/native/libnio/ch/FileKey.c ++++ b/src/java.base/unix/native/libnio/ch/FileKey.c +@@ -30,7 +30,7 @@ + #include "nio_util.h" + #include "sun_nio_ch_FileKey.h" + +-#ifdef _ALLBSD_SOURCE ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + #define stat64 stat + + #define fstat64 fstat +diff --git a/src/java.base/unix/native/libnio/ch/NativeThread.c b/src/java.base/unix/native/libnio/ch/NativeThread.c +index 92dcb9e56..4bf09d03b 100644 +--- a/src/java.base/unix/native/libnio/ch/NativeThread.c ++++ b/src/java.base/unix/native/libnio/ch/NativeThread.c +@@ -40,7 +40,7 @@ + #elif defined(_AIX) + /* Also defined in net/aix_close.c */ + #define INTERRUPT_SIGNAL (SIGRTMAX - 1) +-#elif defined(_ALLBSD_SOURCE) ++#elif defined(_ALLBSD_SOURCE) || defined(SERENITY) + /* Also defined in net/bsd_close.c */ + #define INTERRUPT_SIGNAL SIGIO + #else +diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c +index 42a07359d..ca1401861 100644 +--- a/src/java.base/unix/native/libnio/ch/Net.c ++++ b/src/java.base/unix/native/libnio/ch/Net.c +@@ -701,7 +701,7 @@ JNIEXPORT jint JNICALL + Java_sun_nio_ch_Net_blockOrUnblock6(JNIEnv *env, jobject this, jboolean block, jobject fdo, + jbyteArray group, jint index, jbyteArray source) + { +-#ifdef __APPLE__ ++#if defined(__APPLE__) || defined(SERENITY) + /* no IPv6 exclude-mode filtering for now */ + return IOS_UNAVAILABLE; + #else +diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +index 9df8be1e6..993e240db 100644 +--- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c ++++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +@@ -57,7 +57,7 @@ + #include + #endif + +-#ifdef _ALLBSD_SOURCE ++#if defined(_ALLBSD_SOURCE) || defined(SERENITY) + #include + + #define stat64 stat +@@ -1114,6 +1114,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid + int retry; + + /* initial size of buffer for group record */ ++#ifndef SERENITY + buflen = (int)sysconf(_SC_GETGR_R_SIZE_MAX); + if (buflen == -1) + buflen = ENT_BUF_SIZE; +@@ -1156,6 +1157,24 @@ Java_sun_nio_fs_UnixNativeDispatcher_getgrgid(JNIEnv* env, jclass this, jint gid + + } while (retry); + ++#else ++ // FIXME: Not thread safe, implement getgrgid_r ++ errno = 0; ++ struct group * g = getgrgid(gid); ++ if (g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { ++ if (errno == 0) ++ errno = ENOENT; ++ throwUnixException(env, errno); ++ } ++ else { ++ jsize len = strlen(g->gr_name); ++ result = (*env)->NewByteArray(env, len); ++ if (result != NULL) { ++ (*env)->SetByteArrayRegion(env, result, 0, len, (jbyte*)(g->gr_name)); ++ } ++ } ++#endif ++ + return result; + } + +@@ -1204,6 +1223,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, + jlong nameAddress) + { + jint gid = -1; ++#ifndef SERENITY + int buflen, retry; + + /* initial size of buffer for group record */ +@@ -1248,6 +1268,23 @@ Java_sun_nio_fs_UnixNativeDispatcher_getgrnam0(JNIEnv* env, jclass this, + free(grbuf); + + } while (retry); ++#else ++ // FIXME: Not thread safe, implement getgrnam_r ++ const char* name = (const char*)jlong_to_ptr(nameAddress); ++ errno = 0; ++ struct group * g = getgrnam(name); ++ if (g == NULL || g->gr_name == NULL || *(g->gr_name) == '\0') { ++ /* not found or error */ ++ if (errno != 0 && errno != ENOENT && errno != ESRCH && ++ errno != EBADF && errno != EPERM) ++ { ++ throwUnixException(env, errno); ++ } ++ } ++ else { ++ gid = g->gr_gid; ++ } ++#endif + + return gid; + } diff --git a/Ports/OpenJDK/patches/0008-java.base-Enable-java.lang.Process-on-serenity.patch b/Ports/OpenJDK/patches/0008-java.base-Enable-java.lang.Process-on-serenity.patch new file mode 100644 index 00000000000..e99b3d2dd87 --- /dev/null +++ b/Ports/OpenJDK/patches/0008-java.base-Enable-java.lang.Process-on-serenity.patch @@ -0,0 +1,259 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Andrew Kaster +Date: Sun, 12 Jun 2022 23:15:17 -0600 +Subject: [PATCH] java.base: Enable java.lang.Process on serenity + +--- + make/modules/java.base/Launcher.gmk | 2 +- + make/modules/java.base/lib/CoreLibraries.gmk | 3 + + .../libjava/ProcessHandleImpl_serenity.cpp | 167 ++++++++++++++++++ + .../unix/classes/java/lang/ProcessImpl.java | 7 +- + 4 files changed, 177 insertions(+), 2 deletions(-) + create mode 100644 src/java.base/serenity/native/libjava/ProcessHandleImpl_serenity.cpp + +diff --git a/make/modules/java.base/Launcher.gmk b/make/modules/java.base/Launcher.gmk +index 700ddefda..78c884dae 100644 +--- a/make/modules/java.base/Launcher.gmk ++++ b/make/modules/java.base/Launcher.gmk +@@ -73,7 +73,7 @@ endif + + ################################################################################ + +-ifeq ($(call isTargetOs, macosx aix linux), true) ++ifeq ($(call isTargetOs, macosx aix linux serenity), true) + $(eval $(call SetupJdkExecutable, BUILD_JSPAWNHELPER, \ + NAME := jspawnhelper, \ + SRC := $(TOPDIR)/src/$(MODULE)/unix/native/jspawnhelper, \ +diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk +index 0a61d009f..7867a3095 100644 +--- a/make/modules/java.base/lib/CoreLibraries.gmk ++++ b/make/modules/java.base/lib/CoreLibraries.gmk +@@ -90,6 +90,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \ + OPTIMIZATION := HIGH, \ + CFLAGS := $(CFLAGS_JDKLIB) \ + $(LIBJAVA_CFLAGS), \ ++ CXXFLAGS := $(CXXFLAGS_JDKLIB) \ ++ $(LIBJAVA_CXXFLAGS), \ + jdk_util.c_CFLAGS := $(VERSION_CFLAGS), \ + EXTRA_HEADER_DIRS := libfdlibm, \ + WARNINGS_AS_ERRORS_xlc := false, \ +@@ -102,6 +104,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJAVA, \ + LIBS_unix := -ljvm, \ + LIBS_linux := $(LIBDL), \ + LIBS_aix := $(LIBDL) $(LIBM),\ ++ LIBS_serenity := $(LIBDL) -lcore, \ + LIBS_macosx := -framework CoreFoundation \ + -framework Foundation \ + -framework SystemConfiguration, \ +diff --git a/src/java.base/serenity/native/libjava/ProcessHandleImpl_serenity.cpp b/src/java.base/serenity/native/libjava/ProcessHandleImpl_serenity.cpp +new file mode 100644 +index 000000000..e9bb2ec4a +--- /dev/null ++++ b/src/java.base/serenity/native/libjava/ProcessHandleImpl_serenity.cpp +@@ -0,0 +1,167 @@ ++/* ++ * Copyright (c) 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. ++ */ ++ ++#define AK_DONT_REPLACE_STD ++ ++#include "jvm.h" ++#include "jni.h" ++#include "jni_util.h" ++#include "java_lang_String.h" ++ ++extern "C" { ++#include "ProcessHandleImpl_unix.h" ++} ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* ++ * Implementation of native ProcessHandleImpl functions for SERENITY. ++ * See ProcessHandleImpl_unix.c for more details. ++ */ ++ ++#define JAVA_TRY(expression, message) \ ++ ({ \ ++ auto _temporary_result = (expression); \ ++ if (_temporary_result.is_error()) [[unlikely]] \ ++ return throwSerenityError(env, _temporary_result.release_error(), (message)); \ ++ _temporary_result.release_value(); \ ++ }) ++ ++ ++static RefPtr proc_all; ++ ++extern "C" { ++void os_initNative(JNIEnv *env, jclass clazz) { ++ proc_all = MUST(Core::File::open("/proc/all", Core::OpenMode::ReadOnly)); ++} ++ ++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) { ++ auto maybe_stats = Core::ProcessStatisticsReader::get_all(proc_all); ++ if (!maybe_stats.has_value()) { ++ JNU_ThrowByNameWithLastError(env, ++ "java/lang/RuntimeException", "ProcessStatisticsReader::get_all failed"); ++ return -1; ++ } ++ auto stats = maybe_stats.release_value(); ++ auto proc_it = find_if(stats.processes.begin(), stats.processes.end(), [pid](auto& proc_stats) { ++ return proc_stats.pid == pid; ++ }); ++ if (proc_it == stats.processes.end()) { ++ JNU_ThrowByNameWithLastError(env, ++ "java/lang/RuntimeException", "Selected pid does not exist"); ++ return -1; ++ } ++ auto& proc = *proc_it; ++ ++ for (auto& thread : proc.threads) { ++ *total += thread.time_user + thread.time_kernel; ++ } ++ ++ *start = 0; // FIXME: When did thread start? not reported in /proc/all ++ ++ return proc.ppid; ++} ++ ++ ++static void throwSerenityError(JNIEnv* env, Error const& e, StringView msg) { ++ char err_buf[256]; ++ if (e.is_errno()) ++ getErrorString(e.code(), err_buf, sizeof(err_buf)); ++ else ++ strncpy(err_buf, e.string_literal().characters_without_null_termination(), sizeof(err_buf) - 1); ++ jstring s = JNU_NewStringPlatform(env, err_buf); ++ if (s != NULL) { ++ jobject x = JNU_NewObjectByName(env, "java/lang/RuntimeException", ++ "(Ljava/lang/String;)V", s); ++ if (x != NULL) { ++ env->Throw((jthrowable)x); ++ } ++ } ++ if (!env->ExceptionOccurred()) { ++ JNU_ThrowByName(env, "java/lang/RuntimeException", msg.characters_without_null_termination()); ++ } ++} ++ ++void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) { ++ auto maybe_stats = Core::ProcessStatisticsReader::get_all(proc_all); ++ if (!maybe_stats.has_value()) { ++ JNU_ThrowByNameWithLastError(env, ++ "java/lang/RuntimeException", "ProcessStatisticsReader::get_all failed"); ++ return; ++ } ++ ++ auto stats = maybe_stats.release_value(); ++ auto proc_it = find_if(stats.processes.begin(), stats.processes.end(), [pid](auto& proc_stats) { ++ return proc_stats.pid == pid; ++ }); ++ if (proc_it == stats.processes.end()) { ++ JNU_ThrowByNameWithLastError(env, ++ "java/lang/RuntimeException", "Selected pid does not exist"); ++ return; ++ } ++ auto& proc = *proc_it; ++ ++ unix_getUserInfo(env, jinfo, proc.pid); ++ JNU_CHECK_EXCEPTION(env); ++ ++ char cmdline_name[256]; ++ snprintf(cmdline_name , sizeof(cmdline_name) - 1, "/proc/%d/cmdline", pid); ++ ++ auto cmdline_file = JAVA_TRY(Core::Stream::File::open(cmdline_name, Core::Stream::OpenMode::Read), "Unable to open /proc/pid/cmdline"sv); ++ auto contents = JAVA_TRY(cmdline_file->read_all(), "Unable to read /proc/pid/cmdline"sv); ++ auto cmdline = JAVA_TRY(JsonValue::from_string(contents), "Invalid JSON in /proc/pid/cmdline"sv); ++ ++ if (!cmdline.is_array()) ++ return throwSerenityError(env, Error::from_string_literal("Not an array"), "Unexpected JSON in /proc/pid/cmdline"); ++ ++ jstring cmdexe = JNU_NewStringPlatform(env, cmdline.as_array()[0].as_string().characters()); ++ env->ExceptionClear(); // unconditionally clear any exception ++ env->SetObjectField(jinfo, ProcessHandleImpl_Info_commandID, cmdexe); ++ ++ int arr_size = cmdline.as_array().size(); ++ jclass string_clazz = JNU_ClassString(env); ++ CHECK_NULL(string_clazz); ++ jobjectArray java_cmdline = env->NewObjectArray(arr_size, string_clazz, NULL); ++ CHECK_NULL(java_cmdline); ++ jstring elem = NULL; ++ for (int i = 0; i < arr_size; ++i) { ++ elem = JNU_NewStringPlatform(env, cmdline.as_array()[i].as_string().characters()); ++ CHECK_NULL(elem); ++ env->SetObjectArrayElement(java_cmdline, i, elem); ++ JNU_CHECK_EXCEPTION(env); ++ } ++ env->SetObjectField(jinfo, ProcessHandleImpl_Info_argumentsID, java_cmdline); ++ JNU_CHECK_EXCEPTION(env); ++} ++} +diff --git a/src/java.base/unix/classes/java/lang/ProcessImpl.java b/src/java.base/unix/classes/java/lang/ProcessImpl.java +index 2bf36f8f1..317bbf158 100644 +--- a/src/java.base/unix/classes/java/lang/ProcessImpl.java ++++ b/src/java.base/unix/classes/java/lang/ProcessImpl.java +@@ -89,7 +89,9 @@ final class ProcessImpl extends Process { + + BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK), + +- AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK); ++ AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK), ++ ++ SERENITY(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK); + + final LaunchMechanism defaultLaunchMechanism; + final Set validLaunchMechanisms; +@@ -135,6 +137,7 @@ final class ProcessImpl extends Process { + if (osName.equals("Linux")) { return LINUX; } + if (osName.contains("OS X")) { return BSD; } + if (osName.equals("AIX")) { return AIX; } ++ if (osName.equals("SerenityOS")) { return SERENITY; } + + throw new Error(osName + " is not a supported OS platform."); + } +@@ -348,6 +351,7 @@ final class ProcessImpl extends Process { + switch (platform) { + case LINUX: + case BSD: ++ case SERENITY: + stdin = (fds[0] == -1) ? + ProcessBuilder.NullOutputStream.INSTANCE : + new ProcessPipeOutputStream(fds[0]); +@@ -467,6 +471,7 @@ final class ProcessImpl extends Process { + case LINUX: + case BSD: + case AIX: ++ case SERENITY: + // 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, diff --git a/Ports/OpenJDK/patches/ReadMe.md b/Ports/OpenJDK/patches/ReadMe.md new file mode 100644 index 00000000000..2a91ba91e13 --- /dev/null +++ b/Ports/OpenJDK/patches/ReadMe.md @@ -0,0 +1,51 @@ +# Patches for OpenJDK on SerenityOS + +## `0001-make-Add-Serenity-support-masquerading-as-BSD-when-n.patch` + +make: Add Serenity support, masquerading as BSD when necessary + + +## `0002-make-Build-with-c-20-when-targeting-serenity.patch` + +make: Build with c++20 when targeting serenity + + +## `0003-make-Remove-CUPS-dependency.patch` + +make: Remove CUPS dependency + + +## `0004-hotspot-Add-workarounds-for-BSD-differences-from-ser.patch` + +hotspot: Add workarounds for BSD differences from serenity + +For the most part, we can pretend to be *BSD. + +However, for some methods, we need to convince hotspot that we're macOS, +and others need serenity-specific ifdefs due to the lack of sysctl in +serenity. + + +## `0005-hotspot-Update-non-BSD-native-modules-for-Serenity.patch` + +hotspot: Update non-BSD native modules for Serenity + + +## `0006-Add-serenity-specific-modules-to-java.base-and-jdk.a.patch` + +Add serenity-specific modules to java.base and jdk.attach + +It would be nice to re-direct the build to the same files *BSD use, but +for now we've got our own copy + + +## `0007-java.base-Update-native-modules-to-support-Serenity.patch` + +java.base: Update native modules to support Serenity + + +## `0008-java.base-Enable-java.lang.Process-on-serenity.patch` + +java.base: Enable java.lang.Process on serenity + +