Probably correct semaphore object.
This commit is contained in:
parent
eff46a9d0b
commit
90ff8e590f
|
@ -7,6 +7,8 @@
|
||||||
'xfile.h',
|
'xfile.h',
|
||||||
'xmodule.cc',
|
'xmodule.cc',
|
||||||
'xmodule.h',
|
'xmodule.h',
|
||||||
|
'xsemaphore.cc',
|
||||||
|
'xsemaphore.h',
|
||||||
'xthread.cc',
|
'xthread.cc',
|
||||||
'xthread.h',
|
'xthread.h',
|
||||||
],
|
],
|
||||||
|
|
|
@ -21,6 +21,9 @@ XEvent::XEvent(KernelState* kernel_state) :
|
||||||
}
|
}
|
||||||
|
|
||||||
XEvent::~XEvent() {
|
XEvent::~XEvent() {
|
||||||
|
if (handle_) {
|
||||||
|
CloseHandle(handle_);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XEvent::Initialize(bool manual_reset, bool initial_state) {
|
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/kernel_state.h>
|
||||||
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
|
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
|
||||||
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
|
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
|
||||||
|
#include <xenia/kernel/xboxkrnl/objects/xsemaphore.h>
|
||||||
#include <xenia/kernel/xboxkrnl/objects/xthread.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(
|
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) {
|
||||||
|
@ -829,6 +898,9 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports(
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", KeResetEvent, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", KeResetEvent, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", NtClearEvent, 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", KeWaitForSingleObject, state);
|
||||||
SHIM_SET_MAPPING("xboxkrnl.exe", NtWaitForSingleObjectEx, state);
|
SHIM_SET_MAPPING("xboxkrnl.exe", NtWaitForSingleObjectEx, state);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
|
#include <xenia/kernel/xboxkrnl/xboxkrnl_private.h>
|
||||||
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
|
#include <xenia/kernel/xboxkrnl/objects/xevent.h>
|
||||||
|
#include <xenia/kernel/xboxkrnl/objects/xsemaphore.h>
|
||||||
|
|
||||||
|
|
||||||
using namespace xe;
|
using namespace xe;
|
||||||
|
@ -104,7 +105,8 @@ void XObject::SetNativePointer(uint32_t native_ptr) {
|
||||||
XObject::UnlockType();
|
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
|
// Unfortunately the XDK seems to inline some KeInitialize calls, meaning
|
||||||
// we never see it and just randomly start getting passed events/timers/etc.
|
// 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
|
// 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_flink = XESWAP32(header_be->wait_list_flink);
|
||||||
header.wait_list_blink = XESWAP32(header_be->wait_list_blink);
|
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) {
|
if (header.wait_list_blink & 0x1) {
|
||||||
// Already initialized.
|
// Already initialized.
|
||||||
uint64_t object_ptr =
|
uint64_t object_ptr =
|
||||||
|
@ -136,7 +142,7 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr) {
|
||||||
// First use, create new.
|
// First use, create new.
|
||||||
// http://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html
|
// http://www.nirsoft.net/kernel_struct/vista/KOBJECTS.html
|
||||||
XObject* object = NULL;
|
XObject* object = NULL;
|
||||||
switch (header.type_flags & 0xFF) {
|
switch (as_type) {
|
||||||
case 0: // EventNotificationObject
|
case 0: // EventNotificationObject
|
||||||
case 1: // EventSynchronizationObject
|
case 1: // EventSynchronizationObject
|
||||||
{
|
{
|
||||||
|
@ -145,10 +151,16 @@ XObject* XObject::GetObject(KernelState* kernel_state, void* native_ptr) {
|
||||||
object = ev;
|
object = ev;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 5: // SemaphoreObject
|
||||||
|
{
|
||||||
|
XSemaphore* sem = new XSemaphore(kernel_state);
|
||||||
|
sem->InitializeNative(native_ptr, header);
|
||||||
|
object = sem;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 2: // MutantObject
|
case 2: // MutantObject
|
||||||
case 3: // ProcessObject
|
case 3: // ProcessObject
|
||||||
case 4: // QueueObject
|
case 4: // QueueObject
|
||||||
case 5: // SemaphoreObject
|
|
||||||
case 6: // ThreadObject
|
case 6: // ThreadObject
|
||||||
case 7: // GateObject
|
case 7: // GateObject
|
||||||
case 8: // TimerNotificationObject
|
case 8: // TimerNotificationObject
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
kTypeThread = 0x00000002,
|
kTypeThread = 0x00000002,
|
||||||
kTypeEvent = 0x00000003,
|
kTypeEvent = 0x00000003,
|
||||||
kTypeFile = 0x00000004,
|
kTypeFile = 0x00000004,
|
||||||
|
kTypeSemaphore = 0x00000005,
|
||||||
};
|
};
|
||||||
|
|
||||||
XObject(KernelState* kernel_state, Type type);
|
XObject(KernelState* kernel_state, Type type);
|
||||||
|
@ -61,7 +62,8 @@ public:
|
||||||
|
|
||||||
static void LockType();
|
static void LockType();
|
||||||
static void UnlockType();
|
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:
|
protected:
|
||||||
Memory* memory() const;
|
Memory* memory() const;
|
||||||
|
|
Loading…
Reference in New Issue