Implementing SetTimer and CompleteOverlappedEx APC callbacks.
Fixes #410.
This commit is contained in:
parent
7f505a15b7
commit
7711568af9
|
@ -540,16 +540,9 @@ void KernelState::CompleteOverlappedEx(uint32_t overlapped_ptr, X_RESULT result,
|
|||
X_HANDLE thread_handle = XOverlappedGetContext(ptr);
|
||||
auto thread = object_table()->LookupObject<XThread>(thread_handle);
|
||||
if (thread) {
|
||||
// Queue APC on the thread that requested the overlapped operation.
|
||||
uint32_t routine = XOverlappedGetCompletionRoutine(ptr);
|
||||
uint64_t args[] = {
|
||||
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));
|
||||
thread->EnqueueApc(routine, result, length, overlapped_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -417,6 +417,9 @@ void XThread::Execute() {
|
|||
|
||||
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.
|
||||
// Otherwise, we are a raw thread.
|
||||
if (creation_params_.xapi_thread_startup) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "xenia/base/clock.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/cpu/processor.h"
|
||||
#include "xenia/kernel/objects/xthread.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
|
@ -42,25 +43,38 @@ X_STATUS XTimer::SetTimer(int64_t due_time, uint32_t period_ms,
|
|||
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);
|
||||
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;
|
||||
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 {
|
||||
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;
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
namespace xe {
|
||||
namespace kernel {
|
||||
|
||||
class XThread;
|
||||
|
||||
class XTimer : public XObject {
|
||||
public:
|
||||
explicit XTimer(KernelState* kernel_state);
|
||||
|
@ -24,7 +26,6 @@ class XTimer : public XObject {
|
|||
|
||||
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,
|
||||
uint32_t routine_arg, bool resume);
|
||||
X_STATUS Cancel();
|
||||
|
@ -34,8 +35,9 @@ class XTimer : public XObject {
|
|||
private:
|
||||
std::unique_ptr<xe::threading::Timer> timer_;
|
||||
|
||||
uint32_t current_routine_;
|
||||
uint32_t current_routine_arg_;
|
||||
XThread* callback_thread_ = nullptr;
|
||||
uint32_t callback_routine_ = 0;
|
||||
uint32_t callback_routine_arg_ = 0;
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
|
|
Loading…
Reference in New Issue