Probably correct semaphore object.

This commit is contained in:
Ben Vanik 2014-01-04 13:56:38 -08:00
parent eff46a9d0b
commit 90ff8e590f
7 changed files with 228 additions and 8 deletions

View File

@ -7,6 +7,8 @@
'xfile.h',
'xmodule.cc',
'xmodule.h',
'xsemaphore.cc',
'xsemaphore.h',
'xthread.cc',
'xthread.h',
],

View File

@ -21,6 +21,9 @@ XEvent::XEvent(KernelState* kernel_state) :
}
XEvent::~XEvent() {
if (handle_) {
CloseHandle(handle_);
}
}
void XEvent::Initialize(bool manual_reset, bool initial_state) {

View File

@ -0,0 +1,83 @@
/**
******************************************************************************
* 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/xboxkrnl/objects/xsemaphore.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::xboxkrnl;
XSemaphore::XSemaphore(KernelState* kernel_state) :
XObject(kernel_state, kTypeSemaphore),
handle_(NULL) {
}
XSemaphore::~XSemaphore() {
if (handle_) {
CloseHandle(handle_);
}
}
void XSemaphore::Initialize(int32_t initial_count, int32_t maximum_count) {
XEASSERTNULL(handle_);
handle_ = CreateSemaphore(NULL, initial_count, maximum_count, NULL);
}
void XSemaphore::InitializeNative(void* native_ptr, DISPATCH_HEADER& header) {
XEASSERTNULL(handle_);
// NOT IMPLEMENTED
// We expect Initialize to be called shortly.
}
int32_t XSemaphore::ReleaseSemaphore(int32_t release_count) {
LONG previous_count = 0;
::ReleaseSemaphore(handle_, release_count, &previous_count);
return previous_count;
}
X_STATUS XSemaphore::Wait(
uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
DWORD timeout_ms;
if (opt_timeout) {
int64_t timeout_ticks = (int64_t)(*opt_timeout);
if (timeout_ticks > 0) {
// Absolute time, based on January 1, 1601.
// TODO(benvanik): convert time to relative time.
XEASSERTALWAYS();
timeout_ms = 0;
} else if (timeout_ticks < 0) {
// Relative time.
timeout_ms = (DWORD)(-timeout_ticks / 10000); // Ticks -> MS
} else {
timeout_ms = 0;
}
} else {
timeout_ms = INFINITE;
}
DWORD result = WaitForSingleObjectEx(handle_, timeout_ms, alertable);
switch (result) {
case WAIT_OBJECT_0:
return X_STATUS_SUCCESS;
case WAIT_IO_COMPLETION:
// Or X_STATUS_ALERTED?
return X_STATUS_USER_APC;
case WAIT_TIMEOUT:
return X_STATUS_TIMEOUT;
default:
case WAIT_FAILED:
case WAIT_ABANDONED:
return X_STATUS_ABANDONED_WAIT_0;
}
}

View File

@ -0,0 +1,46 @@
/**
******************************************************************************
* 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_XSEMAPHORE_H_
#define XENIA_KERNEL_XBOXKRNL_XSEMAPHORE_H_
#include <xenia/kernel/xboxkrnl/xobject.h>
#include <xenia/xbox.h>
namespace xe {
namespace kernel {
namespace xboxkrnl {
class XSemaphore : public XObject {
public:
XSemaphore(KernelState* kernel_state);
virtual ~XSemaphore();
void Initialize(int32_t initial_count, int32_t maximum_count);
void InitializeNative(void* native_ptr, DISPATCH_HEADER& header);
int32_t ReleaseSemaphore(int32_t release_count);
virtual X_STATUS Wait(uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout);
private:
HANDLE handle_;
};
} // namespace xboxkrnl
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_XBOXKRNL_XSEMAPHORE_H_

View File

@ -13,6 +13,7 @@
#include <xenia/kernel/xboxkrnl/kernel_state.h>
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
#include <xenia/kernel/xboxkrnl/objects/xsemaphore.h>
#include <xenia/kernel/xboxkrnl/objects/xthread.h>
@ -656,6 +657,74 @@ SHIM_CALL NtClearEvent_shim(
}
void xeKeInitializeSemaphore(
void* semaphore_ptr, int32_t count, int32_t limit) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
XSemaphore* sem = (XSemaphore*)XSemaphore::GetObject(
state, semaphore_ptr, 5 /* SemaphoreObject */);
XEASSERTNOTNULL(sem);
if (!sem) {
return;
}
sem->Initialize(count, limit);
}
SHIM_CALL KeInitializeSemaphore_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t semaphore_ref = SHIM_GET_ARG_32(0);
int32_t count = SHIM_GET_ARG_32(1);
int32_t limit = SHIM_GET_ARG_32(2);
XELOGD(
"KeInitializeSemaphore(%.8X, %d, %d)",
semaphore_ref, count, limit);
void* semaphore_ptr = SHIM_MEM_ADDR(semaphore_ref);
xeKeInitializeSemaphore(semaphore_ptr, count, limit);
}
int32_t xeKeReleaseSemaphore(
void* semaphore_ptr, int32_t increment, int32_t adjustment, bool wait) {
KernelState* state = shared_kernel_state_;
XEASSERTNOTNULL(state);
XSemaphore* sem = (XSemaphore*)XSemaphore::GetObject(state, semaphore_ptr);
XEASSERTNOTNULL(sem);
if (!sem) {
return 0;
}
// TODO(benvanik): increment thread priority?
// TODO(benvanik): wait?
return sem->ReleaseSemaphore(adjustment);
}
SHIM_CALL KeReleaseSemaphore_shim(
PPCContext* ppc_state, KernelState* state) {
uint32_t semaphore_ref = SHIM_GET_ARG_32(0);
int32_t increment = SHIM_GET_ARG_32(1);
int32_t adjustment = SHIM_GET_ARG_32(2);
int32_t wait = SHIM_GET_ARG_32(3);
XELOGD(
"KeReleaseSemaphore(%.8X, %d, %d, #d)",
semaphore_ref, increment, adjustment, wait);
void* semaphore_ptr = SHIM_MEM_ADDR(semaphore_ref);
int32_t result = xeKeReleaseSemaphore(
semaphore_ptr, increment, adjustment, wait == 1);
SHIM_SET_RETURN(result);
}
X_STATUS xeKeWaitForSingleObject(
void* object_ptr, uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout) {
@ -829,6 +898,9 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports(
SHIM_SET_MAPPING("xboxkrnl.exe", KeResetEvent, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtClearEvent, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeInitializeSemaphore, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeReleaseSemaphore, state);
SHIM_SET_MAPPING("xboxkrnl.exe", KeWaitForSingleObject, state);
SHIM_SET_MAPPING("xboxkrnl.exe", NtWaitForSingleObjectEx, state);

View File

@ -11,6 +11,7 @@
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
#include <xenia/kernel/xboxkrnl/objects/xsemaphore.h>
using namespace xe;
@ -104,7 +105,8 @@ void XObject::SetNativePointer(uint32_t native_ptr) {
XObject::UnlockType();
}
XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr) {
XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr,
int32_t as_type) {
// Unfortunately the XDK seems to inline some KeInitialize calls, meaning
// we never see it and just randomly start getting passed events/timers/etc.
// Luckily it seems like all other calls (Set/Reset/Wait/etc) are used and
@ -123,6 +125,10 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr) {
header.wait_list_flink = XESWAP32(header_be->wait_list_flink);
header.wait_list_blink = XESWAP32(header_be->wait_list_blink);
if (as_type == -1) {
as_type = header.type_flags & 0xFF;
}
if (header.wait_list_blink & 0x1) {
// Already initialized.
uint64_t object_ptr =
@ -136,7 +142,7 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr) {
// First use, create new.
// http://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html
XObject* object = NULL;
switch (header.type_flags & 0xFF) {
switch (as_type) {
case 0: // EventNotificationObject
case 1: // EventSynchronizationObject
{
@ -145,10 +151,16 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr) {
object = ev;
}
break;
case 5: // SemaphoreObject
{
XSemaphore* sem = new XSemaphore(kernel_state);
sem->InitializeNative(native_ptr, header);
object = sem;
}
break;
case 2: // MutantObject
case 3: // ProcessObject
case 4: // QueueObject
case 5: // SemaphoreObject
case 6: // ThreadObject
case 7: // GateObject
case 8: // TimerNotificationObject

View File

@ -32,10 +32,11 @@ typedef struct {
class XObject {
public:
enum Type {
kTypeModule = 0x00000001,
kTypeThread = 0x00000002,
kTypeEvent = 0x00000003,
kTypeFile = 0x00000004,
kTypeModule = 0x00000001,
kTypeThread = 0x00000002,
kTypeEvent = 0x00000003,
kTypeFile = 0x00000004,
kTypeSemaphore = 0x00000005,
};
XObject(KernelState* kernel_state, Type type);
@ -61,7 +62,8 @@ public:
static void LockType();
static void UnlockType();
static XObject* GetObject(KernelState* kernel_state, void* native_ptr);
static XObject* GetObject(KernelState* kernel_state, void* native_ptr,
int32_t as_type = -1);
protected:
Memory* memory() const;