123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
- From: Andrew Kaster <andrewdkaster@gmail.com>
- 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 | 164 ++++++++++++++++++
- .../unix/classes/java/lang/ProcessImpl.java | 7 +-
- 4 files changed, 174 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 700ddefda49e891ac1a2cfd8602fb8a9409ad1d4..78c884dae8271aea4431976823a0f18506cab4b4 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 0a61d009f34a4e73ace746d0cc6068fe2852e832..7867a3095dbe3d76c8db6d7d1948ae0f05d41c63 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 0000000000000000000000000000000000000000..cc0c08cb85a682d66a00f6b48ad2871f83b5e719
- --- /dev/null
- +++ b/src/java.base/serenity/native/libjava/ProcessHandleImpl_serenity.cpp
- @@ -0,0 +1,166 @@
- +/*
- + * 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 <AK/JsonArray.h>
- +#include <LibCore/DeprecatedFile.h>
- +#include <LibCore/File.h>
- +#include <LibCore/ProcessStatisticsReader.h>
- +#include <LibCore/Stream.h>
- +#include <stdio.h>
- +#include <string.h>
- +
- +/*
- + * 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<Core::DeprecatedFile> proc_all;
- +
- +extern "C" {
- +void os_initNative(JNIEnv *env, jclass clazz) {
- + proc_all = MUST(Core::DeprecatedFile::open("/sys/kernel/processes", 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.is_error()) {
- + 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 /sys/kernel/processes
- +
- + 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.is_error()) {
- + 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);
- +
- + auto cmdline_file = JAVA_TRY(Core::File::open(DeprecatedString::formatted("/proc/{}/cmdline", pid), Core::File::OpenMode::Read), "Unable to open /proc/pid/cmdline"sv);
- + auto contents = JAVA_TRY(cmdline_file->read_until_eof(), "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"sv);
- +
- + 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 2bf36f8f136794af4030e12c64026ab217696959..317bbf158a2032cc23ef3b73528a9e9c801612cf 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<LaunchMechanism> 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,
|