mirror of
https://github.com/ndeadly/MissionControl
synced 2024-11-23 04:43:10 +00:00
mc.mitm: add basic functionality to run async code in a worker thread and receive a response
This commit is contained in:
parent
18c7453530
commit
1bb3594e24
3 changed files with 168 additions and 0 deletions
80
mc_mitm/source/async/async.cpp
Normal file
80
mc_mitm/source/async/async.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 ndeadly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "async.hpp"
|
||||
|
||||
namespace ams::async {
|
||||
|
||||
namespace {
|
||||
|
||||
const size_t ThreadCount = 1;
|
||||
const size_t ThreadStackSize = 0x2000;
|
||||
const s32 ThreadPriority = 10;
|
||||
|
||||
alignas(os::MemoryPageSize) uint8_t g_thread_stacks[ThreadCount][ThreadStackSize];
|
||||
os::ThreadType g_thread_pool[ThreadCount];
|
||||
|
||||
const size_t MessageBufferSize = 10;
|
||||
uintptr_t g_message_buffer[MessageBufferSize];
|
||||
os::MessageQueueType g_work_queue;
|
||||
|
||||
void WorkerThreadFunc(void *) {
|
||||
uintptr_t ptr;
|
||||
for (;;) {
|
||||
os::ReceiveMessageQueue(&ptr, &g_work_queue);
|
||||
|
||||
// Convert pointer to work function back to correct type and claim ownership
|
||||
auto work_func = std::unique_ptr<AsyncFunction>(reinterpret_cast<AsyncFunction *>(ptr));
|
||||
|
||||
// Execute the work function
|
||||
Result rc = (*work_func)();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Result Initialize(void) {
|
||||
os::InitializeMessageQueue(&g_work_queue, g_message_buffer, MessageBufferSize);
|
||||
|
||||
for (unsigned int i = 0; i < ThreadCount; ++i) {
|
||||
R_TRY(os::CreateThread(&g_thread_pool[i],
|
||||
WorkerThreadFunc,
|
||||
nullptr,
|
||||
g_thread_stacks[i],
|
||||
ThreadStackSize,
|
||||
ThreadPriority
|
||||
));
|
||||
|
||||
os::SetThreadNamePointer(&g_thread_pool[i], "mc::AsyncWorker");
|
||||
os::StartThread(&g_thread_pool[i]);
|
||||
}
|
||||
|
||||
return ams::ResultSuccess();
|
||||
}
|
||||
|
||||
void Finalize(void) {
|
||||
os::FinalizeMessageQueue(&g_work_queue);
|
||||
|
||||
for (unsigned int i = 0; i < ThreadCount; ++i) {
|
||||
os::DestroyThread(&g_thread_pool[i]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void QueueWork(AsyncFunction *function) {
|
||||
os::SendMessageQueue(&g_work_queue, reinterpret_cast<uintptr_t>(function));
|
||||
}
|
||||
|
||||
}
|
31
mc_mitm/source/async/async.hpp
Normal file
31
mc_mitm/source/async/async.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2022 ndeadly
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include <functional>
|
||||
|
||||
namespace ams::async {
|
||||
|
||||
using AsyncFunction = std::function<Result(void)>;
|
||||
|
||||
Result Initialize(void);
|
||||
void Finalize(void);
|
||||
|
||||
void QueueWork(AsyncFunction *function);
|
||||
|
||||
#define MC_RUN_ASYNC(code) async::QueueWork(new async::AsyncFunction ([&]() -> ams::Result { code }));
|
||||
|
||||
}
|
57
mc_mitm/source/async/future_response.hpp
Normal file
57
mc_mitm/source/async/future_response.hpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams {
|
||||
|
||||
template <class T1, class T2, class T3>
|
||||
class FutureResponse {
|
||||
public:
|
||||
FutureResponse(T1 type) : m_type(type) {
|
||||
os::InitializeEvent(&m_ready_event, false, os::EventClearMode_AutoClear);
|
||||
}
|
||||
|
||||
~FutureResponse() {
|
||||
os::FinalizeEvent(&m_ready_event);
|
||||
}
|
||||
|
||||
const T1& GetType() {
|
||||
return m_type;
|
||||
}
|
||||
|
||||
void SetData(const T2& data) {
|
||||
m_data = data;
|
||||
os::SignalEvent(&m_ready_event);
|
||||
}
|
||||
|
||||
const T2& GetData() {
|
||||
return m_data;
|
||||
}
|
||||
|
||||
void SetUserData(const T3& user_data) {
|
||||
m_user_data = user_data;
|
||||
}
|
||||
|
||||
const T3& GetUserData() {
|
||||
return m_user_data;
|
||||
}
|
||||
|
||||
void Wait(void) {
|
||||
os::WaitEvent(&m_ready_event);
|
||||
}
|
||||
|
||||
bool TryWait(void) {
|
||||
return os::TryWaitEvent(&m_ready_event);
|
||||
}
|
||||
|
||||
bool TimedWait(TimeSpan timeout) {
|
||||
return os::TimedWaitEvent(&m_ready_event, timeout);
|
||||
}
|
||||
|
||||
private:
|
||||
T1 m_type;
|
||||
T2 m_data;
|
||||
T3 m_user_data;
|
||||
os::EventType m_ready_event;
|
||||
};
|
||||
|
||||
}
|
Loading…
Reference in a new issue