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:
parent
0a308e224c
commit
f9d55ecf3f
2 changed files with 85 additions and 3 deletions
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue