/* * Copyright (c) 2026, Aliaksandr Kalenik * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #if !defined(AK_OS_MACOS) # error "TransportMachPort is only available on macOS" #endif #include #include #include #include #include #include #include #include #include #include #include namespace IPC { class TransportMachPort { AK_MAKE_NONCOPYABLE(TransportMachPort); AK_MAKE_NONMOVABLE(TransportMachPort); public: struct Paired { NonnullOwnPtr local; TransportHandle remote_handle; }; static ErrorOr create_paired(); TransportMachPort(Core::MachPort receive_right, Core::MachPort send_right); ~TransportMachPort(); void set_up_read_hook(Function); bool is_open() const; void close(); void close_after_sending_all_pending_messages(); void wait_until_readable(); void post_message(Vector const&, Vector& attachments); enum class ShouldShutdown { No, Yes, }; struct Message { Vector bytes; Queue attachments; }; ShouldShutdown read_as_many_messages_as_possible_without_blocking(Function&&); ErrorOr 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 bytes; Vector 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 m_is_open { true }; // True while release_for_transfer() is moving this transport's rights to a new owner. In that state, // shutdown from the old endpoint is part of the handoff and must not be reported as peer EOF. Atomic m_is_being_transferred { false }; RefPtr m_io_thread; Atomic m_io_thread_state { IOThreadState::Running }; Atomic m_peer_eof { false }; Vector m_pending_send_messages; Threading::Mutex m_send_mutex; Vector m_send_buffer; Threading::Mutex m_incoming_mutex; Threading::ConditionVariable m_incoming_cv { m_incoming_mutex }; Vector> m_incoming_messages; RefPtr m_notify_hook_read_fd; RefPtr m_notify_hook_write_fd; RefPtr m_read_hook_notifier; Function m_on_read_hook; }; }