From 5b2f049d4ce9c5ef3701874504c8c392bda199a7 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 29 Jun 2015 12:02:08 -0700 Subject: [PATCH] Adding deferred xoverlapped completion helper. --- src/xenia/kernel/kernel_state.cc | 57 ++++++++++++++++++++++++++++++++ src/xenia/kernel/kernel_state.h | 16 +++++++++ 2 files changed, 73 insertions(+) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index b50d64164..86994216f 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -36,6 +36,8 @@ DEFINE_string(content_root, "content", namespace xe { namespace kernel { +constexpr uint32_t kDeferredOverlappedDelayMillis = 100; + // This is a global object initialized with the XboxkrnlModule. // It references the current kernel state object that all kernel methods should // be using to stash their variables. @@ -88,6 +90,12 @@ KernelState::KernelState(Emulator* emulator) KernelState::~KernelState() { SetExecutableModule(nullptr); + if (dispatch_thread_running_) { + dispatch_thread_running_ = false; + dispatch_cond_.notify_all(); + dispatch_thread_->Wait(0, 0, 0, nullptr); + } + if (process_info_block_address_) { memory_->SystemHeapFree(process_info_block_address_); } @@ -202,6 +210,30 @@ void KernelState::SetExecutableModule(object_ref module) { memory()->TranslateVirtual*>(export->variable_ptr); *variable_ptr = executable_module_->hmodule_ptr(); } + + // Spin up deferred dispatch worker. + // TODO(benvanik): move someplace more appropriate (out of ctor, but around + // here). + assert_false(dispatch_thread_running_); + dispatch_thread_running_ = true; + dispatch_thread_ = + object_ref(new XHostThread(this, 128 * 1024, 0, [this]() { + while (dispatch_thread_running_) { + std::unique_lock lock(dispatch_mutex_); + if (dispatch_queue_.empty()) { + dispatch_cond_.wait(lock); + if (!dispatch_thread_running_) { + break; + } + } + auto fn = std::move(dispatch_queue_.front()); + dispatch_queue_.pop_front(); + fn(); + } + return 0; + })); + dispatch_thread_->set_name("Kernel Dispatch Thread"); + dispatch_thread_->Create(); } void KernelState::LoadKernelModule(object_ref kernel_module) { @@ -430,5 +462,30 @@ void KernelState::CompleteOverlappedImmediateEx(uint32_t overlapped_ptr, CompleteOverlappedEx(overlapped_ptr, result, extended_error, length); } +void KernelState::CompleteOverlappedDeferred( + std::function completion_callback, uint32_t overlapped_ptr, + X_RESULT result) { + CompleteOverlappedDeferredEx(std::move(completion_callback), overlapped_ptr, + result, result, 0); +} + +void KernelState::CompleteOverlappedDeferredEx( + std::function completion_callback, uint32_t overlapped_ptr, + X_RESULT result, uint32_t extended_error, uint32_t length) { + auto ptr = memory()->TranslateVirtual(overlapped_ptr); + XOverlappedSetResult(ptr, X_ERROR_IO_PENDING); + XOverlappedSetContext(ptr, XThread::GetCurrentThreadHandle()); + std::unique_lock lock(dispatch_mutex_); + dispatch_queue_.push_back([this, completion_callback, overlapped_ptr, result, + extended_error, length]() { + xe::threading::Sleep( + std::chrono::milliseconds::duration(kDeferredOverlappedDelayMillis)); + completion_callback(); + auto ptr = memory()->TranslateVirtual(overlapped_ptr); + CompleteOverlappedEx(overlapped_ptr, result, extended_error, length); + }); + dispatch_cond_.notify_all(); +} + } // namespace kernel } // namespace xe diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index c2ac47c3b..8b448ea5f 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -12,6 +12,10 @@ #include +#include +#include +#include +#include #include #include @@ -38,6 +42,7 @@ namespace xe { namespace kernel { class Dispatcher; +class XHostThread; class XKernelModule; class XModule; class XNotifyListener; @@ -133,6 +138,11 @@ class KernelState { void CompleteOverlappedImmediate(uint32_t overlapped_ptr, X_RESULT result); void CompleteOverlappedImmediateEx(uint32_t overlapped_ptr, X_RESULT result, uint32_t extended_error, uint32_t length); + void CompleteOverlappedDeferred(std::function completion_callback, + uint32_t overlapped_ptr, X_RESULT result); + void CompleteOverlappedDeferredEx(std::function completion_callback, + uint32_t overlapped_ptr, X_RESULT result, + uint32_t extended_error, uint32_t length); private: void LoadKernelModule(object_ref kernel_module); @@ -161,6 +171,12 @@ class KernelState { uint32_t process_info_block_address_; + std::atomic dispatch_thread_running_ = false; + object_ref dispatch_thread_; + std::mutex dispatch_mutex_; + std::condition_variable dispatch_cond_; + std::list> dispatch_queue_; + friend class XObject; };