Add a display server and graphical user interface #38
@ -16,6 +16,7 @@ set(SOURCES
|
||||
src/Security.cpp
|
||||
src/LocalServer.cpp
|
||||
src/LocalClient.cpp
|
||||
src/IPC.cpp
|
||||
)
|
||||
|
||||
add_library(os ${SOURCES})
|
||||
|
157
libos/include/os/IPC.h
Normal file
157
libos/include/os/IPC.h
Normal file
@ -0,0 +1,157 @@
|
||||
/**
|
||||
* @file IPC.h
|
||||
* @author apio (cloudapio.eu)
|
||||
* @brief Inter-process communication primitives.
|
||||
*
|
||||
* @copyright Copyright (c) 2023, the Luna authors.
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <os/LocalClient.h>
|
||||
#include <os/LocalServer.h>
|
||||
|
||||
#define IPC_ENUM_SERVER(name) __##name##_SERVER_ERROR = 0
|
||||
#define IPC_ENUM_CLIENT(name) __##name##_CLIENT_ERROR = 0
|
||||
|
||||
/**
|
||||
* @brief Called to handle IPC events (client-side).
|
||||
*
|
||||
* @param conn The connection object being used.
|
||||
* @param id The ID of the message.
|
||||
* @return Result<void> Whether the operation succeded.
|
||||
*/
|
||||
extern Result<void> handle_ipc_client_event(os::LocalClient& conn, u8 id);
|
||||
|
||||
/**
|
||||
* @brief Called to handle IPC events (server-side).
|
||||
*
|
||||
* @param conn The connection object being used.
|
||||
* @param id The ID of the message.
|
||||
* @return Result<void> Whether the operation succeded.
|
||||
*/
|
||||
extern Result<void> handle_ipc_server_event(os::LocalServer::Client& conn, u8 id);
|
||||
|
||||
namespace os
|
||||
{
|
||||
namespace IPC
|
||||
{
|
||||
static constexpr usize IPC_STRING_LENGTH = 256;
|
||||
|
||||
#define IPC_STRING(name) char name[os::IPC::IPC_STRING_LENGTH];
|
||||
#define COPY_IPC_STRING(name) \
|
||||
TRY(String::from_string_view(StringView::from_fixed_size_cstring(name, os::IPC::IPC_STRING_LENGTH)))
|
||||
#define SET_IPC_STRING(name, value) strlcpy(name, value, os::IPC::IPC_STRING_LENGTH)
|
||||
|
||||
/**
|
||||
* @brief Sends an IPC message without waiting for a reply.
|
||||
*
|
||||
* @tparam Client The type of the client interface being used to communicate.
|
||||
* @tparam T The type of the message.
|
||||
* @param client The connection object being used to communicate.
|
||||
* @param message The IPC message.
|
||||
* @return Result<void> Whether the operation succeded.
|
||||
*/
|
||||
template <typename Client, typename T> Result<void> send_async(Client& client, const T& message)
|
||||
{
|
||||
u8 id = T::id;
|
||||
TRY(client.send_typed(id));
|
||||
TRY(client.send_typed(message));
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends an error result to the IPC connection, indicating that an operation could not be performed.
|
||||
*
|
||||
* @tparam Client The type of the client interface being used to communicate.
|
||||
* @param client The connection object being used to communicate.
|
||||
* @param error The error code.
|
||||
* @return Result<void> Whether the operation succeded.
|
||||
*/
|
||||
template <typename Client> Result<void> send_error(Client& client, int error)
|
||||
{
|
||||
u8 id = 0;
|
||||
TRY(client.send_typed(id));
|
||||
TRY(client.send_typed(error));
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sends an IPC message and waits for a reply (client-only).
|
||||
*
|
||||
* @tparam ResponseType The type of the response.
|
||||
* @tparam T The type of the message.
|
||||
* @param client The connection object being used to communicate.
|
||||
* @param message The IPC message.
|
||||
* @param handler The function used to handle messages that do not match the reply.
|
||||
* @return Result<ResponseType> An error, or the response.
|
||||
*/
|
||||
template <typename ResponseType, typename T>
|
||||
Result<ResponseType> send_sync(os::LocalClient& client, const T& message,
|
||||
decltype(handle_ipc_client_event) handler = handle_ipc_client_event)
|
||||
{
|
||||
u8 id = T::id;
|
||||
TRY(client.send_typed(id));
|
||||
TRY(client.send_typed(message));
|
||||
|
||||
// We allow receiving 5 messages of different types, but if those have passed and we still don't have a
|
||||
// reply, fail with ENOMSG.
|
||||
int max_other_messages = 5;
|
||||
|
||||
while (max_other_messages)
|
||||
{
|
||||
u8 response_id;
|
||||
auto rc = client.recv_typed(response_id);
|
||||
if (rc.has_error() && rc.error() == EAGAIN) continue;
|
||||
|
||||
if (response_id == 0) // Error result
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
int code;
|
||||
rc = client.recv_typed(code);
|
||||
if (rc.has_error() && rc.error() == EAGAIN) continue;
|
||||
return err(code);
|
||||
}
|
||||
}
|
||||
|
||||
if (response_id != ResponseType::id)
|
||||
{
|
||||
TRY(handler(client, response_id));
|
||||
max_other_messages--;
|
||||
continue;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
ResponseType response;
|
||||
rc = client.recv_typed(response);
|
||||
if (rc.has_error() && rc.error() == EAGAIN) continue;
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
return err(ENOMSG);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check for new IPC messages on a connection and handle them appropriately.
|
||||
*
|
||||
* @param client The client connection.
|
||||
* @param handler The function used to handle messages.
|
||||
* @return Result<void> Whether the operation succeded.
|
||||
*/
|
||||
Result<void> check_for_messages(os::LocalClient& client,
|
||||
decltype(handle_ipc_client_event) handler = handle_ipc_client_event);
|
||||
|
||||
/**
|
||||
* @brief Check for new IPC messages on a connection and handle them appropriately.
|
||||
*
|
||||
* @param server The server connection.
|
||||
* @param handler The function used to handle messages.
|
||||
* @return Result<void> Whether the operation succeded.
|
||||
*/
|
||||
Result<void> check_for_messages(os::LocalServer::Client& server,
|
||||
decltype(handle_ipc_server_event) handler = handle_ipc_server_event);
|
||||
}
|
||||
}
|
39
libos/src/IPC.cpp
Normal file
39
libos/src/IPC.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @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<void> check_for_messages(os::LocalClient& client, decltype(handle_ipc_client_event) handler)
|
||||
{
|
||||
u8 id;
|
||||
auto rc = client.recv_typed(id);
|
||||
if (rc.has_error())
|
||||
{
|
||||
if (rc.error() == EAGAIN) return {}; // No messages, and the caller does not want us to block.
|
||||
return rc.release_error();
|
||||
}
|
||||
|
||||
return handler(client, id);
|
||||
}
|
||||
|
||||
Result<void> check_for_messages(os::LocalServer::Client& client, decltype(handle_ipc_server_event) handler)
|
||||
{
|
||||
u8 id;
|
||||
auto rc = client.recv_typed(id);
|
||||
if (rc.has_error())
|
||||
{
|
||||
if (rc.error() == EAGAIN) return {}; // No messages, and the caller does not want us to block.
|
||||
return rc.release_error();
|
||||
}
|
||||
|
||||
return handler(client, id);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user