Timers. Probably.

This commit is contained in:
Ben Vanik 2014-01-07 21:55:32 -08:00
parent 1357a798ef
commit cfe7b2127d
6 changed files with 212 additions and 6 deletions

View File

@ -15,5 +15,7 @@
'xsemaphore.h', 'xsemaphore.h',
'xthread.cc', 'xthread.cc',
'xthread.h', 'xthread.h',
'xtimer.cc',
'xtimer.h',
], ],
} }

View File

@ -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;
}

View File

@ -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_

View File

@ -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);

View File

@ -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,

View File

@ -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: