Everywhere: Move Mach bootstrap listener into LibIPC

Move MachPortServer from LibWebView into LibIPC as MachBootstrapListener
and move the Mach message structs from MachMessageTypes.h into LibIPC.

These types are IPC infrastructure, not UI or platform concerns.
Consolidating them in LibIPC keeps the Mach bootstrap handshake
self-contained in a single library and removes LibWebView's dependency
on LibThreading.
This commit is contained in:
Aliaksandr Kalenik
2026-03-24 07:28:28 +01:00
committed by Alexander Kalenik
parent e47f4cf90f
commit 1d025620e3
Notes: github-actions[bot] 2026-03-24 18:53:16 +00:00
12 changed files with 42 additions and 44 deletions

View File

@@ -10,6 +10,7 @@ if (APPLE AND NOT IOS)
list(APPEND SOURCES
AttachmentMachPort.cpp
File.cpp
MachBootstrapListener.cpp
Message.cpp
TransportBootstrapMach.cpp
TransportMachPort.cpp)

View File

@@ -22,6 +22,7 @@ class Stub;
class TransportHandle;
#if defined(AK_OS_MACOS)
class MachBootstrapListener;
class TransportMachPort;
using Transport = TransportMachPort;
#elif !defined(AK_OS_WINDOWS)

View File

@@ -5,14 +5,14 @@
*/
#include <AK/Debug.h>
#include <LibCore/Platform/MachMessageTypes.h>
#include <LibIPC/MachBootstrapListener.h>
#include <LibIPC/MachBootstrapMessages.h>
#include <LibThreading/Thread.h>
#include <LibWebView/MachPortServer.h>
namespace WebView {
namespace IPC {
MachPortServer::MachPortServer(ByteString server_port_name)
: m_thread(Threading::Thread::construct("MachPortServer"sv, [this]() -> intptr_t { thread_loop(); return 0; }))
MachBootstrapListener::MachBootstrapListener(ByteString server_port_name)
: m_thread(Threading::Thread::construct("MachBootstrapListener"sv, [this]() -> intptr_t { thread_loop(); return 0; }))
, m_server_port_name(move(server_port_name))
{
if (auto err = allocate_server_port(); err.is_error())
@@ -21,29 +21,29 @@ MachPortServer::MachPortServer(ByteString server_port_name)
start();
}
MachPortServer::~MachPortServer()
MachBootstrapListener::~MachBootstrapListener()
{
stop();
}
void MachPortServer::start()
void MachBootstrapListener::start()
{
m_thread->start();
}
void MachPortServer::stop()
void MachBootstrapListener::stop()
{
// FIXME: We should join instead (after storing should_stop = false) when we have a way to interrupt the thread's mach_msg call
m_thread->detach();
m_should_stop.store(true, MemoryOrder::memory_order_release);
}
bool MachPortServer::is_initialized()
bool MachBootstrapListener::is_initialized()
{
return MACH_PORT_VALID(m_server_port_recv_right.port()) && MACH_PORT_VALID(m_server_port_send_right.port());
}
ErrorOr<void> MachPortServer::allocate_server_port()
ErrorOr<void> MachBootstrapListener::allocate_server_port()
{
m_server_port_recv_right = TRY(Core::MachPort::create_with_right(Core::MachPort::PortRight::Receive));
m_server_port_send_right = TRY(m_server_port_recv_right.insert_right(Core::MachPort::MessageRight::MakeSend));
@@ -53,10 +53,10 @@ ErrorOr<void> MachPortServer::allocate_server_port()
return {};
}
void MachPortServer::thread_loop()
void MachBootstrapListener::thread_loop()
{
while (!m_should_stop.load(MemoryOrder::memory_order_acquire)) {
Core::Platform::ReceivedMachMessage message {};
ReceivedMachMessage message {};
// Get the pid of the child from the audit trailer so we can associate the port w/it
mach_msg_options_t const options = MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
@@ -68,7 +68,7 @@ void MachPortServer::thread_loop()
break;
}
if (message.header.msgh_id == Core::Platform::SELF_TASK_PORT_MESSAGE_ID) {
if (message.header.msgh_id == SELF_TASK_PORT_MESSAGE_ID) {
auto const& task_port_message = message.body;
VERIFY(MACH_MSGH_BITS_LOCAL(message.header.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND);
VERIFY(task_port_message.body.msgh_descriptor_count == 1);

View File

@@ -7,23 +7,24 @@
#pragma once
#include <AK/Atomic.h>
#include <AK/Function.h>
#include <AK/Platform.h>
#include <AK/String.h>
#include <LibCore/MachPort.h>
#include <LibThreading/Forward.h>
#include <LibWebView/Forward.h>
#if !defined(AK_OS_MACH)
# error "This file is only for Mach kernel-based OS's"
# error "MachBootstrapListener is only available on Mach kernel-based OS's"
#endif
namespace WebView {
namespace IPC {
class WEBVIEW_API MachPortServer {
class MachBootstrapListener {
AK_MAKE_NONCOPYABLE(MachBootstrapListener);
public:
explicit MachPortServer(ByteString server_port_name);
~MachPortServer();
explicit MachBootstrapListener(ByteString server_port_name);
~MachBootstrapListener();
void start();
void stop();

View File

@@ -16,7 +16,7 @@
#include <mach/mach.h>
namespace Core::Platform {
namespace IPC {
struct MessageBodyWithSelfTaskPort {
mach_msg_body_t body;

View File

@@ -8,8 +8,8 @@
#include <AK/ByteString.h>
#include <AK/Optional.h>
#include <LibCore/MachPort.h>
#include <LibCore/Platform/MachMessageTypes.h>
#include <LibCore/System.h>
#include <LibIPC/MachBootstrapMessages.h>
#include <LibIPC/TransportBootstrapMach.h>
#include <mach/mach.h>
@@ -20,12 +20,12 @@ ErrorOr<TransportBootstrapMachPorts> bootstrap_transport_from_server_port(Core::
{
auto reply_port = TRY(Core::MachPort::create_with_right(Core::MachPort::PortRight::Receive));
Core::Platform::MessageWithSelfTaskPort message {};
MessageWithSelfTaskPort message {};
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE) | MACH_MSGH_BITS_COMPLEX;
message.header.msgh_size = sizeof(message);
message.header.msgh_remote_port = server_port.port();
message.header.msgh_local_port = reply_port.port();
message.header.msgh_id = Core::Platform::SELF_TASK_PORT_MESSAGE_ID;
message.header.msgh_id = SELF_TASK_PORT_MESSAGE_ID;
message.body.msgh_descriptor_count = 1;
message.port_descriptor.name = mach_task_self();
message.port_descriptor.disposition = MACH_MSG_TYPE_COPY_SEND;
@@ -36,14 +36,14 @@ ErrorOr<TransportBootstrapMachPorts> bootstrap_transport_from_server_port(Core::
if (send_result != KERN_SUCCESS)
return Core::mach_error_to_error(send_result);
Core::Platform::ReceivedIPCChannelPortsMessage reply {};
ReceivedIPCChannelPortsMessage reply {};
mach_msg_timeout_t const reply_timeout = 5000;
auto const recv_result = mach_msg(&reply.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(reply),
reply_port.port(), reply_timeout, MACH_PORT_NULL);
if (recv_result != KERN_SUCCESS)
return Core::mach_error_to_error(recv_result);
VERIFY(reply.header.msgh_id == Core::Platform::IPC_CHANNEL_PORTS_MESSAGE_ID);
VERIFY(reply.header.msgh_id == IPC_CHANNEL_PORTS_MESSAGE_ID);
VERIFY(reply.body.msgh_descriptor_count == 2);
VERIFY(reply.receive_port.type == MACH_MSG_PORT_DESCRIPTOR);
VERIFY(reply.receive_port.disposition == MACH_MSG_TYPE_MOVE_RECEIVE);
@@ -64,12 +64,12 @@ ErrorOr<TransportBootstrapMachPorts> bootstrap_transport_from_mach_server(String
void TransportBootstrapMachServer::send_transport_ports_to_child(Core::MachPort reply_port, TransportBootstrapMachPorts ports)
{
Core::Platform::MessageWithIPCChannelPorts message {};
MessageWithIPCChannelPorts message {};
message.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0) | MACH_MSGH_BITS_COMPLEX;
message.header.msgh_size = sizeof(message);
message.header.msgh_remote_port = reply_port.release();
message.header.msgh_local_port = MACH_PORT_NULL;
message.header.msgh_id = Core::Platform::IPC_CHANNEL_PORTS_MESSAGE_ID;
message.header.msgh_id = IPC_CHANNEL_PORTS_MESSAGE_ID;
message.body.msgh_descriptor_count = 2;
message.receive_port.name = ports.receive_right.release();
message.receive_port.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;

View File

@@ -27,9 +27,9 @@
#include <LibWebView/WebContentClient.h>
#if defined(AK_OS_MACOS)
# include <LibIPC/MachBootstrapListener.h>
# include <LibIPC/Transport.h>
# include <LibIPC/TransportBootstrapMach.h>
# include <LibWebView/MachPortServer.h>
#endif
namespace WebView {
@@ -103,10 +103,10 @@ ErrorOr<void> Application::initialize(Main::Arguments const& arguments)
#endif
#if defined(AK_OS_MACOS)
m_mach_port_server = make<MachPortServer>(mach_server_name_for_process("Ladybird"sv, Core::System::getpid()));
m_mach_port_server = make<IPC::MachBootstrapListener>(mach_server_name_for_process("Ladybird"sv, Core::System::getpid()));
set_mach_server_name(m_mach_port_server->server_port_name());
m_mach_port_server->on_bootstrap_request = [this](MachPortServer::BootstrapRequest request) {
m_mach_port_server->on_bootstrap_request = [this](IPC::MachBootstrapListener::BootstrapRequest request) {
set_process_mach_port(request.pid, move(request.task_port));
auto result = MUST(m_transport_bootstrap_server.handle_bootstrap_request(request.pid, move(request.reply_port)));
result.visit(

View File

@@ -294,7 +294,7 @@ private:
FileDownloader m_file_downloader;
#if defined(AK_OS_MACOS)
OwnPtr<MachPortServer> m_mach_port_server;
OwnPtr<IPC::MachBootstrapListener> m_mach_port_server;
IPC::TransportBootstrapMachServer m_transport_bootstrap_server;
Function<void(NonnullOwnPtr<IPC::Transport>)> m_on_browser_process_transport;
#endif

View File

@@ -1,3 +1,5 @@
include(fontconfig)
set(SOURCES
Application.cpp
Attribute.cpp
@@ -31,10 +33,6 @@ set(SOURCES
WebUI/SettingsUI.cpp
)
if (APPLE)
list(APPEND SOURCES MachPortServer.cpp)
endif()
set(GENERATED_SOURCES ${CURRENT_LIB_GENERATED})
embed_as_string(
@@ -70,8 +68,9 @@ set(GENERATED_SOURCES
ladybird_lib(LibWebView webview EXPLICIT_SYMBOL_EXPORT)
target_link_libraries(LibWebView PRIVATE LibCore LibDatabase LibDevTools LibFileSystem LibGfx LibHTTP LibImageDecoderClient LibIPC LibRequests LibJS LibWeb LibUnicode LibURL LibSyntax LibTextCodec)
if (APPLE)
target_link_libraries(LibWebView PRIVATE LibThreading)
# Third-party
if (HAS_FONTCONFIG)
target_link_libraries(LibWebView PRIVATE Fontconfig::Fontconfig)
endif()
if (ENABLE_INSTALL_HEADERS)

View File

@@ -25,10 +25,6 @@ class ViewImplementation;
class WebContentClient;
class WebUI;
#if defined(AK_OS_MACOS)
class MachPortServer;
#endif
struct Attribute;
struct AutocompleteEngine;
struct BrowserOptions;

View File

@@ -271,7 +271,7 @@ ErrorOr<void> Session::create_server(NonnullRefPtr<ServerPromise> promise)
dbgln("Listening for WebDriver connection on {}", m_web_content_endpoint);
#if defined(AK_OS_MACOS)
m_web_content_mach_port_server = make<WebView::MachPortServer>(m_web_content_endpoint);
m_web_content_mach_port_server = make<IPC::MachBootstrapListener>(m_web_content_endpoint);
if (!m_web_content_mach_port_server->is_initialized())
return Error::from_string_literal("Failed to initialize Mach port server for WebDriver");

View File

@@ -19,8 +19,8 @@
#if !defined(AK_OS_MACOS)
# include <LibCore/LocalServer.h>
#else
# include <LibIPC/MachBootstrapListener.h>
# include <LibIPC/TransportBootstrapMach.h>
# include <LibWebView/MachPortServer.h>
#endif
#include <LibCore/Process.h>
#include <LibCore/Promise.h>
@@ -115,7 +115,7 @@ private:
NonnullRefPtr<Core::WeakEventLoopReference> m_event_loop;
#if defined(AK_OS_MACOS)
OwnPtr<WebView::MachPortServer> m_web_content_mach_port_server;
OwnPtr<IPC::MachBootstrapListener> m_web_content_mach_port_server;
IPC::TransportBootstrapMachServer m_transport_bootstrap_server;
#else
RefPtr<Core::LocalServer> m_web_content_server;