Adding deferred xoverlapped completion helper.

This commit is contained in:
Ben Vanik 2015-06-29 12:02:08 -07:00
parent c9f4d00da3
commit 5b2f049d4c
2 changed files with 73 additions and 0 deletions

View File

@ -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<XUserModule> module) {
memory()->TranslateVirtual<xe::be<uint32_t>*>(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<XHostThread>(new XHostThread(this, 128 * 1024, 0, [this]() {
while (dispatch_thread_running_) {
std::unique_lock<std::mutex> 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<XKernelModule> 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<void()> completion_callback, uint32_t overlapped_ptr,
X_RESULT result) {
CompleteOverlappedDeferredEx(std::move(completion_callback), overlapped_ptr,
result, result, 0);
}
void KernelState::CompleteOverlappedDeferredEx(
std::function<void()> 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<std::mutex> 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

View File

@ -12,6 +12,10 @@
#include <gflags/gflags.h>
#include <atomic>
#include <condition_variable>
#include <functional>
#include <list>
#include <memory>
#include <mutex>
@ -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<void()> completion_callback,
uint32_t overlapped_ptr, X_RESULT result);
void CompleteOverlappedDeferredEx(std::function<void()> completion_callback,
uint32_t overlapped_ptr, X_RESULT result,
uint32_t extended_error, uint32_t length);
private:
void LoadKernelModule(object_ref<XKernelModule> kernel_module);
@ -161,6 +171,12 @@ class KernelState {
uint32_t process_info_block_address_;
std::atomic<bool> dispatch_thread_running_ = false;
object_ref<XHostThread> dispatch_thread_;
std::mutex dispatch_mutex_;
std::condition_variable dispatch_cond_;
std::list<std::function<void()>> dispatch_queue_;
friend class XObject;
};