Files
ladybird/Libraries/LibIPC/TransportBootstrapMach.h
Aliaksandr Kalenik e47f4cf90f Everywhere: Simplify Mach bootstrap transport handshake
Previously, the bootstrap handshake used a two-state machine
(WaitingForPorts / WaitingForReplyPort) to handle a race: the parent
registering transport ports and the child sending a bootstrap request
could arrive in either order, so whichever came first stored its half
and the second completed the handshake.

Eliminate the race by holding a mutex across spawn() and
register_child_transport(). Since the child cannot send a bootstrap
request before it exists, and the lock isn't released until its
transport is registered, handle_bootstrap_request() is guaranteed to
find the entry. This reduces the pending map to a simple pid-to-ports
lookup and collapses the two-variant state into two straightforward
branches: known child, or on-demand (non-child) caller like WebDriver.
2026-03-24 19:51:52 +01:00

61 lines
1.9 KiB
C++

/*
* Copyright (c) 2026, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/HashMap.h>
#include <AK/Platform.h>
#include <AK/StringView.h>
#include <AK/Variant.h>
#if !defined(AK_OS_MACH)
# error "TransportBootstrapMach is only available on Mach platforms"
#endif
#include <LibCore/MachPort.h>
#include <LibThreading/Mutex.h>
namespace IPC {
struct TransportBootstrapMachPorts {
Core::MachPort receive_right;
Core::MachPort send_right;
};
ErrorOr<TransportBootstrapMachPorts> bootstrap_transport_from_mach_server(StringView server_name);
ErrorOr<TransportBootstrapMachPorts> bootstrap_transport_from_server_port(Core::MachPort const& server_port);
class TransportBootstrapMachServer {
AK_MAKE_NONCOPYABLE(TransportBootstrapMachServer);
public:
TransportBootstrapMachServer() = default;
struct ChildTransportHandled {
};
struct OnDemandTransport {
TransportBootstrapMachPorts ports;
};
using BootstrapRequestResult = Variant<ChildTransportHandled, OnDemandTransport>;
// Hold this lock across process spawn and child transport registration so a
// child bootstrap request cannot observe an unregistered pid.
Threading::Mutex& child_registration_lock() { return m_child_registration_mutex; }
// Must be called while holding child_registration_lock().
void register_child_transport(pid_t, TransportBootstrapMachPorts);
ErrorOr<BootstrapRequestResult> handle_bootstrap_request(pid_t, Core::MachPort reply_port);
private:
static void send_transport_ports_to_child(Core::MachPort reply_port, TransportBootstrapMachPorts ports);
static ErrorOr<TransportBootstrapMachPorts> create_on_demand_local_transport(Core::MachPort reply_port);
Threading::Mutex m_child_registration_mutex;
HashMap<pid_t, TransportBootstrapMachPorts> m_child_transports;
};
}