Mach transport already sends payloads as out-of-line virtual-copy regions, but the receive path immediately copied each payload into a new Vector and deallocated the kernel mapping. That made the IPC IO thread touch every byte before the main thread could decode the message. Add ReceivedMessageBytes as the raw-message byte storage and let the Mach transport adopt the OOL region directly. The mapping now lives until the raw message storage is destroyed, so invalid descriptor paths and normal queue teardown both release it through the same destructor. Socket transports keep their existing receive copy path by wrapping vectors in the same storage type, and the direct raw-message consumers now decode from its ReadonlyBytes view.
120 lines
3.3 KiB
C++
120 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/Forward.h>
|
|
#include <LibIPC/ReceivedMessageBytes.h>
|
|
#include <LibIPC/TransportHandle.h>
|
|
#include <LibSync/ConditionVariable.h>
|
|
#include <LibSync/Mutex.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();
|
|
|
|
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(MessageDataType, Vector<Attachment>& attachments);
|
|
|
|
enum class ShouldShutdown {
|
|
No,
|
|
Yes,
|
|
};
|
|
struct Message {
|
|
ReceivedMessageBytes 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 {
|
|
MessageDataType 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 };
|
|
// 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<bool> m_is_being_transferred { false };
|
|
|
|
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;
|
|
Sync::Mutex m_send_mutex;
|
|
Vector<u8> m_send_buffer;
|
|
|
|
Sync::Mutex m_incoming_mutex;
|
|
Sync::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;
|
|
};
|
|
|
|
}
|