
We now create a WorkerAgent for the parent context, which is currently only a Window. Note that Workers can have Workers per the spec. The WorkerAgent spawns a WebWorker process to hold the actual script execution of the Worker. This is modeled with the DedicatedWorkerHost object in the WebWorker process. A start_dedicated_worker IPC method in the WebWorker IPC creates the WorkerHost object. Future different worker types may use different IPC messages to create their WorkerHost instance. This implementation cannot yet postMessage between the parent and the child processes. Co-Authored-By: Andreas Kling <kling@serenityos.org>
115 lines
3.7 KiB
C++
115 lines
3.7 KiB
C++
/*
|
|
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#include <AK/LexicalPath.h>
|
|
#include <LibCore/Socket.h>
|
|
#include <LibCore/System.h>
|
|
#include <LibWeb/HTML/WorkerAgent.h>
|
|
#include <LibWeb/Worker/WebWorkerClient.h>
|
|
|
|
// FIXME: Deduplicate this code with ladybird!!
|
|
|
|
#ifndef AK_OS_SERENITY
|
|
namespace {
|
|
|
|
ErrorOr<String> application_directory()
|
|
{
|
|
auto current_executable_path = TRY(Core::System::current_executable_path());
|
|
auto dirname = LexicalPath::dirname(current_executable_path.to_deprecated_string());
|
|
return String::from_deprecated_string(dirname);
|
|
}
|
|
|
|
ErrorOr<Vector<String>> get_paths_for_helper_process(StringView process_name)
|
|
{
|
|
auto application_path = TRY(application_directory());
|
|
Vector<String> paths;
|
|
|
|
TRY(paths.try_append(TRY(String::formatted("{}/{}", application_path, process_name))));
|
|
TRY(paths.try_append(TRY(String::formatted("./{}", process_name))));
|
|
// NOTE: Add platform-specific paths here
|
|
return paths;
|
|
}
|
|
|
|
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<String> candidate_web_content_paths)
|
|
{
|
|
int socket_fds[2] {};
|
|
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
|
|
|
|
int ui_fd = socket_fds[0];
|
|
int wc_fd = socket_fds[1];
|
|
|
|
int fd_passing_socket_fds[2] {};
|
|
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
|
|
|
|
int ui_fd_passing_fd = fd_passing_socket_fds[0];
|
|
int wc_fd_passing_fd = fd_passing_socket_fds[1];
|
|
|
|
if (auto child_pid = TRY(Core::System::fork()); child_pid == 0) {
|
|
TRY(Core::System::close(ui_fd_passing_fd));
|
|
TRY(Core::System::close(ui_fd));
|
|
|
|
auto takeover_string = TRY(String::formatted("WebWorker:{}", wc_fd));
|
|
TRY(Core::System::setenv("SOCKET_TAKEOVER"sv, takeover_string, true));
|
|
|
|
auto webcontent_fd_passing_socket_string = TRY(String::number(wc_fd_passing_fd));
|
|
|
|
ErrorOr<void> result;
|
|
for (auto const& path : candidate_web_content_paths) {
|
|
if (Core::System::access(path, X_OK).is_error())
|
|
continue;
|
|
|
|
auto arguments = Vector {
|
|
path.bytes_as_string_view(),
|
|
"--fd-passing-socket"sv,
|
|
webcontent_fd_passing_socket_string
|
|
};
|
|
|
|
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();
|
|
}
|
|
|
|
TRY(Core::System::close(wc_fd_passing_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) Web::HTML::WebWorkerClient(move(socket))));
|
|
new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
|
|
|
|
return new_client;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
namespace Web::HTML {
|
|
|
|
WorkerAgent::WorkerAgent(AK::URL url, WorkerOptions const& options)
|
|
: m_worker_options(options)
|
|
, m_url(move(url))
|
|
{
|
|
#ifndef AK_OS_SERENITY
|
|
// FIXME: Add factory function
|
|
auto paths = MUST(get_paths_for_helper_process("WebWorker"sv));
|
|
m_worker_ipc = MUST(launch_web_worker_process(paths));
|
|
#else
|
|
m_worker_ipc = MUST(Web::HTML::WebWorkerClient::try_create());
|
|
#endif
|
|
|
|
int fds[2] = {};
|
|
MUST(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fds));
|
|
m_message_port_fd = fds[0];
|
|
|
|
m_worker_ipc->async_start_dedicated_worker(m_url, options.type, options.credentials, options.name, fds[1]);
|
|
}
|
|
|
|
}
|