// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include #include "common/error.h" #include "common/logging/log.h" #include "common/thread.h" #ifdef __APPLE__ #include #elif defined(_WIN32) #include #else #if defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include #else #include #endif #include #endif #ifndef _WIN32 #include #endif #ifdef __FreeBSD__ #define cpu_set_t cpuset_t #endif namespace Common { #ifdef _WIN32 void SetCurrentThreadPriority(ThreadPriority new_priority) { auto handle = GetCurrentThread(); int windows_priority = 0; switch (new_priority) { case ThreadPriority::Low: windows_priority = THREAD_PRIORITY_BELOW_NORMAL; break; case ThreadPriority::Normal: windows_priority = THREAD_PRIORITY_NORMAL; break; case ThreadPriority::High: windows_priority = THREAD_PRIORITY_ABOVE_NORMAL; break; case ThreadPriority::VeryHigh: windows_priority = THREAD_PRIORITY_HIGHEST; break; case ThreadPriority::Critical: windows_priority = THREAD_PRIORITY_TIME_CRITICAL; break; default: windows_priority = THREAD_PRIORITY_NORMAL; break; } SetThreadPriority(handle, windows_priority); } #else void SetCurrentThreadPriority(ThreadPriority new_priority) { pthread_t this_thread = pthread_self(); const auto scheduling_type = SCHED_OTHER; s32 max_prio = sched_get_priority_max(scheduling_type); s32 min_prio = sched_get_priority_min(scheduling_type); u32 level = std::max(static_cast(new_priority) + 1, 4U); struct sched_param params; if (max_prio > min_prio) { params.sched_priority = min_prio + ((max_prio - min_prio) * level) / 4; } else { params.sched_priority = min_prio - ((min_prio - max_prio) * level) / 4; } pthread_setschedparam(this_thread, scheduling_type, ¶ms); } #endif #ifdef _MSC_VER // Sets the debugger-visible name of the current thread. // Uses trick documented in: // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code void SetCurrentThreadName(const char* name) { static const DWORD MS_VC_EXCEPTION = 0x406D1388; #pragma pack(push, 8) struct THREADNAME_INFO { 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 } info; #pragma pack(pop) info.dwType = 0x1000; info.szName = name; info.dwThreadID = std::numeric_limits::max(); info.dwFlags = 0; __try { RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); } __except (EXCEPTION_CONTINUE_EXECUTION) { } } #else // !MSVC_VER, so must be POSIX threads // MinGW with the POSIX threading model does not support pthread_setname_np #if !defined(_WIN32) || defined(_MSC_VER) void SetCurrentThreadName(const char* name) { #ifdef __APPLE__ pthread_setname_np(name); #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) pthread_set_name_np(pthread_self(), name); #elif defined(__NetBSD__) pthread_setname_np(pthread_self(), "%s", (void*)name); #elif defined(__linux__) // Linux limits thread names to 15 characters and will outright reject any // attempt to set a longer name with ERANGE. std::string truncated(name, std::min(strlen(name), static_cast(15))); if (int e = pthread_setname_np(pthread_self(), truncated.c_str())) { errno = e; LOG_ERROR(Common, "Failed to set thread name to '{}': {}", truncated, GetLastErrorMsg()); } #else pthread_setname_np(pthread_self(), name); #endif } #endif #if defined(_WIN32) void SetCurrentThreadName(const char* name) { // Do Nothing on MingW } #endif #endif } // namespace Common