mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 12:51:42 +00:00
Cross-platform event implementation. (#47)
This commit is contained in:
parent
4770e85573
commit
2bcaa61d42
1 changed files with 171 additions and 114 deletions
|
|
@ -16,6 +16,129 @@
|
||||||
|
|
||||||
#include <ntstatus.h>
|
#include <ntstatus.h>
|
||||||
|
|
||||||
|
struct Event final : KernelObject, HostObject<XKEVENT>
|
||||||
|
{
|
||||||
|
bool manualReset;
|
||||||
|
std::atomic<bool> signaled;
|
||||||
|
|
||||||
|
Event(XKEVENT* header)
|
||||||
|
: manualReset(!header->Type), signaled(!!header->SignalState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Event(bool manualReset, bool initialState)
|
||||||
|
: manualReset(manualReset), signaled(initialState)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Wait(uint32_t timeout) override
|
||||||
|
{
|
||||||
|
if (timeout == 0)
|
||||||
|
{
|
||||||
|
if (!signaled)
|
||||||
|
return STATUS_TIMEOUT;
|
||||||
|
|
||||||
|
if (!manualReset)
|
||||||
|
signaled = false;
|
||||||
|
}
|
||||||
|
else if (timeout == INFINITE)
|
||||||
|
{
|
||||||
|
signaled.wait(false);
|
||||||
|
|
||||||
|
if (!manualReset)
|
||||||
|
signaled = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false && "Unhandled timeout value.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Set()
|
||||||
|
{
|
||||||
|
signaled = true;
|
||||||
|
signaled.notify_all();
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Reset()
|
||||||
|
{
|
||||||
|
signaled = false;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::atomic<uint32_t> g_keSetEventGeneration;
|
||||||
|
|
||||||
|
struct Semaphore final : KernelObject, HostObject<XKSEMAPHORE>
|
||||||
|
{
|
||||||
|
std::atomic<uint32_t> count;
|
||||||
|
uint32_t maximumCount;
|
||||||
|
|
||||||
|
Semaphore(XKSEMAPHORE* semaphore)
|
||||||
|
: count(semaphore->Header.SignalState), maximumCount(semaphore->Limit)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Semaphore(uint32_t count, uint32_t maximumCount)
|
||||||
|
: count(count), maximumCount(maximumCount)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Wait(uint32_t timeout) override
|
||||||
|
{
|
||||||
|
if (timeout == 0)
|
||||||
|
{
|
||||||
|
uint32_t currentCount = count.load();
|
||||||
|
if (currentCount != 0)
|
||||||
|
{
|
||||||
|
if (count.compare_exchange_weak(currentCount, currentCount - 1))
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_TIMEOUT;
|
||||||
|
}
|
||||||
|
else if (timeout == INFINITE)
|
||||||
|
{
|
||||||
|
uint32_t currentCount;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
currentCount = count.load();
|
||||||
|
if (currentCount != 0)
|
||||||
|
{
|
||||||
|
if (count.compare_exchange_weak(currentCount, currentCount - 1))
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
count.wait(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
assert(false && "Unhandled timeout value.");
|
||||||
|
return STATUS_TIMEOUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Release(uint32_t releaseCount, uint32_t* previousCount)
|
||||||
|
{
|
||||||
|
if (previousCount != nullptr)
|
||||||
|
*previousCount = count;
|
||||||
|
|
||||||
|
assert(count + releaseCount <= maximumCount);
|
||||||
|
|
||||||
|
count += releaseCount;
|
||||||
|
count.notify_all();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
inline void CloseKernelObject(XDISPATCHER_HEADER& header)
|
inline void CloseKernelObject(XDISPATCHER_HEADER& header)
|
||||||
{
|
{
|
||||||
if (header.WaitListHead.Flink != OBJECT_SIGNATURE)
|
if (header.WaitListHead.Flink != OBJECT_SIGNATURE)
|
||||||
|
|
@ -265,19 +388,10 @@ DWORD NtWaitForSingleObjectEx(DWORD Handle, DWORD WaitMode, DWORD Alertable, XLP
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const auto status = WaitForSingleObjectEx((HANDLE)Handle, timeout, Alertable);
|
assert(false && "Unrecognized handle value.");
|
||||||
|
|
||||||
if (status == WAIT_IO_COMPLETION)
|
|
||||||
{
|
|
||||||
return STATUS_USER_APC;
|
|
||||||
}
|
}
|
||||||
else if (status == WAIT_TIMEOUT)
|
|
||||||
{
|
|
||||||
return STATUS_TIMEOUT;
|
return STATUS_TIMEOUT;
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NtWriteFile()
|
void NtWriteFile()
|
||||||
|
|
@ -367,9 +481,9 @@ void MmQueryStatistics()
|
||||||
LOG_UTILITY("!!! STUB !!!");
|
LOG_UTILITY("!!! STUB !!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NtCreateEvent(uint32_t* handle, void* objAttributes, uint32_t eventType, uint32_t initialState)
|
uint32_t NtCreateEvent(be<uint32_t>* handle, void* objAttributes, uint32_t eventType, uint32_t initialState)
|
||||||
{
|
{
|
||||||
*handle = ByteSwap((uint32_t)CreateEventA(nullptr, !eventType, !!initialState, nullptr));
|
*handle = GetKernelHandle(CreateKernelObject<Event>(!eventType, !!initialState));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -529,92 +643,6 @@ uint32_t KeSetAffinityThread(DWORD Thread, DWORD Affinity, XLPDWORD lpPreviousAf
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Event final : KernelObject, HostObject<XKEVENT>
|
|
||||||
{
|
|
||||||
HANDLE handle;
|
|
||||||
|
|
||||||
Event(XKEVENT* header)
|
|
||||||
{
|
|
||||||
handle = CreateEventA(nullptr, !header->Type, !!header->SignalState, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Set()
|
|
||||||
{
|
|
||||||
return SetEvent(handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Reset()
|
|
||||||
{
|
|
||||||
return ResetEvent(handle);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Semaphore final : KernelObject, HostObject<XKSEMAPHORE>
|
|
||||||
{
|
|
||||||
std::atomic<uint32_t> count;
|
|
||||||
uint32_t maximumCount;
|
|
||||||
|
|
||||||
Semaphore(XKSEMAPHORE* semaphore)
|
|
||||||
: count(semaphore->Header.SignalState), maximumCount(semaphore->Limit)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Semaphore(uint32_t count, uint32_t maximumCount)
|
|
||||||
: count(count), maximumCount(maximumCount)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t Wait(uint32_t timeout) override
|
|
||||||
{
|
|
||||||
if (timeout == 0)
|
|
||||||
{
|
|
||||||
uint32_t currentCount = count.load();
|
|
||||||
if (currentCount != 0)
|
|
||||||
{
|
|
||||||
if (count.compare_exchange_weak(currentCount, currentCount - 1))
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
else if (timeout == INFINITE)
|
|
||||||
{
|
|
||||||
uint32_t currentCount;
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
currentCount = count.load();
|
|
||||||
if (currentCount != 0)
|
|
||||||
{
|
|
||||||
if (count.compare_exchange_weak(currentCount, currentCount - 1))
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
count.wait(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
assert(false && "Unhandled timeout value.");
|
|
||||||
return STATUS_TIMEOUT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Release(uint32_t releaseCount, uint32_t* previousCount)
|
|
||||||
{
|
|
||||||
if (previousCount != nullptr)
|
|
||||||
*previousCount = count;
|
|
||||||
|
|
||||||
assert(count + releaseCount <= maximumCount);
|
|
||||||
|
|
||||||
count += releaseCount;
|
|
||||||
count.notify_all();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void RtlLeaveCriticalSection(XRTL_CRITICAL_SECTION* cs)
|
void RtlLeaveCriticalSection(XRTL_CRITICAL_SECTION* cs)
|
||||||
{
|
{
|
||||||
cs->RecursionCount--;
|
cs->RecursionCount--;
|
||||||
|
|
@ -936,7 +964,12 @@ void KeUnlockL2()
|
||||||
|
|
||||||
bool KeSetEvent(XKEVENT* pEvent, DWORD Increment, bool Wait)
|
bool KeSetEvent(XKEVENT* pEvent, DWORD Increment, bool Wait)
|
||||||
{
|
{
|
||||||
return QueryKernelObject<Event>(*pEvent)->Set();
|
bool result = QueryKernelObject<Event>(*pEvent)->Set();
|
||||||
|
|
||||||
|
++g_keSetEventGeneration;
|
||||||
|
g_keSetEventGeneration.notify_all();
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool KeResetEvent(XKEVENT* pEvent)
|
bool KeResetEvent(XKEVENT* pEvent)
|
||||||
|
|
@ -953,7 +986,7 @@ DWORD KeWaitForSingleObject(XDISPATCHER_HEADER* Object, DWORD WaitReason, DWORD
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
WaitForSingleObjectEx(QueryKernelObject<Event>(*Object)->handle, timeout, Alertable);
|
QueryKernelObject<Event>(*Object)->Wait(timeout);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
|
|
@ -1245,9 +1278,10 @@ void MmQueryAllocationSize()
|
||||||
LOG_UTILITY("!!! STUB !!!");
|
LOG_UTILITY("!!! STUB !!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NtClearEvent(uint32_t handle, uint32_t* previousState)
|
uint32_t NtClearEvent(Event* handle, uint32_t* previousState)
|
||||||
{
|
{
|
||||||
return ResetEvent((HANDLE)handle) ? 0 : 0xFFFFFFFF;
|
handle->Reset();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NtResumeThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
|
uint32_t NtResumeThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
|
||||||
|
|
@ -1260,9 +1294,10 @@ uint32_t NtResumeThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NtSetEvent(uint32_t handle, uint32_t* previousState)
|
uint32_t NtSetEvent(Event* handle, uint32_t* previousState)
|
||||||
{
|
{
|
||||||
return SetEvent((HANDLE)handle) ? 0 : 0xFFFFFFFF;
|
handle->Set();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS NtCreateSemaphore(XLPDWORD Handle, XOBJECT_ATTRIBUTES* ObjectAttributes, DWORD InitialCount, DWORD MaximumCount)
|
NTSTATUS NtCreateSemaphore(XLPDWORD Handle, XOBJECT_ATTRIBUTES* ObjectAttributes, DWORD InitialCount, DWORD MaximumCount)
|
||||||
|
|
@ -1431,19 +1466,41 @@ void NetDll_XNetGetTitleXnAddr()
|
||||||
|
|
||||||
DWORD KeWaitForMultipleObjects(DWORD Count, xpointer<XDISPATCHER_HEADER>* Objects, DWORD WaitType, DWORD WaitReason, DWORD WaitMode, DWORD Alertable, XLPQWORD Timeout)
|
DWORD KeWaitForMultipleObjects(DWORD Count, xpointer<XDISPATCHER_HEADER>* Objects, DWORD WaitType, DWORD WaitReason, DWORD WaitMode, DWORD Alertable, XLPQWORD Timeout)
|
||||||
{
|
{
|
||||||
// TODO: create actual objects by type.
|
// FIXME: This function is only accounting for events.
|
||||||
const uint64_t timeout = GuestTimeoutToMilliseconds(Timeout);
|
|
||||||
|
|
||||||
thread_local std::vector<HANDLE> events;
|
const uint64_t timeout = GuestTimeoutToMilliseconds(Timeout);
|
||||||
events.resize(Count);
|
assert(timeout == INFINITE);
|
||||||
|
|
||||||
|
if (WaitType == 0) // Wait all
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < Count; i++)
|
||||||
|
QueryKernelObject<Event>(*Objects[i])->Wait(timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
thread_local std::vector<Event*> s_events;
|
||||||
|
s_events.resize(Count);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < Count; i++)
|
||||||
|
s_events[i] = QueryKernelObject<Event>(*Objects[i]);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
uint32_t generation = g_keSetEventGeneration.load();
|
||||||
|
|
||||||
for (size_t i = 0; i < Count; i++)
|
for (size_t i = 0; i < Count; i++)
|
||||||
{
|
{
|
||||||
assert(Objects[i]->Type <= 1);
|
if (s_events[i]->Wait(0) == STATUS_SUCCESS)
|
||||||
events[i] = QueryKernelObject<Event>(*Objects[i].get())->handle;
|
{
|
||||||
|
return WAIT_OBJECT_0 + i;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return WaitForMultipleObjectsEx(Count, events.data(), WaitType == 0, timeout, Alertable);
|
g_keSetEventGeneration.wait(generation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t KeRaiseIrqlToDpcLevel()
|
uint32_t KeRaiseIrqlToDpcLevel()
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue