HLE: Implemented SleepClientThread and ContinueClientThread functions to make performing async tasks on the host while in an HLE service function easier.

An HLE service function that wants to perform an async operation should put the caller guest thread to sleep using SleepClientThread, passing in a callback to execute when the thread is resumed.
SleepClientThread returns a ThreadContinuationToken that should be stored and used with ContinueClientThread to resume the guest thread when the host async operation completes.
This commit is contained in:
Subv 2017-09-29 10:00:28 -05:00
parent 0a308e224c
commit f9d55ecf3f
2 changed files with 85 additions and 3 deletions

View file

@ -9,6 +9,7 @@
#include "common/string_util.h"
#include "core/hle/ipc.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/server_port.h"
#include "core/hle/kernel/server_session.h"
@ -210,6 +211,47 @@ void AddService(Interface* interface_) {
server_port->SetHleHandler(std::shared_ptr<Interface>(interface_));
}
bool ThreadContinuationToken::IsValid() {
return thread != nullptr && event != nullptr;
}
ThreadContinuationToken SleepClientThread(const std::string& reason,
ThreadContinuationToken::Callback callback) {
auto thread = Kernel::GetCurrentThread();
ASSERT(thread->status == THREADSTATUS_RUNNING);
ThreadContinuationToken token;
token.event = Kernel::Event::Create(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
token.thread = thread;
token.callback = std::move(callback);
token.pause_reason = std::move(reason);
// Make the thread wait on our newly created event, it will be signaled when
// ContinueClientThread is called.
thread->status = THREADSTATUS_WAIT_HLE_EVENT;
thread->wait_objects = {token.event};
token.event->AddWaitingThread(thread);
return token;
}
void ContinueClientThread(ThreadContinuationToken& token) {
ASSERT_MSG(token.IsValid(), "Invalid continuation token");
ASSERT(token.thread->status == THREADSTATUS_WAIT_HLE_EVENT);
// Signal the event to wake up the thread
token.event->Signal();
ASSERT(token.thread->status == THREADSTATUS_READY);
token.callback(token.thread);
token.event = nullptr;
token.thread = nullptr;
token.callback = nullptr;
}
/// Initialize ServiceManager
void Init() {
SM::g_service_manager = std::make_shared<SM::ServiceManager>();
@ -280,4 +322,4 @@ void Shutdown() {
g_kernel_named_ports.clear();
LOG_DEBUG(Service, "shutdown OK");
}
}
} // namespace Service