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);
|
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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue