From 9fb84e4693e605bed838ed70d88f2678c4e207a7 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Tue, 23 Apr 2024 16:39:04 -0400 Subject: [PATCH] Ladybird: Use Core::Process facilities to spawn helper processes Note that WebContent now also uses launch_generic_server_process() instead of its own implementation. --- Ladybird/HelperProcess.cpp | 235 ++++++++++++++++--------------------- 1 file changed, 98 insertions(+), 137 deletions(-) diff --git a/Ladybird/HelperProcess.cpp b/Ladybird/HelperProcess.cpp index 8cb8aa927a..91629aa770 100644 --- a/Ladybird/HelperProcess.cpp +++ b/Ladybird/HelperProcess.cpp @@ -6,89 +6,104 @@ #include "HelperProcess.h" #include "Utilities.h" -#include +#include +#include #include #include +enum class RegisterWithProcessManager { + No, + Yes, +}; + +template +static ErrorOr> launch_server_process_impl( + StringView server_name, + ReadonlySpan candidate_server_paths, + Vector const& arguments, + RegisterWithProcessManager register_with_process_manager, + SpawnFunction&& spawn_function) +{ + for (auto [i, path] : enumerate(candidate_server_paths)) { + auto result = spawn_function(Core::ProcessSpawnOptions { + .name = server_name, + .executable = path, + .arguments = arguments, + }); + + if (!result.is_error()) { + auto process = result.release_value(); + + if (register_with_process_manager == RegisterWithProcessManager::Yes) + WebView::ProcessManager::the().add_process(WebView::process_type_from_name(server_name), process.process.pid()); + + return move(process.client); + } + + if (i == candidate_server_paths.size() - 1) { + warnln("Could not launch any of {}: {}", candidate_server_paths, result.error()); + return result.release_error(); + } + } + + VERIFY_NOT_REACHED(); +} + +template +static ErrorOr> launch_generic_server_process( + StringView server_name, + ReadonlySpan candidate_server_paths, + Vector const& arguments, + RegisterWithProcessManager register_with_process_manager, + ClientArguments&&... client_arguments) +{ + return launch_server_process_impl(server_name, candidate_server_paths, arguments, register_with_process_manager, [&](auto options) { + return Core::IPCProcess::spawn(move(options), forward(client_arguments)...); + }); +} + ErrorOr> launch_web_content_process( WebView::ViewImplementation& view, ReadonlySpan candidate_web_content_paths, Ladybird::WebContentOptions const& web_content_options, Optional request_server_socket) { - int socket_fds[2] {}; - TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); + Vector arguments { + "--command-line"sv, + web_content_options.command_line.to_byte_string(), + "--executable-path"sv, + web_content_options.executable_path.to_byte_string(), + }; - int ui_fd = socket_fds[0]; - int wc_fd = socket_fds[1]; - - auto child_pid = TRY(Core::System::fork()); - if (child_pid == 0) { - TRY(Core::System::close(ui_fd)); - - auto takeover_string = TRY(String::formatted("WebContent:{}", wc_fd)); - TRY(Core::Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Core::Environment::Overwrite::Yes)); - - ErrorOr result; - for (auto const& path : candidate_web_content_paths) { - constexpr auto callgrind_prefix_length = 3; - - if (Core::System::access(path, X_OK).is_error()) - continue; - - auto arguments = Vector { - "valgrind"sv, - "--tool=callgrind"sv, - "--instr-atstart=no"sv, - path.view(), - "--command-line"sv, - web_content_options.command_line, - "--executable-path"sv, - web_content_options.executable_path, - }; - if (web_content_options.enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::No) - arguments.remove(0, callgrind_prefix_length); - if (web_content_options.is_layout_test_mode == Ladybird::IsLayoutTestMode::Yes) - arguments.append("--layout-test-mode"sv); - if (web_content_options.use_lagom_networking == Ladybird::UseLagomNetworking::Yes) - arguments.append("--use-lagom-networking"sv); - if (web_content_options.enable_gpu_painting == Ladybird::EnableGPUPainting::Yes) - arguments.append("--use-gpu-painting"sv); - if (web_content_options.wait_for_debugger == Ladybird::WaitForDebugger::Yes) - arguments.append("--wait-for-debugger"sv); - if (web_content_options.log_all_js_exceptions == Ladybird::LogAllJSExceptions::Yes) - arguments.append("--log-all-js-exceptions"sv); - if (web_content_options.enable_idl_tracing == Ladybird::EnableIDLTracing::Yes) - arguments.append("--enable-idl-tracing"sv); - if (web_content_options.expose_internals_object == Ladybird::ExposeInternalsObject::Yes) - arguments.append("--expose-internals-object"sv); - if (auto server = mach_server_name(); server.has_value()) { - arguments.append("--mach-server-name"sv); - arguments.append(server.value()); - } - String fd_string; - if (request_server_socket.has_value()) { - arguments.append("--request-server-socket"sv); - fd_string = MUST(String::number(request_server_socket->fd())); - arguments.append(fd_string.bytes_as_string_view()); - } - - result = Core::System::exec(arguments[0], arguments.span(), Core::System::SearchInPath::Yes); - if (!result.is_error()) - break; - } - - if (result.is_error()) - warnln("Could not launch any of {}: {}", candidate_web_content_paths, result.error()); - VERIFY_NOT_REACHED(); + if (web_content_options.enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) { + arguments.prepend("--instr-atstart=no"sv); + arguments.prepend("--tool=callgrind"sv); + arguments.prepend("valgrind"sv); + } + if (web_content_options.is_layout_test_mode == Ladybird::IsLayoutTestMode::Yes) + arguments.append("--layout-test-mode"sv); + if (web_content_options.use_lagom_networking == Ladybird::UseLagomNetworking::Yes) + arguments.append("--use-lagom-networking"sv); + if (web_content_options.enable_gpu_painting == Ladybird::EnableGPUPainting::Yes) + arguments.append("--use-gpu-painting"sv); + if (web_content_options.wait_for_debugger == Ladybird::WaitForDebugger::Yes) + arguments.append("--wait-for-debugger"sv); + if (web_content_options.log_all_js_exceptions == Ladybird::LogAllJSExceptions::Yes) + arguments.append("--log-all-js-exceptions"sv); + if (web_content_options.enable_idl_tracing == Ladybird::EnableIDLTracing::Yes) + arguments.append("--enable-idl-tracing"sv); + if (web_content_options.expose_internals_object == Ladybird::ExposeInternalsObject::Yes) + arguments.append("--expose-internals-object"sv); + if (auto server = mach_server_name(); server.has_value()) { + arguments.append("--mach-server-name"sv); + arguments.append(server.value()); + } + if (request_server_socket.has_value()) { + arguments.append("--request-server-socket"sv); + arguments.append(ByteString::number(request_server_socket->fd())); } - TRY(Core::System::close(wc_fd)); - - auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd)); - TRY(socket->set_blocking(true)); - - auto new_client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebView::WebContentClient(move(socket), view))); + auto web_content_client = TRY(launch_generic_server_process("WebContent"sv, candidate_web_content_paths, arguments, RegisterWithProcessManager::No, view)); if (web_content_options.enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) { dbgln(); @@ -97,98 +112,44 @@ ErrorOr> launch_web_content_process( dbgln(); } - return new_client; -} - -template -ErrorOr> launch_generic_server_process(ReadonlySpan candidate_server_paths, StringView server_name, Vector extra_arguments = {}) -{ - int socket_fds[2] {}; - TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); - - int ui_fd = socket_fds[0]; - int server_fd = socket_fds[1]; - - auto child_pid = TRY(Core::System::fork()); - if (child_pid == 0) { - TRY(Core::System::close(ui_fd)); - - auto takeover_string = TRY(String::formatted("{}:{}", server_name, server_fd)); - TRY(Core::Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Core::Environment::Overwrite::Yes)); - - ErrorOr result; - for (auto const& path : candidate_server_paths) { - - if (Core::System::access(path, X_OK).is_error()) - continue; - - auto arguments = Vector { - path.view(), - }; - - if (!extra_arguments.is_empty()) - arguments.extend(extra_arguments); - - result = Core::System::exec(arguments[0], arguments.span(), Core::System::SearchInPath::Yes); - if (!result.is_error()) - break; - } - - if (result.is_error()) - warnln("Could not launch any of {}: {}", candidate_server_paths, result.error()); - VERIFY_NOT_REACHED(); - } - - TRY(Core::System::close(server_fd)); - - auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd)); - TRY(socket->set_blocking(true)); - - auto new_client = TRY(try_make_ref_counted(move(socket))); - - WebView::ProcessManager::the().add_process(WebView::process_type_from_name(server_name), child_pid); - - return new_client; + return web_content_client; } ErrorOr> launch_image_decoder_process(ReadonlySpan candidate_image_decoder_paths) { - return launch_generic_server_process(candidate_image_decoder_paths, "ImageDecoder"sv); + return launch_generic_server_process("ImageDecoder"sv, candidate_image_decoder_paths, {}, RegisterWithProcessManager::Yes); } ErrorOr> launch_web_worker_process(ReadonlySpan candidate_web_worker_paths, NonnullRefPtr request_client) { auto socket = TRY(connect_new_request_server_client(move(request_client))); - Vector arguments; - String fd_string = MUST(String::number(socket.fd())); + Vector arguments { + "--request-server-socket"sv, + ByteString::number(socket.fd()), + }; - arguments.append("--request-server-socket"sv); - arguments.append(fd_string.bytes_as_string_view()); - - return launch_generic_server_process(candidate_web_worker_paths, "WebWorker"sv, move(arguments)); + return launch_generic_server_process("WebWorker"sv, candidate_web_worker_paths, arguments, RegisterWithProcessManager::Yes); } ErrorOr> launch_request_server_process(ReadonlySpan candidate_request_server_paths, StringView serenity_resource_root, Vector const& certificates) { - Vector arguments; + Vector arguments; + if (!serenity_resource_root.is_empty()) { arguments.append("--serenity-resource-root"sv); arguments.append(serenity_resource_root); } - Vector certificate_args; - for (auto const& certificate : certificates) { - certificate_args.append(ByteString::formatted("--certificate={}", certificate)); - arguments.append(certificate_args.last().view()); - } + for (auto const& certificate : certificates) + arguments.append(ByteString::formatted("--certificate={}", certificate)); if (auto server = mach_server_name(); server.has_value()) { arguments.append("--mach-server-name"sv); arguments.append(server.value()); } - return launch_generic_server_process(candidate_request_server_paths, "RequestServer"sv, move(arguments)); + return launch_generic_server_process("RequestServer"sv, candidate_request_server_paths, arguments, RegisterWithProcessManager::Yes); } ErrorOr> launch_sql_server_process(ReadonlySpan candidate_sql_server_paths)