1 // Copyright 2008 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #include "Common/Thread.h"
6 #include "Common/CommonFuncs.h"
7 #include "Common/CommonTypes.h"
8 #include "Common/StringUtil.h"
9 
10 #ifdef _WIN32
11 #include <Windows.h>
12 #include <processthreadsapi.h>
13 #else
14 #include <unistd.h>
15 #endif
16 
17 #ifdef __APPLE__
18 #include <mach/mach.h>
19 #elif defined BSD4_4 || defined __FreeBSD__ || defined __OpenBSD__
20 #include <pthread_np.h>
21 #elif defined __HAIKU__
22 #include <OS.h>
23 #endif
24 
25 #ifdef USE_VTUNE
26 #include <ittnotify.h>
27 #pragma comment(lib, "libittnotify.lib")
28 #endif
29 
30 namespace Common
31 {
CurrentThreadId()32 int CurrentThreadId()
33 {
34 #ifdef _WIN32
35   return GetCurrentThreadId();
36 #elif defined __APPLE__
37   return mach_thread_self();
38 #else
39   return 0;
40 #endif
41 }
42 
43 #ifdef _WIN32
44 
SetThreadAffinity(std::thread::native_handle_type thread,u32 mask)45 void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
46 {
47   SetThreadAffinityMask(thread, mask);
48 }
49 
SetCurrentThreadAffinity(u32 mask)50 void SetCurrentThreadAffinity(u32 mask)
51 {
52   SetThreadAffinityMask(GetCurrentThread(), mask);
53 }
54 
55 // Supporting functions
SleepCurrentThread(int ms)56 void SleepCurrentThread(int ms)
57 {
58   Sleep(ms);
59 }
60 
SwitchCurrentThread()61 void SwitchCurrentThread()
62 {
63   SwitchToThread();
64 }
65 
66 // Sets the debugger-visible name of the current thread.
67 // Uses trick documented in:
68 // https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
SetCurrentThreadNameViaException(const char * name)69 static void SetCurrentThreadNameViaException(const char* name)
70 {
71   static const DWORD MS_VC_EXCEPTION = 0x406D1388;
72 
73 #pragma pack(push, 8)
74   struct THREADNAME_INFO
75   {
76     DWORD dwType;      // must be 0x1000
77     LPCSTR szName;     // pointer to name (in user addr space)
78     DWORD dwThreadID;  // thread ID (-1=caller thread)
79     DWORD dwFlags;     // reserved for future use, must be zero
80   } info;
81 #pragma pack(pop)
82 
83   info.dwType = 0x1000;
84   info.szName = name;
85   info.dwThreadID = static_cast<DWORD>(-1);
86   info.dwFlags = 0;
87 
88   __try
89   {
90     RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info);
91   }
92   __except (EXCEPTION_CONTINUE_EXECUTION)
93   {
94   }
95 }
96 
SetCurrentThreadNameViaApi(const char * name)97 static void SetCurrentThreadNameViaApi(const char* name)
98 {
99   // If possible, also set via the newer API. On some versions of Server it needs to be manually
100   // resolved. This API allows being able to observe the thread name even if a debugger wasn't
101   // attached when the name was set (see above link for more info).
102   static auto pSetThreadDescription = (decltype(&SetThreadDescription))GetProcAddress(
103       GetModuleHandleA("kernel32"), "SetThreadDescription");
104   if (pSetThreadDescription)
105   {
106     pSetThreadDescription(GetCurrentThread(), UTF8ToWString(name).c_str());
107   }
108 }
109 
SetCurrentThreadName(const char * name)110 void SetCurrentThreadName(const char* name)
111 {
112   SetCurrentThreadNameViaException(name);
113   SetCurrentThreadNameViaApi(name);
114 }
115 
116 #else  // !WIN32, so must be POSIX threads
117 
SetThreadAffinity(std::thread::native_handle_type thread,u32 mask)118 void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
119 {
120 #ifdef __APPLE__
121   thread_policy_set(pthread_mach_thread_np(thread), THREAD_AFFINITY_POLICY, (integer_t*)&mask, 1);
122 #elif (defined __linux__ || defined BSD4_4 || defined __FreeBSD__) && !(defined ANDROID)
123 #ifdef __FreeBSD__
124   cpuset_t cpu_set;
125 #else
126   cpu_set_t cpu_set;
127 #endif
128   CPU_ZERO(&cpu_set);
129 
130   for (int i = 0; i != sizeof(mask) * 8; ++i)
131     if ((mask >> i) & 1)
132       CPU_SET(i, &cpu_set);
133 
134   pthread_setaffinity_np(thread, sizeof(cpu_set), &cpu_set);
135 #endif
136 }
137 
SetCurrentThreadAffinity(u32 mask)138 void SetCurrentThreadAffinity(u32 mask)
139 {
140   SetThreadAffinity(pthread_self(), mask);
141 }
142 
SleepCurrentThread(int ms)143 void SleepCurrentThread(int ms)
144 {
145   usleep(1000 * ms);
146 }
147 
SwitchCurrentThread()148 void SwitchCurrentThread()
149 {
150   usleep(1000 * 1);
151 }
152 
SetCurrentThreadName(const char * name)153 void SetCurrentThreadName(const char* name)
154 {
155 #ifdef __APPLE__
156   pthread_setname_np(name);
157 #elif defined __FreeBSD__ || defined __OpenBSD__
158   pthread_set_name_np(pthread_self(), name);
159 #elif defined __HAIKU__
160   rename_thread(find_thread(nullptr), name);
161 #else
162   // linux doesn't allow to set more than 16 bytes, including \0.
163   pthread_setname_np(pthread_self(), std::string(name).substr(0, 15).c_str());
164 #endif
165 #ifdef USE_VTUNE
166   // VTune uses OS thread names by default but probably supports longer names when set via its own
167   // API.
168   __itt_thread_set_name(name);
169 #endif
170 }
171 
172 #endif
173 
174 }  // namespace Common
175