Implementing SetTimer and CompleteOverlappedEx APC callbacks.

Fixes #410.
This commit is contained in:
Ben Vanik 2015-08-29 23:43:26 -07:00
parent 7f505a15b7
commit 7711568af9
4 changed files with 36 additions and 24 deletions

View File

@ -540,16 +540,9 @@ void KernelState::CompleteOverlappedEx(uint32_t overlapped_ptr, X_RESULT result,
X_HANDLE thread_handle = XOverlappedGetContext(ptr); X_HANDLE thread_handle = XOverlappedGetContext(ptr);
auto thread = object_table()->LookupObject<XThread>(thread_handle); auto thread = object_table()->LookupObject<XThread>(thread_handle);
if (thread) { if (thread) {
// Queue APC on the thread that requested the overlapped operation.
uint32_t routine = XOverlappedGetCompletionRoutine(ptr); uint32_t routine = XOverlappedGetCompletionRoutine(ptr);
uint64_t args[] = { thread->EnqueueApc(routine, result, length, overlapped_ptr);
result, length, overlapped_ptr,
};
// TODO(benvanik): queue APC on the thread that requested the overlapped
// operation.
assert_always();
// THIS IS WRONG, for testing only:
processor()->Execute(XThread::GetCurrentThread()->thread_state(), routine,
args, xe::countof(args));
} }
} }
} }

View File

@ -417,6 +417,9 @@ void XThread::Execute() {
int exit_code = 0; int exit_code = 0;
// Dispatch any APCs that were queued before the thread was created first.
DeliverAPCs();
// If a XapiThreadStartup value is present, we use that as a trampoline. // If a XapiThreadStartup value is present, we use that as a trampoline.
// Otherwise, we are a raw thread. // Otherwise, we are a raw thread.
if (creation_params_.xapi_thread_startup) { if (creation_params_.xapi_thread_startup) {

View File

@ -12,6 +12,7 @@
#include "xenia/base/clock.h" #include "xenia/base/clock.h"
#include "xenia/base/logging.h" #include "xenia/base/logging.h"
#include "xenia/cpu/processor.h" #include "xenia/cpu/processor.h"
#include "xenia/kernel/objects/xthread.h"
namespace xe { namespace xe {
namespace kernel { namespace kernel {
@ -42,25 +43,38 @@ X_STATUS XTimer::SetTimer(int64_t due_time, uint32_t period_ms,
return X_STATUS_TIMER_RESUME_IGNORED; return X_STATUS_TIMER_RESUME_IGNORED;
} }
// Stash routine for callback.
current_routine_ = routine;
current_routine_arg_ = routine_arg;
if (current_routine_) {
// Queue APC to call back routine with (arg, low, high).
// TODO(benvanik): APC dispatch.
XELOGE("Timer needs APC!");
assert_zero(current_routine_);
}
due_time = Clock::ScaleGuestDurationFileTime(due_time); due_time = Clock::ScaleGuestDurationFileTime(due_time);
period_ms = Clock::ScaleGuestDurationMillis(period_ms); period_ms = Clock::ScaleGuestDurationMillis(period_ms);
// Stash routine for callback.
callback_thread_ = XThread::GetCurrentThread();
callback_routine_ = routine;
callback_routine_arg_ = routine_arg;
// This callback will only be issued when the timer is fired.
std::function<void()> callback = nullptr;
if (callback_routine_) {
callback = [this]() {
// Queue APC to call back routine with (arg, low, high).
// It'll be executed on the thread that requested the timer.
uint64_t time = xe::Clock::QueryGuestSystemTime();
uint32_t time_low = static_cast<uint32_t>(time);
uint32_t time_high = static_cast<uint32_t>(time >> 32);
XELOGI("XTimer enqueuing timer callback to %.8X(%.8X, %.8X, %.8X)",
callback_routine_, callback_routine_arg_, time_low, time_high);
callback_thread_->EnqueueApc(callback_routine_, callback_routine_arg_,
time_low, time_high);
};
}
bool result; bool result;
if (!period_ms) { if (!period_ms) {
result = timer_->SetOnce(std::chrono::nanoseconds(due_time * 100)); result = timer_->SetOnce(std::chrono::nanoseconds(due_time * 100),
std::move(callback));
} else { } else {
result = timer_->SetRepeating(std::chrono::nanoseconds(due_time * 100), result = timer_->SetRepeating(std::chrono::nanoseconds(due_time * 100),
std::chrono::milliseconds(period_ms)); std::chrono::milliseconds(period_ms),
std::move(callback));
} }
return result ? X_STATUS_SUCCESS : X_STATUS_UNSUCCESSFUL; return result ? X_STATUS_SUCCESS : X_STATUS_UNSUCCESSFUL;

View File

@ -17,6 +17,8 @@
namespace xe { namespace xe {
namespace kernel { namespace kernel {
class XThread;
class XTimer : public XObject { class XTimer : public XObject {
public: public:
explicit XTimer(KernelState* kernel_state); explicit XTimer(KernelState* kernel_state);
@ -24,7 +26,6 @@ class XTimer : public XObject {
void Initialize(uint32_t timer_type); void Initialize(uint32_t timer_type);
// completion routine, arg to completion routine
X_STATUS SetTimer(int64_t due_time, uint32_t period_ms, uint32_t routine, X_STATUS SetTimer(int64_t due_time, uint32_t period_ms, uint32_t routine,
uint32_t routine_arg, bool resume); uint32_t routine_arg, bool resume);
X_STATUS Cancel(); X_STATUS Cancel();
@ -34,8 +35,9 @@ class XTimer : public XObject {
private: private:
std::unique_ptr<xe::threading::Timer> timer_; std::unique_ptr<xe::threading::Timer> timer_;
uint32_t current_routine_; XThread* callback_thread_ = nullptr;
uint32_t current_routine_arg_; uint32_t callback_routine_ = 0;
uint32_t callback_routine_arg_ = 0;
}; };
} // namespace kernel } // namespace kernel