ladybird/Libraries/LibIPC/TransportMachPort.h
Aliaksandr Kalenik 4ea4d63008 Everywhere: Replace Unix socket IPC transport with Mach ports on macOS
On macOS, use Mach port messaging instead of Unix domain sockets for
all IPC transport. This makes the transport capable of carrying Mach
port rights as message attachments, which is a prerequisite for sending
IOSurface handles over the main IPC channel (currently sent via a
separate out-of-band path). It also avoids the need for the FD
acknowledgement protocol that TransportSocket requires, since Mach port
right transfers are atomic in the kernel.

Three connection establishment patterns:

- Spawned helper processes (WebContent, RequestServer, etc.) use the
  existing MachPortServer: the child sends its task port with a reply
  port, and the parent responds with a pre-created port pair.

- Socket-bootstrapped connections (WebDriver, BrowserProcess) exchange
  Mach port names over the socket, then drop the socket.

- Pre-created pairs for IPC tests and in-message transport transfer.

Attachment on macOS now wraps a MachPort instead of a file descriptor,
converting between the two via fileport_makeport()/fileport_makefd().

The LibIPC socket transport tests are disabled on macOS since they are
socket-specific.
2026-03-23 18:50:48 +01:00

119 lines
3.3 KiB
C++

/*
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Platform.h>
#if !defined(AK_OS_MACOS)
# error "TransportMachPort is only available on macOS"
#endif
#include <AK/Atomic.h>
#include <AK/Queue.h>
#include <AK/RefPtr.h>
#include <AK/Vector.h>
#include <LibCore/MachPort.h>
#include <LibCore/Notifier.h>
#include <LibIPC/Attachment.h>
#include <LibIPC/AutoCloseFileDescriptor.h>
#include <LibIPC/TransportHandle.h>
#include <LibThreading/ConditionVariable.h>
#include <LibThreading/Thread.h>
namespace IPC {
class TransportMachPort {
AK_MAKE_NONCOPYABLE(TransportMachPort);
AK_MAKE_NONMOVABLE(TransportMachPort);
public:
struct Paired {
NonnullOwnPtr<TransportMachPort> local;
TransportHandle remote_handle;
};
static ErrorOr<Paired> create_paired();
// Bootstrap a Mach port connection over an existing Unix socket.
// Used when the initial connection is socket-based (e.g., WebDriver).
// Both sides must call this concurrently on the same socket.
static ErrorOr<NonnullOwnPtr<TransportMachPort>> from_socket(NonnullOwnPtr<Core::LocalSocket> socket);
TransportMachPort(Core::MachPort receive_right, Core::MachPort send_right);
~TransportMachPort();
void set_up_read_hook(Function<void()>);
bool is_open() const;
void close();
void close_after_sending_all_pending_messages();
void wait_until_readable();
void post_message(Vector<u8> const&, Vector<Attachment>& attachments);
enum class ShouldShutdown {
No,
Yes,
};
struct Message {
Vector<u8> bytes;
Queue<Attachment> attachments;
};
ShouldShutdown read_as_many_messages_as_possible_without_blocking(Function<void(Message&&)>&&);
ErrorOr<TransportHandle> release_for_transfer();
private:
static constexpr unsigned int IPC_DATA_MESSAGE_ID = 0x4950C001;
static constexpr unsigned int IPC_WAKEUP_MESSAGE_ID = 0x4950C003;
struct PendingMessage {
Vector<u8> bytes;
Vector<Attachment> attachments;
};
enum class IOThreadState {
Running,
SendPendingMessagesAndStop,
Stopped,
};
intptr_t io_thread_loop();
void stop_io_thread(IOThreadState desired_state);
void wake_io_thread();
void notify_read_available();
void mark_peer_eof();
void send_mach_message(PendingMessage&);
void process_received_message(u8* buffer);
Core::MachPort m_receive_port;
Core::MachPort m_send_port;
Core::MachPort m_port_set;
Core::MachPort m_wakeup_receive_port;
Core::MachPort m_wakeup_send_port;
Atomic<bool> m_is_open { true };
RefPtr<Threading::Thread> m_io_thread;
Atomic<IOThreadState> m_io_thread_state { IOThreadState::Running };
Atomic<bool> m_peer_eof { false };
Vector<PendingMessage> m_pending_send_messages;
Threading::Mutex m_send_mutex;
Vector<u8> m_send_buffer;
Threading::Mutex m_incoming_mutex;
Threading::ConditionVariable m_incoming_cv { m_incoming_mutex };
Vector<NonnullOwnPtr<Message>> m_incoming_messages;
RefPtr<AutoCloseFileDescriptor> m_notify_hook_read_fd;
RefPtr<AutoCloseFileDescriptor> m_notify_hook_write_fd;
RefPtr<Core::Notifier> m_read_hook_notifier;
Function<void()> m_on_read_hook;
};
}