Probably correct semaphore object.
This commit is contained in:
parent
eff46a9d0b
commit
90ff8e590f
|
@ -7,6 +7,8 @@
|
|||
'xfile.h',
|
||||
'xmodule.cc',
|
||||
'xmodule.h',
|
||||
'xsemaphore.cc',
|
||||
'xsemaphore.h',
|
||||
'xthread.cc',
|
||||
'xthread.h',
|
||||
],
|
||||
|
|
|
@ -21,6 +21,9 @@ XEvent::XEvent(KernelState* kernel_state) :
|
|||
}
|
||||
|
||||
XEvent::~XEvent() {
|
||||
if (handle_) {
|
||||
CloseHandle(handle_);
|
||||
}
|
||||
}
|
||||
|
||||
void XEvent::Initialize(bool manual_reset, bool initial_state) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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_
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue