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