htcs: hook up CreateSocket/RpcClient Begin<>/End<>

This commit is contained in:
Michael Scire
2021-02-17 23:28:05 -08:00
committed by SciresM
parent abff428212
commit 536e3e99a8
9 changed files with 235 additions and 14 deletions

View File

@@ -22,6 +22,27 @@
namespace ams::htc::server::rpc {
template<typename T>
concept IsRpcTask = std::derived_from<T, Task>;
struct RpcTaskFunctionTraits {
public:
template<typename R, typename C, typename... A>
static std::tuple<A...> GetArgsImpl(R(C::*)(A...));
};
template<typename T> requires IsRpcTask<T>
using RpcTaskArgumentsType = decltype(RpcTaskFunctionTraits::GetArgsImpl(&T::SetArguments));
template<typename T> requires IsRpcTask<T>
using RpcTaskResultType = decltype(RpcTaskFunctionTraits::GetArgsImpl(&T::GetResult));
template<typename T, typename... Args>
concept IsRpcTaskArgumentsType = IsRpcTask<T> && std::same_as<std::tuple<Args...>, RpcTaskArgumentsType<T>>;
template<typename T, typename... Args>
concept IsRpcTaskResultType = IsRpcTask<T> && std::same_as<std::tuple<Args...>, RpcTaskResultType<T>>;
class RpcClient {
private:
/* TODO: where is this value coming from, again? */
@@ -68,6 +89,88 @@ namespace ams::htc::server::rpc {
Result ReceiveHeader(RpcPacket *header);
Result ReceiveBody(char *dst, size_t size);
Result SendRequest(const char *src, size_t size);
public:
void Wait(u32 task_id) {
os::WaitEvent(m_task_table.Get<Task>(task_id)->GetEvent());
}
template<typename T, typename... Args> requires IsRpcTaskArgumentsType<T, Args...>
Result Begin(u32 *out_task_id, Args... args) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
/* Allocate a free task id. */
u32 task_id;
R_TRY(m_task_id_free_list.Allocate(std::addressof(task_id)));
/* Create the new task. */
T *task = m_task_table.New<T>(task_id);
m_task_active[task_id] = true;
/* Ensure we clean up the task, if we fail after this. */
auto task_guard = SCOPE_GUARD {
m_task_active[task_id] = false;
m_task_table.Delete<T>(task_id);
m_task_id_free_list.Free(task_id);
};
/* Set the task arguments. */
R_TRY(task->SetArguments(args...));
/* Clear the task's events. */
os::ClearEvent(std::addressof(m_receive_buffer_available_events[task_id]));
os::ClearEvent(std::addressof(m_send_buffer_available_events[task_id]));
/* Add the task to our queue if we can, or cancel it. */
if (m_thread_running) {
m_task_queue.Add(task_id, PacketCategory::Request);
} else {
task->Cancel(RpcTaskCancelReason::QueueNotAvailable);
}
/* Set the output task id. */
*out_task_id = task_id;
/* We succeeded. */
task_guard.Cancel();
return ResultSuccess();
}
template<typename T, typename... Args> requires IsRpcTaskResultType<T, Args...>
Result End(u32 task_id, Args... args) {
/* Lock ourselves. */
std::scoped_lock lk(m_mutex);
/* Get the task. */
T *task = m_task_table.Get<T>(task_id);
R_UNLESS(task != nullptr, htc::ResultInvalidTaskId());
/* Ensure the task is freed if it needs to be, when we're done. */
auto task_guard = SCOPE_GUARD {
m_task_active[task_id] = false;
m_task_table.Delete<T>(task_id);
m_task_id_free_list.Free(task_id);
};
/* If the task was cancelled, handle that. */
if (task->GetTaskState() == RpcTaskState::Cancelled) {
switch (task->GetTaskCancelReason()) {
case RpcTaskCancelReason::One:
task_guard.Cancel();
return htc::ResultUnknown2021();
case RpcTaskCancelReason::Two:
return htc::ResultCancelled();
case RpcTaskCancelReason::QueueNotAvailable:
return htc::ResultTaskQueueNotAvailable();
AMS_UNREACHABLE_DEFAULT_CASE();
}
}
/* Get the task's result. */
R_TRY(task->GetResult(args...));
return ResultSuccess();
}
};
}

View File

@@ -39,8 +39,10 @@ namespace ams::htc::server::rpc {
static_assert(sizeof(RpcPacket) == 0x40);
enum class RpcTaskCancelReason {
None = 0,
/* ... */
None = 0,
One = 1,
Two = 2,
QueueNotAvailable = 3,
};
enum class RpcTaskState {