Timers. Probably.
This commit is contained in:
parent
1357a798ef
commit
cfe7b2127d
|
@ -15,5 +15,7 @@
|
||||||
'xsemaphore.h',
|
'xsemaphore.h',
|
||||||
'xthread.cc',
|
'xthread.cc',
|
||||||
'xthread.h',
|
'xthread.h',
|
||||||
|
'xtimer.cc',
|
||||||
|
'xtimer.h',
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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/objects/xtimer.h>
|
||||||
|
|
||||||
|
|
||||||
|
using namespace xe;
|
||||||
|
using namespace xe::kernel;
|
||||||
|
|
||||||
|
|
||||||
|
XTimer::XTimer(KernelState* kernel_state) :
|
||||||
|
XObject(kernel_state, kTypeTimer),
|
||||||
|
handle_(NULL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
XTimer::~XTimer() {
|
||||||
|
if (handle_) {
|
||||||
|
CloseHandle(handle_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XTimer::Initialize(uint32_t timer_type) {
|
||||||
|
XEASSERTNULL(handle_);
|
||||||
|
|
||||||
|
bool manual_reset = false;
|
||||||
|
switch (timer_type) {
|
||||||
|
case 0: // NotificationTimer
|
||||||
|
manual_reset = true;
|
||||||
|
break;
|
||||||
|
case 1: // SynchronizationTimer
|
||||||
|
manual_reset = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_ = CreateWaitableTimer(NULL, manual_reset, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XTimer::SetTimer(int64_t due_time, uint32_t period_ms) {
|
||||||
|
LARGE_INTEGER due_time_li;
|
||||||
|
due_time_li.QuadPart = due_time;
|
||||||
|
if (SetWaitableTimer(handle_, &due_time_li, period_ms, NULL, NULL, TRUE)) {
|
||||||
|
return X_STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
return X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
X_STATUS XTimer::Cancel() {
|
||||||
|
return CancelWaitableTimer(handle_) == 0 ?
|
||||||
|
X_STATUS_SUCCESS : X_STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* 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. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef XENIA_KERNEL_XBOXKRNL_XTIMER_H_
|
||||||
|
#define XENIA_KERNEL_XBOXKRNL_XTIMER_H_
|
||||||
|
|
||||||
|
#include <xenia/kernel/xobject.h>
|
||||||
|
|
||||||
|
#include <xenia/xbox.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace xe {
|
||||||
|
namespace kernel {
|
||||||
|
|
||||||
|
|
||||||
|
class XTimer : public XObject {
|
||||||
|
public:
|
||||||
|
XTimer(KernelState* kernel_state);
|
||||||
|
virtual ~XTimer();
|
||||||
|
|
||||||
|
void Initialize(uint32_t timer_type);
|
||||||
|
|
||||||
|
// completion routine, arg to completion routine
|
||||||
|
X_STATUS SetTimer(int64_t due_time, uint32_t period_ms);
|
||||||
|
X_STATUS Cancel();
|
||||||
|
|
||||||
|
virtual void* GetWaitHandle() { return handle_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
HANDLE handle_;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace xe
|
||||||
|
|
||||||
|
|
||||||
|
#endif // XENIA_KERNEL_XBOXKRNL_TIMER_H_
|
|
@ -15,6 +15,7 @@
|
||||||
#include <xenia/kernel/objects/xmutant.h>
|
#include <xenia/kernel/objects/xmutant.h>
|
||||||
#include <xenia/kernel/objects/xsemaphore.h>
|
#include <xenia/kernel/objects/xsemaphore.h>
|
||||||
#include <xenia/kernel/objects/xthread.h>
|
#include <xenia/kernel/objects/xthread.h>
|
||||||
|
#include <xenia/kernel/objects/xtimer.h>
|
||||||
#include <xenia/kernel/util/shim_utils.h>
|
#include <xenia/kernel/util/shim_utils.h>
|
||||||
|
|
||||||
|
|
||||||
|
@ -945,6 +946,100 @@ SHIM_CALL NtReleaseMutant_shim(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHIM_CALL NtCreateTimer_shim(
|
||||||
|
PPCContext* ppc_state, KernelState* state) {
|
||||||
|
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
|
||||||
|
uint32_t obj_attributes_ptr = SHIM_GET_ARG_32(1);
|
||||||
|
uint32_t timer_type = SHIM_GET_ARG_32(2);
|
||||||
|
|
||||||
|
// timer_type = NotificationTimer (0) or SynchronizationTimer (1)
|
||||||
|
|
||||||
|
XELOGD(
|
||||||
|
"NtCreateTimer(%.8X, %.8X, %.1X)",
|
||||||
|
handle_ptr, obj_attributes_ptr, timer_type);
|
||||||
|
|
||||||
|
XTimer* timer = new XTimer(state);
|
||||||
|
timer->Initialize(timer_type);
|
||||||
|
|
||||||
|
// obj_attributes may have a name inside of it, if != NULL.
|
||||||
|
if (obj_attributes_ptr) {
|
||||||
|
//timer->SetName(...);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle_ptr) {
|
||||||
|
SHIM_SET_MEM_32(handle_ptr, timer->handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
SHIM_SET_RETURN(X_STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHIM_CALL NtSetTimerEx_shim(
|
||||||
|
PPCContext* ppc_state, KernelState* state) {
|
||||||
|
uint32_t timer_handle = SHIM_GET_ARG_32(0);
|
||||||
|
uint32_t info_class = SHIM_GET_ARG_32(1);
|
||||||
|
uint32_t info_ptr = SHIM_GET_ARG_32(2);
|
||||||
|
uint32_t info_length = SHIM_GET_ARG_32(3);
|
||||||
|
|
||||||
|
// UNVERIFIED
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
|
||||||
|
XELOGD(
|
||||||
|
"NtSetTimerEx(%.8X, %.8X, %.8X, %d)",
|
||||||
|
timer_handle, info_class, info_ptr, info_length);
|
||||||
|
|
||||||
|
// TIMER_BASIC_INFORMATION
|
||||||
|
XEASSERT(info_class == 0);
|
||||||
|
XEASSERT(info_length == 12);
|
||||||
|
|
||||||
|
uint64_t due_time = SHIM_MEM_64(info_ptr + 0);
|
||||||
|
uint32_t timer_state = SHIM_MEM_32(info_ptr + 8); // unused?
|
||||||
|
uint32_t period_ms = 0; // Not repeating.
|
||||||
|
|
||||||
|
X_STATUS result = X_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
XTimer* timer = NULL;
|
||||||
|
result = state->object_table()->GetObject(
|
||||||
|
timer_handle, (XObject**)&timer);
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
result = timer->SetTimer(due_time, period_ms);
|
||||||
|
timer->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
SHIM_SET_RETURN(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHIM_CALL NtCancelTimer_shim(
|
||||||
|
PPCContext* ppc_state, KernelState* state) {
|
||||||
|
uint32_t timer_handle = SHIM_GET_ARG_32(0);
|
||||||
|
uint32_t current_state_ptr = SHIM_GET_ARG_32(1);
|
||||||
|
|
||||||
|
// UNVERIFIED
|
||||||
|
XEASSERTALWAYS();
|
||||||
|
|
||||||
|
XELOGD(
|
||||||
|
"NtCancelTimer(%.8X, %.8X)",
|
||||||
|
timer_handle, current_state_ptr);
|
||||||
|
|
||||||
|
X_STATUS result = X_STATUS_SUCCESS;
|
||||||
|
|
||||||
|
XTimer* timer = NULL;
|
||||||
|
result = state->object_table()->GetObject(
|
||||||
|
timer_handle, (XObject**)&timer);
|
||||||
|
if (XSUCCEEDED(result)) {
|
||||||
|
result = timer->Cancel();
|
||||||
|
timer->Release();
|
||||||
|
|
||||||
|
if (current_state_ptr) {
|
||||||
|
SHIM_SET_MEM_32(current_state_ptr, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SHIM_SET_RETURN(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
X_STATUS xeKeWaitForSingleObject(
|
X_STATUS xeKeWaitForSingleObject(
|
||||||
void* object_ptr, uint32_t wait_reason, uint32_t processor_mode,
|
void* object_ptr, uint32_t wait_reason, uint32_t processor_mode,
|
||||||
uint32_t alertable, uint64_t* opt_timeout) {
|
uint32_t alertable, uint64_t* opt_timeout) {
|
||||||
|
@ -1208,6 +1303,10 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports(
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateMutant, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateMutant, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", NtReleaseMutant, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtReleaseMutant, state);
|
||||||
|
|
||||||
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtCreateTimer, state);
|
||||||
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtSetTimerEx, state);
|
||||||
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtCancelTimer, state);
|
||||||
|
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForSingleObject, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForSingleObject, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", NtWaitForSingleObjectEx, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtWaitForSingleObjectEx, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForMultipleObjects, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForMultipleObjects, state);
|
||||||
|
|
|
@ -71,8 +71,7 @@ X_STATUS XObject::Delete() {
|
||||||
return shared_kernel_state_->object_table()->RemoveHandle(handle_);
|
return shared_kernel_state_->object_table()->RemoveHandle(handle_);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
uint32_t XObject::TimeoutTicksToMs(int64_t timeout_ticks) {
|
||||||
uint32_t ConvertTimeoutTicks(int64_t timeout_ticks) {
|
|
||||||
if (timeout_ticks > 0) {
|
if (timeout_ticks > 0) {
|
||||||
// Absolute time, based on January 1, 1601.
|
// Absolute time, based on January 1, 1601.
|
||||||
// TODO(benvanik): convert time to relative time.
|
// TODO(benvanik): convert time to relative time.
|
||||||
|
@ -85,7 +84,6 @@ uint32_t ConvertTimeoutTicks(int64_t timeout_ticks) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode,
|
X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode,
|
||||||
uint32_t alertable, uint64_t* opt_timeout) {
|
uint32_t alertable, uint64_t* opt_timeout) {
|
||||||
|
@ -96,7 +94,7 @@ X_STATUS XObject::Wait(uint32_t wait_reason, uint32_t processor_mode,
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD timeout_ms = opt_timeout ?
|
DWORD timeout_ms = opt_timeout ?
|
||||||
ConvertTimeoutTicks(*opt_timeout) : INFINITE;
|
TimeoutTicksToMs(*opt_timeout) : INFINITE;
|
||||||
|
|
||||||
DWORD result = WaitForSingleObjectEx(wait_handle, timeout_ms, alertable);
|
DWORD result = WaitForSingleObjectEx(wait_handle, timeout_ms, alertable);
|
||||||
switch (result) {
|
switch (result) {
|
||||||
|
@ -119,7 +117,7 @@ X_STATUS XObject::SignalAndWait(
|
||||||
uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable,
|
uint32_t wait_reason, uint32_t processor_mode, uint32_t alertable,
|
||||||
uint64_t* opt_timeout) {
|
uint64_t* opt_timeout) {
|
||||||
DWORD timeout_ms = opt_timeout ?
|
DWORD timeout_ms = opt_timeout ?
|
||||||
ConvertTimeoutTicks(*opt_timeout) : INFINITE;
|
TimeoutTicksToMs(*opt_timeout) : INFINITE;
|
||||||
|
|
||||||
DWORD result = SignalObjectAndWait(
|
DWORD result = SignalObjectAndWait(
|
||||||
signal_object->GetWaitHandle(),
|
signal_object->GetWaitHandle(),
|
||||||
|
@ -141,7 +139,7 @@ X_STATUS XObject::WaitMultiple(
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD timeout_ms = opt_timeout ?
|
DWORD timeout_ms = opt_timeout ?
|
||||||
ConvertTimeoutTicks(*opt_timeout) : INFINITE;
|
TimeoutTicksToMs(*opt_timeout) : INFINITE;
|
||||||
|
|
||||||
DWORD result = WaitForMultipleObjectsEx(
|
DWORD result = WaitForMultipleObjectsEx(
|
||||||
count, wait_handles,
|
count, wait_handles,
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
kTypeSemaphore,
|
kTypeSemaphore,
|
||||||
kTypeNotifyListener,
|
kTypeNotifyListener,
|
||||||
kTypeMutant,
|
kTypeMutant,
|
||||||
|
kTypeTimer,
|
||||||
};
|
};
|
||||||
|
|
||||||
XObject(KernelState* kernel_state, Type type);
|
XObject(KernelState* kernel_state, Type type);
|
||||||
|
@ -81,6 +82,8 @@ protected:
|
||||||
Memory* memory() const;
|
Memory* memory() const;
|
||||||
void SetNativePointer(uint32_t native_ptr);
|
void SetNativePointer(uint32_t native_ptr);
|
||||||
|
|
||||||
|
static uint32_t TimeoutTicksToMs(int64_t timeout_ticks);
|
||||||
|
|
||||||
KernelState* kernel_state_;
|
KernelState* kernel_state_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in New Issue