xenia-canary/src/xenia/kernel/xtimer.cc

89 lines
3.0 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include "xenia/kernel/xtimer.h"
#include "xenia/base/clock.h"
#include "xenia/base/logging.h"
#include "xenia/cpu/processor.h"
#include "xenia/kernel/xthread.h"
namespace xe {
namespace kernel {
XTimer::XTimer(KernelState* kernel_state) : XObject(kernel_state, kType) {}
XTimer::~XTimer() = default;
void XTimer::Initialize(uint32_t timer_type) {
assert_false(timer_);
switch (timer_type) {
case 0: // NotificationTimer
timer_ = xe::threading::Timer::CreateManualResetTimer();
break;
case 1: // SynchronizationTimer
timer_ = xe::threading::Timer::CreateSynchronizationTimer();
break;
default:
assert_always();
break;
}
}
X_STATUS XTimer::SetTimer(int64_t due_time, uint32_t period_ms,
uint32_t routine, uint32_t routine_arg, bool resume) {
// Caller is checking for STATUS_TIMER_RESUME_IGNORED.
if (resume) {
return X_STATUS_TIMER_RESUME_IGNORED;
}
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),
std::move(callback));
} else {
result = timer_->SetRepeating(std::chrono::nanoseconds(due_time * 100),
std::chrono::milliseconds(period_ms),
std::move(callback));
}
return result ? X_STATUS_SUCCESS : X_STATUS_UNSUCCESSFUL;
}
X_STATUS XTimer::Cancel() {
return timer_->Cancel() ? X_STATUS_SUCCESS : X_STATUS_UNSUCCESSFUL;
}
} // namespace kernel
} // namespace xe