Luna/libos/src/IPC.cpp
apio 909d0ed289
libos+wind+apps: Make IPC code object-oriented and add functionality for properly receiving messages
This functionality previously had to be repeated across all server programs using the IPC API.
2024-02-03 19:16:39 +01:00

88 lines
2.4 KiB
C++

/**
* @file IPC.cpp
* @author apio (cloudapio.eu)
* @brief Inter-process communication primitives.
*
* @copyright Copyright (c) 2023, the Luna authors.
*
*/
#include <os/IPC.h>
namespace os::IPC
{
Result<OwnedPtr<ClientConnection>> ClientConnection::adopt_connection(LocalServer::Client&& connection)
{
return adopt_owned_if_nonnull(new (std::nothrow) ClientConnection(move(connection)));
}
ClientConnection::ClientConnection(LocalServer::Client&& connection) : m_connection(move(connection))
{
}
Result<void> ClientConnection::check_for_messages()
{
if (m_ipc_in_progress)
{
m_ipc_in_progress = false;
m_message_handler(*this, m_ipc_saved_id, m_arg);
return {};
}
u8 id;
auto rc = m_connection.recv_typed(id);
if (rc.has_error())
{
if (rc.error() == EAGAIN) return {}; // No messages, and the caller does not want us to block.
if (rc.error() == EINTR)
return {}; // Let the caller check for anything having happened because a signal handler ran.
return rc.release_error();
}
m_message_handler(*this, id, m_arg);
return {};
}
Result<void> ClientConnection::send_error(int error)
{
u8 id = 0;
TRY(m_connection.send_typed(id));
TRY(m_connection.send_typed(error));
return {};
}
Result<OwnedPtr<Client>> Client::connect(StringView path, bool blocking)
{
auto connection = TRY(LocalClient::connect(path, blocking));
return adopt_owned_if_nonnull(new (std::nothrow) Client(move(connection)));
}
Result<void> Client::check_for_messages()
{
if (m_ipc_in_progress)
{
m_ipc_in_progress = false;
m_message_handler(*this, m_ipc_saved_id, m_arg);
return {};
}
u8 id;
auto rc = m_connection->recv_typed(id);
if (rc.has_error())
{
if (rc.error() == EAGAIN) return {}; // No messages, and the caller does not want us to block.
if (rc.error() == EINTR)
return {}; // Let the caller check for anything having happened because a signal handler ran.
return rc.release_error();
}
m_message_handler(*this, id, m_arg);
return {};
}
Client::Client(OwnedPtr<LocalClient>&& connection) : m_connection(move(connection))
{
}
}