mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2026-04-27 12:51:42 +00:00
Cross platform thread implementation. (#41)
* Cross-platform thread implementation. * Put set thread name calls behind a Win32 macro.
This commit is contained in:
parent
c23db5b746
commit
afce26fc35
6 changed files with 164 additions and 97 deletions
|
|
@ -27,7 +27,7 @@ GuestThreadContext::GuestThreadContext(uint32_t cpuNumber)
|
||||||
*(thread + 0x10C) = cpuNumber;
|
*(thread + 0x10C) = cpuNumber;
|
||||||
|
|
||||||
*(uint32_t*)(thread + PCR_SIZE + 0x10) = 0xFFFFFFFF; // that one TLS entry that felt quirky
|
*(uint32_t*)(thread + PCR_SIZE + 0x10) = 0xFFFFFFFF; // that one TLS entry that felt quirky
|
||||||
*(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = ByteSwap(GetCurrentThreadId()); // thread id
|
*(uint32_t*)(thread + PCR_SIZE + TLS_SIZE + 0x14C) = ByteSwap(GuestThread::GetCurrentThreadId()); // thread id
|
||||||
|
|
||||||
ppcContext.fn = (uint8_t*)g_codeCache.bucket;
|
ppcContext.fn = (uint8_t*)g_codeCache.bucket;
|
||||||
ppcContext.r1.u64 = g_memory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer
|
ppcContext.r1.u64 = g_memory.MapVirtual(thread + PCR_SIZE + TLS_SIZE + TEB_SIZE + STACK_SIZE); // stack pointer
|
||||||
|
|
@ -42,42 +42,82 @@ GuestThreadContext::~GuestThreadContext()
|
||||||
g_userHeap.Free(thread);
|
g_userHeap.Free(thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD GuestThread::Start(uint32_t function)
|
static void GuestThreadFunc(GuestThreadHandle* hThread)
|
||||||
{
|
{
|
||||||
const GuestThreadParameter parameter{ function };
|
hThread->suspended.wait(true);
|
||||||
return Start(parameter);
|
GuestThread::Start(hThread->params);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD GuestThread::Start(const GuestThreadParameter& parameter)
|
GuestThreadHandle::GuestThreadHandle(const GuestThreadParams& params)
|
||||||
|
: params(params), suspended((params.flags & 0x1) != 0), thread(GuestThreadFunc, this)
|
||||||
{
|
{
|
||||||
const auto procMask = (uint8_t)(parameter.flags >> 24);
|
}
|
||||||
|
|
||||||
|
GuestThreadHandle::~GuestThreadHandle()
|
||||||
|
{
|
||||||
|
if (thread.joinable())
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuestThreadHandle::Wait(uint32_t timeout)
|
||||||
|
{
|
||||||
|
assert(timeout == INFINITE);
|
||||||
|
|
||||||
|
if (thread.joinable())
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GuestThread::Start(const GuestThreadParams& params)
|
||||||
|
{
|
||||||
|
const auto procMask = (uint8_t)(params.flags >> 24);
|
||||||
const auto cpuNumber = procMask == 0 ? 0 : 7 - std::countl_zero(procMask);
|
const auto cpuNumber = procMask == 0 ? 0 : 7 - std::countl_zero(procMask);
|
||||||
|
|
||||||
GuestThreadContext ctx(cpuNumber);
|
GuestThreadContext ctx(cpuNumber);
|
||||||
ctx.ppcContext.r3.u64 = parameter.value;
|
ctx.ppcContext.r3.u64 = params.value;
|
||||||
|
|
||||||
GuestCode::Run(g_codeCache.Find(parameter.function), &ctx.ppcContext, g_memory.Translate(0));
|
GuestCode::Run(g_codeCache.Find(params.function), &ctx.ppcContext, g_memory.Translate(0));
|
||||||
|
|
||||||
return (DWORD)ctx.ppcContext.r3.u64;
|
return ctx.ppcContext.r3.u32;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD HostThreadStart(void* pParameter)
|
static uint32_t GetThreadId(const std::thread::id& id)
|
||||||
{
|
{
|
||||||
auto* parameter = static_cast<GuestThreadParameter*>(pParameter);
|
if constexpr (sizeof(id) == 4)
|
||||||
const auto result = GuestThread::Start(*parameter);
|
return *reinterpret_cast<const uint32_t*>(&id);
|
||||||
|
else
|
||||||
delete parameter;
|
return XXH32(&id, sizeof(id), 0);
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE GuestThread::Start(uint32_t function, uint32_t parameter, uint32_t flags, LPDWORD threadId)
|
GuestThreadHandle* GuestThread::Start(const GuestThreadParams& params, uint32_t* threadId)
|
||||||
{
|
{
|
||||||
const auto hostCreationFlags = (flags & 1) != 0 ? CREATE_SUSPENDED : 0;
|
auto hThread = CreateKernelObject<GuestThreadHandle>(params);
|
||||||
//return CreateThread(nullptr, 0, Start, (void*)((uint64_t(parameter) << 32) | function), suspended ? CREATE_SUSPENDED : 0, threadId);
|
|
||||||
return CreateThread(nullptr, 0, HostThreadStart, new GuestThreadParameter{ function, parameter, flags }, hostCreationFlags, threadId);
|
if (threadId != nullptr)
|
||||||
|
*threadId = GetThreadId(hThread->thread.get_id());
|
||||||
|
|
||||||
|
return hThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GuestThread::SetThreadName(uint32_t id, const char* name)
|
uint32_t GuestThread::GetCurrentThreadId()
|
||||||
|
{
|
||||||
|
return GetThreadId(std::this_thread::get_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
void GuestThread::SetLastError(uint32_t error)
|
||||||
|
{
|
||||||
|
auto* thread = (char*)g_memory.Translate(GetPPCContext()->r13.u32);
|
||||||
|
if (*(uint32_t*)(thread + 0x150))
|
||||||
|
{
|
||||||
|
// Program doesn't want errors
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEB + 0x160 : Win32LastError
|
||||||
|
*(uint32_t*)(thread + TEB_OFFSET + 0x160) = ByteSwap(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
void GuestThread::SetThreadName(uint32_t threadId, const char* name)
|
||||||
{
|
{
|
||||||
#pragma pack(push,8)
|
#pragma pack(push,8)
|
||||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||||
|
|
@ -94,7 +134,7 @@ void GuestThread::SetThreadName(uint32_t id, const char* name)
|
||||||
THREADNAME_INFO info;
|
THREADNAME_INFO info;
|
||||||
info.dwType = 0x1000;
|
info.dwType = 0x1000;
|
||||||
info.szName = name;
|
info.szName = name;
|
||||||
info.dwThreadID = id;
|
info.dwThreadID = threadId;
|
||||||
info.dwFlags = 0;
|
info.dwFlags = 0;
|
||||||
|
|
||||||
__try
|
__try
|
||||||
|
|
@ -105,41 +145,31 @@ void GuestThread::SetThreadName(uint32_t id, const char* name)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
void GuestThread::SetLastError(DWORD error)
|
|
||||||
{
|
|
||||||
auto* thread = (char*)g_memory.Translate(GetPPCContext()->r13.u32);
|
|
||||||
if (*(DWORD*)(thread + 0x150))
|
|
||||||
{
|
|
||||||
// Program doesn't want errors
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TEB + 0x160 : Win32LastError
|
|
||||||
*(DWORD*)(thread + TEB_OFFSET + 0x160) = ByteSwap(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
PPCContext* GuestThread::Invoke(uint32_t address)
|
|
||||||
{
|
|
||||||
auto* ctx = GetPPCContext();
|
|
||||||
GuestCode::Run(g_codeCache.Find(address), ctx);
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetThreadNameImpl(uint32_t a1, uint32_t threadId, uint32_t* name)
|
void SetThreadNameImpl(uint32_t a1, uint32_t threadId, uint32_t* name)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
GuestThread::SetThreadName(threadId, (const char*)g_memory.Translate(ByteSwap(*name)));
|
GuestThread::SetThreadName(threadId, (const char*)g_memory.Translate(ByteSwap(*name)));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int GetThreadPriorityImpl(uint32_t hThread)
|
int GetThreadPriorityImpl(GuestThreadHandle* hThread)
|
||||||
{
|
{
|
||||||
return GetThreadPriority((HANDLE)hThread);
|
#ifdef _WIN32
|
||||||
|
return GetThreadPriority(hThread == GetKernelObject(CURRENT_THREAD_HANDLE) ? GetCurrentThread() : hThread->thread.native_handle());
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD SetThreadIdealProcessorImpl(uint32_t hThread, DWORD dwIdealProcessor)
|
uint32_t SetThreadIdealProcessorImpl(GuestThreadHandle* hThread, uint32_t dwIdealProcessor)
|
||||||
{
|
{
|
||||||
return SetThreadIdealProcessor((HANDLE)hThread, dwIdealProcessor);
|
#ifdef _WIN32
|
||||||
|
return SetThreadIdealProcessor(hThread == GetKernelObject(CURRENT_THREAD_HANDLE) ? GetCurrentThread() : hThread->thread.native_handle(), dwIdealProcessor);
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl);
|
GUEST_FUNCTION_HOOK(sub_82DFA2E8, SetThreadNameImpl);
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
struct PPCContext;
|
#include <kernel/xdm.h>
|
||||||
struct GuestThreadParameter
|
|
||||||
{
|
#define CURRENT_THREAD_HANDLE uint32_t(-2)
|
||||||
uint32_t function;
|
|
||||||
uint32_t value;
|
|
||||||
uint32_t flags;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GuestThreadContext
|
struct GuestThreadContext
|
||||||
{
|
{
|
||||||
|
|
@ -17,13 +13,34 @@ struct GuestThreadContext
|
||||||
~GuestThreadContext();
|
~GuestThreadContext();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GuestThreadParams
|
||||||
|
{
|
||||||
|
uint32_t function;
|
||||||
|
uint32_t value;
|
||||||
|
uint32_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GuestThreadHandle : KernelObject
|
||||||
|
{
|
||||||
|
GuestThreadParams params;
|
||||||
|
std::atomic<bool> suspended;
|
||||||
|
std::thread thread;
|
||||||
|
|
||||||
|
GuestThreadHandle(const GuestThreadParams& params);
|
||||||
|
~GuestThreadHandle() override;
|
||||||
|
|
||||||
|
void Wait(uint32_t timeout) override;
|
||||||
|
};
|
||||||
|
|
||||||
struct GuestThread
|
struct GuestThread
|
||||||
{
|
{
|
||||||
static DWORD Start(uint32_t function);
|
static uint32_t Start(const GuestThreadParams& params);
|
||||||
static DWORD Start(const GuestThreadParameter& parameter);
|
static GuestThreadHandle* Start(const GuestThreadParams& params, uint32_t* threadId);
|
||||||
static HANDLE Start(uint32_t function, uint32_t parameter, uint32_t flags, LPDWORD threadId);
|
|
||||||
|
|
||||||
static void SetThreadName(uint32_t id, const char* name);
|
static uint32_t GetCurrentThreadId();
|
||||||
static void SetLastError(DWORD error);
|
static void SetLastError(uint32_t error);
|
||||||
static PPCContext* Invoke(uint32_t address);
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
static void SetThreadName(uint32_t threadId, const char* name);
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -4047,8 +4047,9 @@ static void ProcSetPixelShader(const RenderCommand& cmd)
|
||||||
|
|
||||||
static std::thread g_renderThread([]
|
static std::thread g_renderThread([]
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
GuestThread::SetThreadName(GetCurrentThreadId(), "Render Thread");
|
GuestThread::SetThreadName(GetCurrentThreadId(), "Render Thread");
|
||||||
|
#endif
|
||||||
RenderCommand commands[32];
|
RenderCommand commands[32];
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
|
|
@ -4857,7 +4858,9 @@ static moodycamel::BlockingConcurrentQueue<PipelineStateQueueItem> g_pipelineSta
|
||||||
|
|
||||||
static void PipelineCompilerThread()
|
static void PipelineCompilerThread()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
GuestThread::SetThreadName(GetCurrentThreadId(), "Pipeline Compiler Thread");
|
GuestThread::SetThreadName(GetCurrentThreadId(), "Pipeline Compiler Thread");
|
||||||
|
#endif
|
||||||
std::unique_ptr<GuestThreadContext> ctx;
|
std::unique_ptr<GuestThreadContext> ctx;
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
|
|
@ -5508,8 +5511,9 @@ static bool CheckMadeAll(const T& modelData)
|
||||||
|
|
||||||
static void ModelConsumerThread()
|
static void ModelConsumerThread()
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
GuestThread::SetThreadName(GetCurrentThreadId(), "Model Consumer Thread");
|
GuestThread::SetThreadName(GetCurrentThreadId(), "Model Consumer Thread");
|
||||||
|
#endif
|
||||||
std::vector<boost::shared_ptr<Hedgehog::Database::CDatabaseData>> localPendingDataQueue;
|
std::vector<boost::shared_ptr<Hedgehog::Database::CDatabaseData>> localPendingDataQueue;
|
||||||
std::unique_ptr<GuestThreadContext> ctx;
|
std::unique_ptr<GuestThreadContext> ctx;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -256,7 +256,16 @@ uint32_t FscSetCacheElementCount()
|
||||||
|
|
||||||
DWORD NtWaitForSingleObjectEx(DWORD Handle, DWORD WaitMode, DWORD Alertable, XLPQWORD Timeout)
|
DWORD NtWaitForSingleObjectEx(DWORD Handle, DWORD WaitMode, DWORD Alertable, XLPQWORD Timeout)
|
||||||
{
|
{
|
||||||
const auto status = WaitForSingleObjectEx((HANDLE)Handle, GuestTimeoutToMilliseconds(Timeout), Alertable);
|
uint32_t timeout = GuestTimeoutToMilliseconds(Timeout);
|
||||||
|
assert(timeout == 0 || timeout == INFINITE);
|
||||||
|
|
||||||
|
if (IsKernelObject(Handle))
|
||||||
|
{
|
||||||
|
GetKernelObject(Handle)->Wait(timeout);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const auto status = WaitForSingleObjectEx((HANDLE)Handle, timeout, Alertable);
|
||||||
|
|
||||||
if (status == WAIT_IO_COMPLETION)
|
if (status == WAIT_IO_COMPLETION)
|
||||||
{
|
{
|
||||||
|
|
@ -266,6 +275,7 @@ DWORD NtWaitForSingleObjectEx(DWORD Handle, DWORD WaitMode, DWORD Alertable, XLP
|
||||||
{
|
{
|
||||||
return STATUS_ALERTED;
|
return STATUS_ALERTED;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
@ -474,8 +484,9 @@ void ObDereferenceObject()
|
||||||
LOG_UTILITY("!!! STUB !!!");
|
LOG_UTILITY("!!! STUB !!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeSetBasePriorityThread(uint32_t thread, int priority)
|
void KeSetBasePriorityThread(GuestThreadHandle* hThread, int priority)
|
||||||
{
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
if (priority == 16)
|
if (priority == 16)
|
||||||
{
|
{
|
||||||
priority = 15;
|
priority = 15;
|
||||||
|
|
@ -485,7 +496,8 @@ void KeSetBasePriorityThread(uint32_t thread, int priority)
|
||||||
priority = -15;
|
priority = -15;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetThreadPriority((HANDLE)thread, priority);
|
SetThreadPriority(hThread == GetKernelObject(CURRENT_THREAD_HANDLE) ? GetCurrentThread() : hThread->thread.native_handle(), priority);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ObReferenceObjectByHandle(uint32_t handle, uint32_t objectType, XLPDWORD object)
|
uint32_t ObReferenceObjectByHandle(uint32_t handle, uint32_t objectType, XLPDWORD object)
|
||||||
|
|
@ -499,15 +511,12 @@ void KeQueryBasePriorityThread()
|
||||||
LOG_UTILITY("!!! STUB !!!");
|
LOG_UTILITY("!!! STUB !!!");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NtSuspendThread(uint32_t hThread, uint32_t* suspendCount)
|
uint32_t NtSuspendThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
|
||||||
{
|
{
|
||||||
DWORD count = SuspendThread((HANDLE)hThread);
|
assert(hThread != GetKernelObject(CURRENT_THREAD_HANDLE) && hThread->thread.get_id() == std::this_thread::get_id());
|
||||||
|
|
||||||
if (count == (DWORD)-1)
|
hThread->suspended = true;
|
||||||
return E_FAIL;
|
hThread->suspended.wait(true);
|
||||||
|
|
||||||
if (suspendCount != nullptr)
|
|
||||||
*suspendCount = ByteSwap(count);
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -890,29 +899,32 @@ DWORD KeWaitForSingleObject(XDISPATCHER_HEADER* Object, DWORD WaitReason, DWORD
|
||||||
return WaitForSingleObjectEx(handle, timeout, Alertable);
|
return WaitForSingleObjectEx(handle, timeout, Alertable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static thread_local std::vector<uint32_t> g_tlsValues;
|
|
||||||
static std::vector<size_t> g_tlsFreeIndices;
|
static std::vector<size_t> g_tlsFreeIndices;
|
||||||
static size_t g_tlsNextIndex = 0;
|
static size_t g_tlsNextIndex = 0;
|
||||||
static Mutex g_tlsAllocationMutex;
|
static Mutex g_tlsAllocationMutex;
|
||||||
|
|
||||||
static void KeTlsEnsureTlsCapacity(size_t index)
|
static uint32_t& KeTlsGetValueRef(size_t index)
|
||||||
{
|
{
|
||||||
if (g_tlsValues.size() <= index)
|
// Having this a global thread_local variable
|
||||||
|
// for some reason crashes on boot in debug builds.
|
||||||
|
thread_local std::vector<uint32_t> s_tlsValues;
|
||||||
|
|
||||||
|
if (s_tlsValues.size() <= index)
|
||||||
{
|
{
|
||||||
g_tlsValues.resize(index + 1, 0);
|
s_tlsValues.resize(index + 1, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return s_tlsValues[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t KeTlsGetValue(DWORD dwTlsIndex)
|
uint32_t KeTlsGetValue(DWORD dwTlsIndex)
|
||||||
{
|
{
|
||||||
KeTlsEnsureTlsCapacity(dwTlsIndex);
|
return KeTlsGetValueRef(dwTlsIndex);
|
||||||
return g_tlsValues[dwTlsIndex];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL KeTlsSetValue(DWORD dwTlsIndex, DWORD lpTlsValue)
|
BOOL KeTlsSetValue(DWORD dwTlsIndex, DWORD lpTlsValue)
|
||||||
{
|
{
|
||||||
KeTlsEnsureTlsCapacity(dwTlsIndex);
|
KeTlsGetValueRef(dwTlsIndex) = lpTlsValue;
|
||||||
g_tlsValues[dwTlsIndex] = lpTlsValue;
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1169,15 +1181,12 @@ uint32_t NtClearEvent(uint32_t handle, uint32_t* previousState)
|
||||||
return ResetEvent((HANDLE)handle) ? 0 : 0xFFFFFFFF;
|
return ResetEvent((HANDLE)handle) ? 0 : 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t NtResumeThread(uint32_t hThread, uint32_t* suspendCount)
|
uint32_t NtResumeThread(GuestThreadHandle* hThread, uint32_t* suspendCount)
|
||||||
{
|
{
|
||||||
DWORD count = ResumeThread((HANDLE)hThread);
|
assert(hThread != GetKernelObject(CURRENT_THREAD_HANDLE));
|
||||||
|
|
||||||
if (count == (DWORD)-1)
|
hThread->suspended = false;
|
||||||
return E_FAIL;
|
hThread->suspended.notify_all();
|
||||||
|
|
||||||
if (suspendCount != nullptr)
|
|
||||||
*suspendCount = ByteSwap(count);
|
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -1270,9 +1279,9 @@ uint32_t ExCreateThread(XLPDWORD handle, uint32_t stackSize, XLPDWORD threadId,
|
||||||
LOGF_UTILITY("0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}",
|
LOGF_UTILITY("0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}, 0x{:X}",
|
||||||
(intptr_t)handle, stackSize, (intptr_t)threadId, xApiThreadStartup, startAddress, startContext, creationFlags);
|
(intptr_t)handle, stackSize, (intptr_t)threadId, xApiThreadStartup, startAddress, startContext, creationFlags);
|
||||||
|
|
||||||
DWORD hostThreadId;
|
uint32_t hostThreadId;
|
||||||
|
|
||||||
*handle = (uint32_t)GuestThread::Start(startAddress, startContext, creationFlags, &hostThreadId);
|
*handle = GetKernelHandle(GuestThread::Start({ startAddress, startContext, creationFlags }, &hostThreadId));
|
||||||
|
|
||||||
if (threadId != nullptr)
|
if (threadId != nullptr)
|
||||||
*threadId = hostThreadId;
|
*threadId = hostThreadId;
|
||||||
|
|
@ -1391,10 +1400,13 @@ DWORD XAudioGetVoiceCategoryVolumeChangeMask(DWORD Driver, XLPDWORD Mask)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t KeResumeThread(uint32_t object)
|
uint32_t KeResumeThread(GuestThreadHandle* object)
|
||||||
{
|
{
|
||||||
LOGF_UTILITY("0x{:x}", object);
|
assert(object != GetKernelObject(CURRENT_THREAD_HANDLE));
|
||||||
return ResumeThread((HANDLE)object);
|
|
||||||
|
object->suspended = false;
|
||||||
|
object->suspended.notify_all();
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeInitializeSemaphore(XKSEMAPHORE* semaphore, uint32_t count, uint32_t limit)
|
void KeInitializeSemaphore(XKSEMAPHORE* semaphore, uint32_t count, uint32_t limit)
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,11 @@ struct KernelObject
|
||||||
{
|
{
|
||||||
virtual ~KernelObject()
|
virtual ~KernelObject()
|
||||||
{
|
{
|
||||||
;
|
}
|
||||||
|
|
||||||
|
virtual void Wait(uint32_t timeout)
|
||||||
|
{
|
||||||
|
assert(false && "Wait not implemented for this kernel object.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
Video::StartPipelinePrecompilation();
|
Video::StartPipelinePrecompilation();
|
||||||
|
|
||||||
GuestThread::Start(entry);
|
GuestThread::Start({ entry, 0, 0 });
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue