diff --git a/lib/libimhex/include/hex/api/task_manager.hpp b/lib/libimhex/include/hex/api/task_manager.hpp index 1c7868be1..b6cc8eb80 100644 --- a/lib/libimhex/include/hex/api/task_manager.hpp +++ b/lib/libimhex/include/hex/api/task_manager.hpp @@ -154,6 +154,9 @@ namespace hex { */ static void runWhenTasksFinished(const std::function &function); + static void setCurrentThreadName(const std::string &name); + static std::string getCurrentThreadName(); + static void collectGarbage(); static size_t getRunningTaskCount(); diff --git a/lib/libimhex/include/hex/helpers/utils.hpp b/lib/libimhex/include/hex/helpers/utils.hpp index ec3e47cc9..1bbe17996 100644 --- a/lib/libimhex/include/hex/helpers/utils.hpp +++ b/lib/libimhex/include/hex/helpers/utils.hpp @@ -78,7 +78,8 @@ namespace hex { [[nodiscard]] std::string encodeByteString(const std::vector &bytes); [[nodiscard]] std::vector decodeByteString(const std::string &string); - std::wstring utf8ToUtf16(const std::string& utf8); + [[nodiscard]] std::wstring utf8ToUtf16(const std::string& utf8); + [[nodiscard]] std::string utf16ToUtf8(const std::wstring& utf16); [[nodiscard]] constexpr u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) { if (from < to) std::swap(from, to); diff --git a/lib/libimhex/source/api/task_manager.cpp b/lib/libimhex/source/api/task_manager.cpp index f5277cee6..9317a990f 100644 --- a/lib/libimhex/source/api/task_manager.cpp +++ b/lib/libimhex/source/api/task_manager.cpp @@ -6,6 +6,7 @@ #include #include +#include #if defined(OS_WINDOWS) #include @@ -31,32 +32,6 @@ namespace hex { } - static void setThreadName(const std::string &name) { - #if defined(OS_WINDOWS) - typedef struct tagTHREADNAME_INFO { - DWORD dwType; - LPCSTR szName; - DWORD dwThreadID; - DWORD dwFlags; - } THREADNAME_INFO; - - THREADNAME_INFO info; - info.dwType = 0x1000; - info.szName = name.c_str(); - info.dwThreadID = ::GetCurrentThreadId(); - info.dwFlags = 0; - - constexpr static DWORD MS_VC_EXCEPTION = 0x406D1388; - RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), reinterpret_cast(&info)); - #elif defined(OS_LINUX) - pthread_setname_np(pthread_self(), name.c_str()); - #elif defined(OS_WEB) - hex::unused(name); - #elif defined(OS_MACOS) - pthread_setname_np(name.c_str()); - #endif - } - Task::Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function function) : m_unlocalizedName(std::move(unlocalizedName)), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { } @@ -222,7 +197,6 @@ namespace hex { return u32((task->getValue() * 100) / task->getMaxValue()); } - void TaskManager::init() { const auto threadCount = std::thread::hardware_concurrency(); @@ -235,7 +209,7 @@ namespace hex { std::shared_ptr task; // Set the thread name to "Idle Task" while waiting for a task - setThreadName("Idle Task"); + TaskManager::setCurrentThreadName("Idle Task"); { // Wait for a task to be added to the queue @@ -255,7 +229,7 @@ namespace hex { try { // Set the thread name to the name of the task - setThreadName(Lang(task->m_unlocalizedName)); + TaskManager::setCurrentThreadName(Lang(task->m_unlocalizedName)); // Execute the task task->m_function(*task); @@ -391,4 +365,41 @@ namespace hex { s_tasksFinishedCallbacks.push_back(function); } + void TaskManager::setCurrentThreadName(const std::string &name) { + #if defined(OS_WINDOWS) + auto longName = hex::utf8ToUtf16(name); + ::SetThreadDescription(::GetCurrentThread(), longName.c_str()); + #elif defined(OS_LINUX) + pthread_setname_np(pthread_self(), name.c_str()); + #elif defined(OS_WEB) + hex::unused(name); + #elif defined(OS_MACOS) + pthread_setname_np(name.c_str()); + #endif + } + + std::string TaskManager::getCurrentThreadName() { + #if defined(OS_WINDOWS) + PWSTR name; + if (SUCCEEDED(::GetThreadDescription(::GetCurrentThread(), &name))) { + auto utf8Name = hex::utf16ToUtf8(name); + LocalFree(name); + + return utf8Name; + } + + return ""; + #elif defined(OS_MACOS) || defined(OS_LINUX) + std::array name; + pthread_getname_np(pthread_self(), name.data(), name.size()); + + return name; + #elif defined(OS_WEB) + return ""; + #else + return ""; + #endif + } + + } diff --git a/lib/libimhex/source/helpers/logger.cpp b/lib/libimhex/source/helpers/logger.cpp index 7cbeb12de..12b36ab91 100644 --- a/lib/libimhex/source/helpers/logger.cpp +++ b/lib/libimhex/source/helpers/logger.cpp @@ -6,6 +6,7 @@ #include #include +#include #if defined(OS_WINDOWS) #include @@ -72,10 +73,18 @@ namespace hex::log::impl { else fmt::print(dest, ts, "{0} ", level); - fmt::print(dest, "[{0}] ", projectName); + std::string projectThreadTag = projectName; + if (auto threadName = TaskManager::getCurrentThreadName(); !threadName.empty()) + projectThreadTag += fmt::format("|{0}", threadName); - auto projectNameLength = std::string_view(projectName).length(); - fmt::print(dest, "{}", std::string(projectNameLength > 10 ? 0 : 10 - projectNameLength, ' ')); + constexpr static auto MaxTagLength = 25; + if (projectThreadTag.length() > MaxTagLength) + projectThreadTag.resize(MaxTagLength); + + fmt::print(dest, "[{0}] ", projectThreadTag); + + const auto projectNameLength = projectThreadTag.length(); + fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' ')); } void assertionHandler(bool expr, const char* exprString, const char* file, int line) { diff --git a/lib/libimhex/source/helpers/utils.cpp b/lib/libimhex/source/helpers/utils.cpp index d7adf9a00..ad74fc5fd 100644 --- a/lib/libimhex/source/helpers/utils.cpp +++ b/lib/libimhex/source/helpers/utils.cpp @@ -550,6 +550,60 @@ namespace hex { return utf16; } + std::string utf16ToUtf8(const std::wstring& utf16) { + std::vector unicodes; + + for (size_t index = 0; index < utf16.size();) { + u32 unicode = 0; + + wchar_t wch = utf16[index]; + index += 1; + + if (wch < 0xD800 || wch > 0xDFFF) { + unicode = static_cast(wch); + } else if (wch >= 0xD800 && wch <= 0xDBFF) { + if (index == utf16.size()) + return ""; + + wchar_t nextWch = utf16[index]; + index += 1; + + if (nextWch < 0xDC00 || nextWch > 0xDFFF) + return ""; + + unicode = static_cast(((wch - 0xD800) << 10) + (nextWch - 0xDC00) + 0x10000); + } else { + return ""; + } + + unicodes.push_back(unicode); + } + + std::string utf8; + + for (auto unicode : unicodes) { + if (unicode <= 0x7F) { + utf8 += static_cast(unicode); + } else if (unicode <= 0x7FF) { + utf8 += static_cast(0xC0 | ((unicode >> 6) & 0x1F)); + utf8 += static_cast(0x80 | (unicode & 0x3F)); + } else if (unicode <= 0xFFFF) { + utf8 += static_cast(0xE0 | ((unicode >> 12) & 0x0F)); + utf8 += static_cast(0x80 | ((unicode >> 6) & 0x3F)); + utf8 += static_cast(0x80 | (unicode & 0x3F)); + } else if (unicode <= 0x10FFFF) { + utf8 += static_cast(0xF0 | ((unicode >> 18) & 0x07)); + utf8 += static_cast(0x80 | ((unicode >> 12) & 0x3F)); + utf8 += static_cast(0x80 | ((unicode >> 6) & 0x3F)); + utf8 += static_cast(0x80 | (unicode & 0x3F)); + } else { + return ""; + } + } + + return utf8; + } + float float16ToFloat32(u16 float16) { u32 sign = float16 >> 15; u32 exponent = (float16 >> 10) & 0x1F; diff --git a/main/gui/source/init/splash_window.cpp b/main/gui/source/init/splash_window.cpp index 69950bf47..9a6caaa09 100644 --- a/main/gui/source/init/splash_window.cpp +++ b/main/gui/source/init/splash_window.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include using namespace std::literals::chrono_literals; @@ -191,7 +192,10 @@ namespace hex::init { // If the task can be run asynchronously, run it in a separate thread // otherwise run it in this thread and wait for it to finish if (task.async) { - std::thread([runTask = std::move(runTask)]{ runTask(); }).detach(); + std::thread([name = task.name, runTask = std::move(runTask)] { + TaskManager::setCurrentThreadName(name); + runTask(); + }).detach(); } else { runTask(); } @@ -199,6 +203,8 @@ namespace hex::init { std::future WindowSplash::processTasksAsync() { return std::async(std::launch::async, [this] { + TaskManager::setCurrentThreadName("Init Tasks"); + auto startTime = std::chrono::high_resolution_clock::now(); // Loop over all registered init tasks diff --git a/main/gui/source/main.cpp b/main/gui/source/main.cpp index 0c569565e..8fcfcde00 100644 --- a/main/gui/source/main.cpp +++ b/main/gui/source/main.cpp @@ -246,6 +246,7 @@ namespace { * @return Exit code */ int main(int argc, char **argv) { + TaskManager::setCurrentThreadName("Main"); Window::initNative(); crash::setupCrashHandlers();