Skip to content

Commit

Permalink
Set thread names for game threads (#666)
Browse files Browse the repository at this point in the history
Adds nice thread names that can be visible in crash dumps, non-attachable debuggers and generally in all places where old method of throwing exceptions to attached debugger on game start wouldn't work
  • Loading branch information
p0358 authored Sep 7, 2024
1 parent 8c546ed commit 8824340
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
40 changes: 40 additions & 0 deletions primedev/client/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -509,13 +509,53 @@ static void __fastcall h_MilesLog(int level, const char* string)
spdlog::info("[MSS] {} - {}", level, string);
}

static void(__fastcall* o_pSub_18003EBD0)(DWORD dwThreadID, const char* threadName) = nullptr;
static void __fastcall h_Sub_18003EBD0(DWORD dwThreadID, const char* threadName)
{
HANDLE hThread = OpenThread(THREAD_SET_LIMITED_INFORMATION, FALSE, dwThreadID);

if (hThread != NULL)
{
// TODO: This "method" of "charset conversion" from string to wstring is abhorrent. Change it to a proper one
// as soon as Northstar has some helper function to do proper charset conversions.
auto tmp = std::string(threadName);
HRESULT WINAPI _SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription);
_SetThreadDescription(hThread, std::wstring(tmp.begin(), tmp.end()).c_str());

CloseHandle(hThread);
}

o_pSub_18003EBD0(dwThreadID, threadName);
}

static char*(__fastcall* o_pSub_18003BC10)(void* a1, void* a2, void* a3, void* a4, void* a5, int a6) = nullptr;
static char* __fastcall h_Sub_18003BC10(void* a1, void* a2, void* a3, void* a4, void* a5, int a6)
{
HANDLE hThread;
char* ret = o_pSub_18003BC10(a1, a2, a3, a4, a5, a6);

if (ret != NULL && (hThread = reinterpret_cast<HANDLE>(*((uint64_t*)ret + 55))) != NULL)
{
HRESULT WINAPI _SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription);
_SetThreadDescription(hThread, L"[Miles] WASAPI Service Thread");
}

return ret;
}

ON_DLL_LOAD("mileswin64.dll", MilesWin64_Audio, (CModule module))
{
o_pLoadSampleMetadata = module.Offset(0xF110).RCast<decltype(o_pLoadSampleMetadata)>();
HookAttach(&(PVOID&)o_pLoadSampleMetadata, (PVOID)h_LoadSampleMetadata);

o_pSub_1800294C0 = module.Offset(0x294C0).RCast<decltype(o_pSub_1800294C0)>();
HookAttach(&(PVOID&)o_pSub_1800294C0, (PVOID)h_Sub_1800294C0);

o_pSub_18003EBD0 = module.Offset(0x3EBD0).RCast<decltype(o_pSub_18003EBD0)>();
HookAttach(&(PVOID&)o_pSub_18003EBD0, (PVOID)h_Sub_18003EBD0);

o_pSub_18003BC10 = module.Offset(0x3BC10).RCast<decltype(o_pSub_18003BC10)>();
HookAttach(&(PVOID&)o_pSub_18003BC10, (PVOID)h_Sub_18003BC10);
}

ON_DLL_LOAD_RELIESON("engine.dll", MilesLogFuncHooks, ConVar, (CModule module))
Expand Down
29 changes: 29 additions & 0 deletions primedev/core/tier0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,40 @@ void TryCreateGlobalMemAlloc()
g_pMemAllocSingleton = CreateGlobalMemAlloc(); // if it already exists, this returns the preexisting IMemAlloc instance
}

HRESULT WINAPI _SetThreadDescription(HANDLE hThread, PCWSTR lpThreadDescription)
{
// need to grab it dynamically as this function was only introduced at some point in Windows 10
static decltype(&SetThreadDescription) _SetThreadDescription =
CModule("KernelBase.dll").GetExportedFunction("SetThreadDescription").RCast<decltype(&SetThreadDescription)>();

if (_SetThreadDescription)
return _SetThreadDescription(hThread, lpThreadDescription);

return ERROR_OLD_WIN_VERSION;
}

static void(__fastcall* o_pThreadSetDebugName)(HANDLE threadHandle, const char* name) = nullptr;
static void __fastcall h_ThreadSetDebugName(HANDLE threadHandle, const char* name)
{
if (threadHandle == 0)
threadHandle = GetCurrentThread();

// TODO: This "method" of "charset conversion" from string to wstring is abhorrent. Change it to a proper one
// as soon as Northstar has some helper function to do proper charset conversions.
auto tmp = std::string(name);
_SetThreadDescription(threadHandle, std::wstring(tmp.begin(), tmp.end()).c_str());

o_pThreadSetDebugName(threadHandle, name);
}

ON_DLL_LOAD("tier0.dll", Tier0GameFuncs, (CModule module))
{
// shouldn't be necessary, but do this just in case
TryCreateGlobalMemAlloc();

o_pThreadSetDebugName = module.GetExportedFunction("ThreadSetDebugName").RCast<decltype(o_pThreadSetDebugName)>();
HookAttach(&(PVOID&)o_pThreadSetDebugName, (PVOID)h_ThreadSetDebugName);

// setup tier0 funcs
CommandLine = module.GetExportedFunction("CommandLine").RCast<CommandLineType>();
Plat_FloatTime = module.GetExportedFunction("Plat_FloatTime").RCast<Plat_FloatTimeType>();
Expand Down

0 comments on commit 8824340

Please sign in to comment.