Skip to content

Commit

Permalink
feat(threading): Name all game threads & own threads.
Browse files Browse the repository at this point in the history
  • Loading branch information
Force67 committed Apr 29, 2022
1 parent aa00ba3 commit d397a62
Show file tree
Hide file tree
Showing 14 changed files with 230 additions and 9 deletions.
46 changes: 46 additions & 0 deletions Code/base/threading/ThreadUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

#include "ThreadUtils.h"

namespace
{
// as defined in sentry-native/src/sentry_sync.h
#ifdef _WIN32
#include <Windows.h>
using sentry_threadid_t = HANDLE;

sentry_threadid_t GetCurrentThreadHandle()
{
return ::GetCurrentThread();
}
#else
#include <pthread.h>
using sentry_threadid_t = pthread_t;

sentry_threadid_t GetCurrentThreadHandle()
{
return ::pthread_self();
}
#endif

} // namespace

// we use the sentry impl here, as it covers all bases, e.g linux & windows support, plus additional windows 10+
// features
extern "C"
{
int sentry__thread_setname(sentry_threadid_t aThreadHandle, const char* apThreadName);
}

namespace base
{
bool SetThreadName(void* apThreadHandle, const char* apThreadName)
{
return sentry__thread_setname(reinterpret_cast<sentry_threadid_t>(apThreadHandle), apThreadName) == 0;
}

bool SetCurrentThreadName(const char* apThreadName)
{
return sentry__thread_setname(GetCurrentThreadHandle(), apThreadName) == 0;
}

} // namespace base
10 changes: 10 additions & 0 deletions Code/base/threading/ThreadUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#pragma once

namespace base
{
// set to thread handle
bool SetThreadName(void* apThreadHandle, const char* apThreadName);

// call this on current thread
bool SetCurrentThreadName(const char* apThreadName);
} // namespace base
3 changes: 2 additions & 1 deletion Code/base/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ target("BaseLib")
add_headerfiles("**.h")
add_files("**.cpp")
add_packages(
"tiltedcore",
"tiltedcore",
"sentry-native",
"hopscotch-map",
"gtest",
"spdlog")
35 changes: 35 additions & 0 deletions Code/client/Games/Skyrim/BSSystem/BSTaskletManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

#include <base/threading/ThreadUtils.h>

namespace
{
struct BSTaskletManager
{
char pad0[0x30];
void* threadHandles[6];
};

static void (*Construct_TaskletManager)(BSTaskletManager*);

static void Hook_Construct_TaskletManager(BSTaskletManager* apSelf)
{
Construct_TaskletManager(apSelf);

for (int i = 0; i < 6; i++)
{
if (!apSelf->threadHandles[i])
continue;

auto name = fmt::format("TaskletThread{}", i);
base::SetThreadName(apSelf->threadHandles[i], name.c_str());
}
}
} // namespace

static TiltedPhoques::Initializer s_BSThreadInit([]() {
const VersionDbPtr<uint8_t> getTaskletManagerInstance(69554);

// tasklet naming
TiltedPhoques::SwapCall(getTaskletManagerInstance.Get() + 0x63, Construct_TaskletManager,
&Hook_Construct_TaskletManager);
});
95 changes: 95 additions & 0 deletions Code/client/Games/Skyrim/BSSystem/BSThread.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@

#include <Games/Skyrim/BSSystem/BSThread.h>
#include <base/threading/ThreadUtils.h>

namespace
{
void (*BSThread_Initialize)(BSThread*, int, const char*){nullptr};

void Hook_BSThread_Initialize(BSThread* apThis, int aStackSize, const char* apName)
{
BSThread_Initialize(apThis, aStackSize, apName);

if (!apName && apThis->m_ThreadHandle)
spdlog::warn("Unnamed thread started: {}", apThis->m_ThreadID);

// this means the thread was successfully created
if (apThis->m_ThreadHandle)
{
bool result = base::SetThreadName(apThis->m_ThreadHandle, apName);
if (!result)
{
spdlog::warn("Failed to set thread name for tid {} to {}", apThis->m_ThreadID, apName);
}
}
}

// bsthreadutils
// hook this in order to redirect the game to use the new naming apis (windows 10+)
void Hook_SetThreadName(uint32_t aThreadId, const char* apThreadName)
{
// query thread handle
if (auto hThread = ::OpenThread(THREAD_QUERY_INFORMATION, FALSE, aThreadId))
{
base::SetThreadName(hThread, apThreadName);

::CloseHandle(hThread);
}
else
spdlog::warn("Hook_SetThreadName(): Unable to query thread handle :(");
}

// experimental stuff..
#if 0
typedef struct
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;

void Hook_RaiseException(DWORD, DWORD, DWORD, const THREADNAME_INFO* lpArguments)
{
base::SetCurrentThreadName(lpArguments->szName);
}

HANDLE WINAPI Hook_CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags,
LPDWORD lpThreadId)
{
auto hThread =
CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);

if (hThread && lpThreadId)
{
auto name = fmt::format("BNetThread{}", *lpThreadId);
base::SetThreadName(hThread, name.c_str());
}

return hThread;
}
#endif
} // namespace

static TiltedPhoques::Initializer s_BSThreadInit([]() {
const VersionDbPtr<uint8_t> threadInit(68261);
BSThread_Initialize = static_cast<decltype(BSThread_Initialize)>(threadInit.GetPtr());
// need to detour this for now :/
TP_HOOK_IMMEDIATE(&BSThread_Initialize, &Hook_BSThread_Initialize);

const VersionDbPtr<uint8_t> setThreadName(69066);
TiltedPhoques::Jump(setThreadName.Get(), &Hook_SetThreadName);

#if 0
const VersionDbPtr<uint8_t> createHavokThread(57704);
// relatively safe to do, since this is unlikely to ever change, as beth wont update havok
TiltedPhoques::Nop(createHavokThread.Get() + 0x81, 6);

TiltedPhoques::PutCall(createHavokThread.Get() + 0x81, &Hook_RaiseException);


TiltedPhoques::Nop(0x1411F0FD4, 6);
TiltedPhoques::PutCall(0x1411F0FD4, &Hook_CreateThread);
#endif
});
20 changes: 20 additions & 0 deletions Code/client/Games/Skyrim/BSSystem/BSThread.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

class BSThread
{
public:
virtual ~BSThread() = 0;
// runner
virtual uint32_t ThreadProc() = 0;
// probably release
virtual bool Release() = 0;

//private:
CRITICAL_SECTION lock; // in reality a BSCriticalSection
void* m_ThreadHandle;
void* m_ParentHandle;
uint32_t m_ThreadID;
uint32_t m_ParentID;
bool bThreadIsActive;
};
static_assert(sizeof(BSThread) == 0x50, "BSThread size mismatch");
10 changes: 5 additions & 5 deletions Code/client/Games/Skyrim/Projectiles/Projectile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,11 @@ static TiltedPhoques::Initializer s_projectileHooks([]() {

TP_HOOK(&RealLaunch, HookLaunch);

static VersionDbPtr<void*> hookLoc(34452);
VersionDbPtr<uint8_t> hookLoc(34452);

struct C : TiltedPhoques::CodeGenerator
{
C()
C(uint8_t* apLoc)
{
// replicate
mov(rbx, ptr[rsp + 0x50]);
Expand All @@ -121,7 +121,7 @@ static TiltedPhoques::Initializer s_projectileHooks([]() {
cmp(rbx, 0);
jz("exit");
// jump back
jmp_S(uintptr_t(hookLoc.Get()) + 0x379);
jmp_S(apLoc + 0x379);

L("exit");
// return false; scratch space from the registers
Expand All @@ -137,7 +137,7 @@ static TiltedPhoques::Initializer s_projectileHooks([]() {
pop(rbp);
ret();
}
} gen;
TiltedPhoques::Jump(uintptr_t(hookLoc.Get()) + 0x374, gen.getCode());
} gen(hookLoc.Get());
TiltedPhoques::Jump(hookLoc.Get() + 0x374, gen.getCode());
});

4 changes: 2 additions & 2 deletions Code/client/Games/Skyrim/RTTI.h
Original file line number Diff line number Diff line change
Expand Up @@ -512,8 +512,8 @@ struct NiStream;
extern template struct internal::RttiLocator<NiStream>;
struct InterfacedClass;
extern template struct internal::RttiLocator<InterfacedClass>;
struct BSThread;
extern template struct internal::RttiLocator<BSThread>;
class BSThread;
extern template class internal::RttiLocator<BSThread>;
struct TESBipedModelForm;
extern template struct internal::RttiLocator<TESBipedModelForm>;
struct QueuedActor;
Expand Down
3 changes: 3 additions & 0 deletions Code/client/Services/Generic/DiscordService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <PlayerCharacter.h>
#include <Forms/TESWorldSpace.h>

#include <base/threading/ThreadUtils.h>
#include <Events/LocationChangeEvent.h>

#define DISCORD_OVERLAY_ENABLE 0
Expand Down Expand Up @@ -206,6 +207,8 @@ bool DiscordService::Init()
//TODO (Force): i want to move this away from its own thread
//this is done because discord needs to be ticked before world
static std::thread updateThread([&]() {
base::SetCurrentThreadName("DiscordCallbacks");

while (!m_bRequestThreadKillHack)
{
const auto runResult = m_pCore->run_callbacks(m_pCore);
Expand Down
1 change: 1 addition & 0 deletions Code/client/xmake.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ target(name)
add_deps(
"UiProcess",
"CommonLib",
"BaseLib",
"ImGuiImpl",
"TiltedConnect",
"TiltedReverse",
Expand Down
3 changes: 3 additions & 0 deletions Code/immersive_launcher/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "launcher.h"
#include <Windows.h>
#include <combaseapi.h>
#include <base/threading/ThreadUtils.h>

#include "script_extender/SEMemoryBlock.h"
#include <crash_handler/CrashHandler.h>
Expand Down Expand Up @@ -53,6 +54,8 @@ struct ComScope

int main(int argc, char** argv)
{
base::SetCurrentThreadName("MainLauncherThread");

// memory block for Script Extender reserved as early as we can
script_extender::SEMemoryBlock b;
if (!b.Good())
Expand Down
Binary file modified Code/immersive_launcher/launcher.aps
Binary file not shown.
3 changes: 3 additions & 0 deletions Code/server_runner/DediRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <chrono>
#include <iostream>
#include <base/threading/ThreadUtils.h>

namespace
{
Expand Down Expand Up @@ -86,6 +87,8 @@ void DediRunner::RunGSThread()
void DediRunner::StartTerminalIO()
{
m_pConIOThread.reset(new std::jthread([&]() {
base::SetCurrentThreadName("ConsoleIO");

spdlog::get("ConOut")->info("Server console");
PrintExecutorArrowHack();

Expand Down
6 changes: 5 additions & 1 deletion Code/server_runner/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

#include <Setting.h>
#include <base/simpleini/SimpleIni.h>
#include <crash_handler/CrashHandler.h>
#include <base/threading/ThreadUtils.h>

#include "DediRunner.h"
#include <crash_handler/CrashHandler.h>

namespace
{
Expand Down Expand Up @@ -150,6 +152,8 @@ int main(int argc, char** argv)
if (!CheckBuildTag(kBuildTag))
return 1;

base::SetCurrentThreadName("ServerRunnerMain");

LogInstance logger;
(void)logger;

Expand Down

0 comments on commit d397a62

Please sign in to comment.