mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
LibWebView+LibCore: Move IPCProcess into WebView::Process
Ladybird's HelperProcess.cpp was the only user of the IPCProcess class. Moving the helper class from LibCore allows for some more interesting LibIPC changes in the upcoming commits.
This commit is contained in:
parent
e537adad77
commit
9a6eccc590
Notes:
github-actions[bot]
2024-10-23 19:14:21 +00:00
Author: https://github.com/ADKaster Commit: https://github.com/LadybirdBrowser/ladybird/commit/9a6eccc5904 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1925 Reviewed-by: https://github.com/awesomekling Reviewed-by: https://github.com/trflynn89
6 changed files with 144 additions and 151 deletions
|
@ -42,15 +42,15 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
|||
options.executable = path;
|
||||
}
|
||||
|
||||
auto result = Core::IPCProcess::spawn<ClientType>(move(options), forward<ClientArguments>(client_arguments)...);
|
||||
auto result = WebView::Process::spawn<ClientType>(process_type, move(options), forward<ClientArguments>(client_arguments)...);
|
||||
|
||||
if (!result.is_error()) {
|
||||
auto process = result.release_value();
|
||||
auto&& [process, client] = result.release_value();
|
||||
|
||||
if constexpr (requires { process.client->set_pid(pid_t {}); })
|
||||
process.client->set_pid(process.process.pid());
|
||||
if constexpr (requires { client->set_pid(pid_t {}); })
|
||||
client->set_pid(process.pid());
|
||||
|
||||
WebView::Application::the().add_child_process(WebView::Process { process_type, process.client, move(process.process) });
|
||||
WebView::Application::the().add_child_process(move(process));
|
||||
|
||||
if (chrome_options.profile_helper_process == process_type) {
|
||||
dbgln();
|
||||
|
@ -59,7 +59,7 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
|||
dbgln();
|
||||
}
|
||||
|
||||
return move(process.client);
|
||||
return move(client);
|
||||
}
|
||||
|
||||
if (i == candidate_server_paths.size() - 1) {
|
||||
|
|
|
@ -14,9 +14,6 @@
|
|||
#include <LibCore/Environment.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/Process.h>
|
||||
#include <LibCore/Socket.h>
|
||||
#include <LibCore/SocketAddress.h>
|
||||
#include <LibCore/StandardPaths.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
@ -363,101 +360,4 @@ ErrorOr<bool> Process::wait_for_termination()
|
|||
return exited_with_code_0;
|
||||
}
|
||||
|
||||
ErrorOr<IPCProcess::ProcessAndIPCSocket> IPCProcess::spawn_and_connect_to_process(ProcessSpawnOptions const& options)
|
||||
{
|
||||
int socket_fds[2] {};
|
||||
TRY(System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
|
||||
|
||||
ArmedScopeGuard guard_fd_0 { [&] { MUST(System::close(socket_fds[0])); } };
|
||||
ArmedScopeGuard guard_fd_1 { [&] { MUST(System::close(socket_fds[1])); } };
|
||||
|
||||
auto& file_actions = const_cast<ProcessSpawnOptions&>(options).file_actions;
|
||||
file_actions.append(FileAction::CloseFile { socket_fds[0] });
|
||||
|
||||
auto takeover_string = MUST(String::formatted("{}:{}", options.name, socket_fds[1]));
|
||||
TRY(Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Environment::Overwrite::Yes));
|
||||
|
||||
auto process = TRY(Process::spawn(options));
|
||||
|
||||
auto ipc_socket = TRY(LocalSocket::adopt_fd(socket_fds[0]));
|
||||
guard_fd_0.disarm();
|
||||
TRY(ipc_socket->set_blocking(true));
|
||||
|
||||
return ProcessAndIPCSocket { move(process), move(ipc_socket) };
|
||||
}
|
||||
|
||||
ErrorOr<Optional<pid_t>> IPCProcess::get_process_pid(StringView process_name, StringView pid_path)
|
||||
{
|
||||
if (System::stat(pid_path).is_error())
|
||||
return OptionalNone {};
|
||||
|
||||
Optional<pid_t> pid;
|
||||
{
|
||||
auto pid_file = File::open(pid_path, File::OpenMode::Read);
|
||||
if (pid_file.is_error()) {
|
||||
warnln("Could not open {} PID file '{}': {}", process_name, pid_path, pid_file.error());
|
||||
return pid_file.release_error();
|
||||
}
|
||||
|
||||
auto contents = pid_file.value()->read_until_eof();
|
||||
if (contents.is_error()) {
|
||||
warnln("Could not read {} PID file '{}': {}", process_name, pid_path, contents.error());
|
||||
return contents.release_error();
|
||||
}
|
||||
|
||||
pid = StringView { contents.value() }.to_number<pid_t>();
|
||||
}
|
||||
|
||||
if (!pid.has_value()) {
|
||||
warnln("{} PID file '{}' exists, but with an invalid PID", process_name, pid_path);
|
||||
TRY(System::unlink(pid_path));
|
||||
return OptionalNone {};
|
||||
}
|
||||
if (kill(*pid, 0) < 0) {
|
||||
warnln("{} PID file '{}' exists with PID {}, but process cannot be found", process_name, pid_path, *pid);
|
||||
TRY(System::unlink(pid_path));
|
||||
return OptionalNone {};
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
// This is heavily based on how SystemServer's Service creates its socket.
|
||||
ErrorOr<int> IPCProcess::create_ipc_socket(ByteString const& socket_path)
|
||||
{
|
||||
if (!System::stat(socket_path).is_error())
|
||||
TRY(System::unlink(socket_path));
|
||||
|
||||
#ifdef SOCK_NONBLOCK
|
||||
auto socket_fd = TRY(System::socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
#else
|
||||
auto socket_fd = TRY(System::socket(AF_LOCAL, SOCK_STREAM, 0));
|
||||
|
||||
int option = 1;
|
||||
TRY(System::ioctl(socket_fd, FIONBIO, &option));
|
||||
TRY(System::fcntl(socket_fd, F_SETFD, FD_CLOEXEC));
|
||||
#endif
|
||||
|
||||
#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_GNU_HURD)
|
||||
TRY(System::fchmod(socket_fd, 0600));
|
||||
#endif
|
||||
|
||||
auto socket_address = SocketAddress::local(socket_path);
|
||||
auto socket_address_un = socket_address.to_sockaddr_un().release_value();
|
||||
|
||||
TRY(System::bind(socket_fd, reinterpret_cast<sockaddr*>(&socket_address_un), sizeof(socket_address_un)));
|
||||
TRY(System::listen(socket_fd, 16));
|
||||
|
||||
return socket_fd;
|
||||
}
|
||||
|
||||
ErrorOr<IPCProcess::ProcessPaths> IPCProcess::paths_for_process(StringView process_name)
|
||||
{
|
||||
auto runtime_directory = TRY(StandardPaths::runtime_directory());
|
||||
auto socket_path = ByteString::formatted("{}/{}.socket", runtime_directory, process_name);
|
||||
auto pid_path = ByteString::formatted("{}/{}.pid", runtime_directory, process_name);
|
||||
|
||||
return ProcessPaths { move(socket_path), move(pid_path) };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
#include <AK/Forward.h>
|
||||
#include <AK/Span.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/Socket.h>
|
||||
|
||||
namespace Core {
|
||||
|
||||
|
@ -45,8 +44,6 @@ struct ProcessSpawnOptions {
|
|||
Vector<FileActionType> file_actions {};
|
||||
};
|
||||
|
||||
class IPCProcess;
|
||||
|
||||
class Process {
|
||||
AK_MAKE_NONCOPYABLE(Process);
|
||||
|
||||
|
@ -102,8 +99,6 @@ public:
|
|||
ErrorOr<bool> wait_for_termination();
|
||||
|
||||
private:
|
||||
friend IPCProcess;
|
||||
|
||||
Process(pid_t pid)
|
||||
: m_pid(pid)
|
||||
, m_should_disown(true)
|
||||
|
@ -114,41 +109,4 @@ private:
|
|||
bool m_should_disown;
|
||||
};
|
||||
|
||||
class IPCProcess {
|
||||
public:
|
||||
template<typename ClientType>
|
||||
struct ProcessAndIPCClient {
|
||||
Process process;
|
||||
NonnullRefPtr<ClientType> client;
|
||||
};
|
||||
|
||||
template<typename ClientType, typename... ClientArguments>
|
||||
static ErrorOr<ProcessAndIPCClient<ClientType>> spawn(ProcessSpawnOptions const& options, ClientArguments&&... client_arguments)
|
||||
{
|
||||
auto [process, socket] = TRY(spawn_and_connect_to_process(options));
|
||||
auto client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ClientType { move(socket), forward<ClientArguments>(client_arguments)... }));
|
||||
|
||||
return ProcessAndIPCClient<ClientType> { move(process), move(client) };
|
||||
}
|
||||
|
||||
struct ProcessPaths {
|
||||
ByteString socket_path;
|
||||
ByteString pid_path;
|
||||
};
|
||||
static ErrorOr<ProcessPaths> paths_for_process(StringView process_name);
|
||||
static ErrorOr<Optional<pid_t>> get_process_pid(StringView process_name, StringView pid_path);
|
||||
static ErrorOr<int> create_ipc_socket(ByteString const& socket_path);
|
||||
|
||||
pid_t pid() const { return m_process.pid(); }
|
||||
|
||||
private:
|
||||
struct ProcessAndIPCSocket {
|
||||
Process process;
|
||||
NonnullOwnPtr<Core::LocalSocket> m_ipc_socket;
|
||||
};
|
||||
static ErrorOr<ProcessAndIPCSocket> spawn_and_connect_to_process(ProcessSpawnOptions const& options);
|
||||
|
||||
Process m_process;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -29,9 +29,9 @@ ErrorOr<ChromeProcess::ProcessDisposition> ChromeProcess::connect(Vector<ByteStr
|
|||
{
|
||||
static constexpr auto process_name = "Ladybird"sv;
|
||||
|
||||
auto [socket_path, pid_path] = TRY(Core::IPCProcess::paths_for_process(process_name));
|
||||
auto [socket_path, pid_path] = TRY(Process::paths_for_process(process_name));
|
||||
|
||||
if (auto pid = TRY(Core::IPCProcess::get_process_pid(process_name, pid_path)); pid.has_value()) {
|
||||
if (auto pid = TRY(Process::get_process_pid(process_name, pid_path)); pid.has_value()) {
|
||||
TRY(connect_as_client(socket_path, raw_urls, new_window));
|
||||
return ProcessDisposition::ExitProcess;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ ErrorOr<void> ChromeProcess::connect_as_client(ByteString const& socket_path, Ve
|
|||
|
||||
ErrorOr<void> ChromeProcess::connect_as_server(ByteString const& socket_path)
|
||||
{
|
||||
auto socket_fd = TRY(Core::IPCProcess::create_ipc_socket(socket_path));
|
||||
auto socket_fd = TRY(Process::create_ipc_socket(socket_path));
|
||||
m_socket_path = socket_path;
|
||||
auto local_server = TRY(Core::LocalServer::try_create());
|
||||
TRY(local_server->take_over_fd(socket_fd));
|
||||
|
|
|
@ -4,7 +4,9 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibCore/Environment.h>
|
||||
#include <LibCore/Process.h>
|
||||
#include <LibCore/StandardPaths.h>
|
||||
#include <LibWebView/Process.h>
|
||||
|
||||
namespace WebView {
|
||||
|
@ -22,4 +24,101 @@ Process::~Process()
|
|||
m_connection->shutdown();
|
||||
}
|
||||
|
||||
ErrorOr<Process::ProcessAndIPCSocket> Process::spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options)
|
||||
{
|
||||
int socket_fds[2] {};
|
||||
TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
|
||||
|
||||
ArmedScopeGuard guard_fd_0 { [&] { MUST(Core::System::close(socket_fds[0])); } };
|
||||
ArmedScopeGuard guard_fd_1 { [&] { MUST(Core::System::close(socket_fds[1])); } };
|
||||
|
||||
auto& file_actions = const_cast<Core::ProcessSpawnOptions&>(options).file_actions;
|
||||
file_actions.append(Core::FileAction::CloseFile { socket_fds[0] });
|
||||
|
||||
auto takeover_string = MUST(String::formatted("{}:{}", options.name, socket_fds[1]));
|
||||
TRY(Core::Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Core::Environment::Overwrite::Yes));
|
||||
|
||||
auto process = TRY(Core::Process::spawn(options));
|
||||
|
||||
auto ipc_socket = TRY(Core::LocalSocket::adopt_fd(socket_fds[0]));
|
||||
guard_fd_0.disarm();
|
||||
TRY(ipc_socket->set_blocking(true));
|
||||
|
||||
return ProcessAndIPCSocket { move(process), move(ipc_socket) };
|
||||
}
|
||||
|
||||
ErrorOr<Optional<pid_t>> Process::get_process_pid(StringView process_name, StringView pid_path)
|
||||
{
|
||||
if (Core::System::stat(pid_path).is_error())
|
||||
return OptionalNone {};
|
||||
|
||||
Optional<pid_t> pid;
|
||||
{
|
||||
auto pid_file = Core::File::open(pid_path, Core::File::OpenMode::Read);
|
||||
if (pid_file.is_error()) {
|
||||
warnln("Could not open {} PID file '{}': {}", process_name, pid_path, pid_file.error());
|
||||
return pid_file.release_error();
|
||||
}
|
||||
|
||||
auto contents = pid_file.value()->read_until_eof();
|
||||
if (contents.is_error()) {
|
||||
warnln("Could not read {} PID file '{}': {}", process_name, pid_path, contents.error());
|
||||
return contents.release_error();
|
||||
}
|
||||
|
||||
pid = StringView { contents.value() }.to_number<pid_t>();
|
||||
}
|
||||
|
||||
if (!pid.has_value()) {
|
||||
warnln("{} PID file '{}' exists, but with an invalid PID", process_name, pid_path);
|
||||
TRY(Core::System::unlink(pid_path));
|
||||
return OptionalNone {};
|
||||
}
|
||||
if (kill(*pid, 0) < 0) {
|
||||
warnln("{} PID file '{}' exists with PID {}, but process cannot be found", process_name, pid_path, *pid);
|
||||
TRY(Core::System::unlink(pid_path));
|
||||
return OptionalNone {};
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
// This is heavily based on how SystemServer's Service creates its socket.
|
||||
ErrorOr<int> Process::create_ipc_socket(ByteString const& socket_path)
|
||||
{
|
||||
if (!Core::System::stat(socket_path).is_error())
|
||||
TRY(Core::System::unlink(socket_path));
|
||||
|
||||
#ifdef SOCK_NONBLOCK
|
||||
auto socket_fd = TRY(Core::System::socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0));
|
||||
#else
|
||||
auto socket_fd = TRY(Core::System::socket(AF_LOCAL, SOCK_STREAM, 0));
|
||||
|
||||
int option = 1;
|
||||
TRY(Core::System::ioctl(socket_fd, FIONBIO, &option));
|
||||
TRY(Core::System::fcntl(socket_fd, F_SETFD, FD_CLOEXEC));
|
||||
#endif
|
||||
|
||||
#if !defined(AK_OS_BSD_GENERIC) && !defined(AK_OS_GNU_HURD)
|
||||
TRY(Core::System::fchmod(socket_fd, 0600));
|
||||
#endif
|
||||
|
||||
auto socket_address = Core::SocketAddress::local(socket_path);
|
||||
auto socket_address_un = socket_address.to_sockaddr_un().release_value();
|
||||
|
||||
TRY(Core::System::bind(socket_fd, reinterpret_cast<sockaddr*>(&socket_address_un), sizeof(socket_address_un)));
|
||||
TRY(Core::System::listen(socket_fd, 16));
|
||||
|
||||
return socket_fd;
|
||||
}
|
||||
|
||||
ErrorOr<Process::ProcessPaths> Process::paths_for_process(StringView process_name)
|
||||
{
|
||||
auto runtime_directory = TRY(Core::StandardPaths::runtime_directory());
|
||||
auto socket_path = ByteString::formatted("{}/{}.socket", runtime_directory, process_name);
|
||||
auto pid_path = ByteString::formatted("{}/{}.pid", runtime_directory, process_name);
|
||||
|
||||
return ProcessPaths { move(socket_path), move(pid_path) };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/String.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibCore/Process.h>
|
||||
#include <LibCore/Socket.h>
|
||||
#include <LibIPC/Connection.h>
|
||||
#include <LibWebView/ProcessType.h>
|
||||
|
||||
|
@ -22,6 +23,12 @@ public:
|
|||
Process(ProcessType type, RefPtr<IPC::ConnectionBase> connection, Core::Process process);
|
||||
~Process();
|
||||
|
||||
template<typename ClientType>
|
||||
struct ProcessAndClient;
|
||||
|
||||
template<typename ClientType, typename... ClientArguments>
|
||||
static ErrorOr<ProcessAndClient<ClientType>> spawn(ProcessType type, Core::ProcessSpawnOptions const& options, ClientArguments&&... client_arguments);
|
||||
|
||||
ProcessType type() const { return m_type; }
|
||||
Optional<String> const& title() const { return m_title; }
|
||||
void set_title(Optional<String> title) { m_title = move(title); }
|
||||
|
@ -36,11 +43,40 @@ public:
|
|||
|
||||
pid_t pid() const { return m_process.pid(); }
|
||||
|
||||
struct ProcessPaths {
|
||||
ByteString socket_path;
|
||||
ByteString pid_path;
|
||||
};
|
||||
static ErrorOr<ProcessPaths> paths_for_process(StringView process_name);
|
||||
static ErrorOr<Optional<pid_t>> get_process_pid(StringView process_name, StringView pid_path);
|
||||
static ErrorOr<int> create_ipc_socket(ByteString const& socket_path);
|
||||
|
||||
private:
|
||||
struct ProcessAndIPCSocket {
|
||||
Core::Process process;
|
||||
NonnullOwnPtr<Core::LocalSocket> socket;
|
||||
};
|
||||
static ErrorOr<ProcessAndIPCSocket> spawn_and_connect_to_process(Core::ProcessSpawnOptions const& options);
|
||||
|
||||
Core::Process m_process;
|
||||
ProcessType m_type;
|
||||
Optional<String> m_title;
|
||||
WeakPtr<IPC::ConnectionBase> m_connection;
|
||||
};
|
||||
|
||||
template<typename ClientType>
|
||||
struct Process::ProcessAndClient {
|
||||
Process process;
|
||||
NonnullRefPtr<ClientType> client;
|
||||
};
|
||||
|
||||
template<typename ClientType, typename... ClientArguments>
|
||||
ErrorOr<Process::ProcessAndClient<ClientType>> Process::spawn(ProcessType type, Core::ProcessSpawnOptions const& options, ClientArguments&&... client_arguments)
|
||||
{
|
||||
auto [core_process, socket] = TRY(spawn_and_connect_to_process(options));
|
||||
auto client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ClientType { move(socket), forward<ClientArguments>(client_arguments)... }));
|
||||
|
||||
return ProcessAndClient { Process { type, client, move(core_process) }, client };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue