2014-01-08 05:55:32 +00:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
* 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. *
|
|
|
|
******************************************************************************
|
|
|
|
*/
|
|
|
|
|
2015-02-01 06:49:47 +00:00
|
|
|
#include "xenia/kernel/objects/xtimer.h"
|
2014-01-08 05:55:32 +00:00
|
|
|
|
2015-05-27 05:20:46 +00:00
|
|
|
#include "xenia/base/clock.h"
|
2015-05-02 10:42:51 +00:00
|
|
|
#include "xenia/base/logging.h"
|
2015-02-01 06:49:47 +00:00
|
|
|
#include "xenia/cpu/processor.h"
|
2014-01-08 06:47:35 +00:00
|
|
|
|
2014-08-17 20:13:03 +00:00
|
|
|
namespace xe {
|
|
|
|
namespace kernel {
|
2014-01-08 05:55:32 +00:00
|
|
|
|
2014-08-17 20:13:03 +00:00
|
|
|
XTimer::XTimer(KernelState* kernel_state)
|
2015-06-11 02:18:12 +00:00
|
|
|
: XObject(kernel_state, kTypeTimer), native_handle_(NULL) {}
|
2014-01-08 05:55:32 +00:00
|
|
|
|
|
|
|
XTimer::~XTimer() {
|
2015-06-11 02:18:12 +00:00
|
|
|
if (native_handle_) {
|
|
|
|
CloseHandle(native_handle_);
|
2014-01-08 05:55:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void XTimer::Initialize(uint32_t timer_type) {
|
2015-06-11 02:18:12 +00:00
|
|
|
assert_null(native_handle_);
|
2014-01-08 05:55:32 +00:00
|
|
|
|
|
|
|
bool manual_reset = false;
|
|
|
|
switch (timer_type) {
|
2014-08-17 20:13:03 +00:00
|
|
|
case 0: // NotificationTimer
|
|
|
|
manual_reset = true;
|
|
|
|
break;
|
|
|
|
case 1: // SynchronizationTimer
|
|
|
|
manual_reset = false;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
assert_always();
|
|
|
|
break;
|
2014-01-08 05:55:32 +00:00
|
|
|
}
|
|
|
|
|
2015-06-11 02:18:12 +00:00
|
|
|
native_handle_ = CreateWaitableTimer(NULL, manual_reset, NULL);
|
2014-01-08 05:55:32 +00:00
|
|
|
}
|
|
|
|
|
2014-08-17 20:13:03 +00:00
|
|
|
X_STATUS XTimer::SetTimer(int64_t due_time, uint32_t period_ms,
|
|
|
|
uint32_t routine, uint32_t routine_arg, bool resume) {
|
2014-01-08 06:47:35 +00:00
|
|
|
// Stash routine for callback.
|
|
|
|
current_routine_ = routine;
|
|
|
|
current_routine_arg_ = routine_arg;
|
|
|
|
|
2015-05-27 05:20:46 +00:00
|
|
|
due_time = Clock::ScaleGuestDurationFileTime(due_time);
|
|
|
|
period_ms = Clock::ScaleGuestDurationMillis(period_ms);
|
|
|
|
|
2014-01-08 05:55:32 +00:00
|
|
|
LARGE_INTEGER due_time_li;
|
|
|
|
due_time_li.QuadPart = due_time;
|
2014-08-17 20:13:03 +00:00
|
|
|
BOOL result =
|
2015-06-11 02:18:12 +00:00
|
|
|
SetWaitableTimer(native_handle_, &due_time_li, period_ms,
|
2014-08-17 20:13:03 +00:00
|
|
|
routine ? (PTIMERAPCROUTINE)CompletionRoutine : NULL,
|
|
|
|
this, resume ? TRUE : FALSE);
|
2014-01-08 06:47:35 +00:00
|
|
|
|
|
|
|
// Caller is checking for STATUS_TIMER_RESUME_IGNORED.
|
|
|
|
// This occurs if result == TRUE but error is set.
|
|
|
|
if (!result && GetLastError() == ERROR_NOT_SUPPORTED) {
|
|
|
|
return X_STATUS_TIMER_RESUME_IGNORED;
|
2014-01-08 05:55:32 +00:00
|
|
|
}
|
2014-01-08 06:47:35 +00:00
|
|
|
|
|
|
|
return result ? X_STATUS_SUCCESS : X_STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
2014-08-17 20:13:03 +00:00
|
|
|
void XTimer::CompletionRoutine(XTimer* timer, DWORD timer_low,
|
|
|
|
DWORD timer_high) {
|
2014-07-12 23:51:52 +00:00
|
|
|
assert_true(timer->current_routine_);
|
2014-01-08 06:47:35 +00:00
|
|
|
|
|
|
|
// Queue APC to call back routine with (arg, low, high).
|
|
|
|
// TODO(benvanik): APC dispatch.
|
|
|
|
XELOGE("Timer needs APC!");
|
2014-01-08 07:16:31 +00:00
|
|
|
|
|
|
|
DebugBreak();
|
2014-01-08 05:55:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
X_STATUS XTimer::Cancel() {
|
2015-06-11 02:18:12 +00:00
|
|
|
return CancelWaitableTimer(native_handle_) == 0 ? X_STATUS_SUCCESS
|
|
|
|
: X_STATUS_UNSUCCESSFUL;
|
2014-01-08 05:55:32 +00:00
|
|
|
}
|
2014-08-17 20:13:03 +00:00
|
|
|
|
|
|
|
} // namespace kernel
|
|
|
|
} // namespace xe
|