]> git.lizzy.rs Git - dragonfireclient.git/blob - src/threading/thread.cpp
Fix msvc annoyances (#5963)
[dragonfireclient.git] / src / threading / thread.cpp
1 /*
2 This file is a part of the JThread package, which contains some object-
3 oriented thread wrappers for different thread implementations.
4
5 Copyright (c) 2000-2006  Jori Liesenborgs (jori.liesenborgs@gmail.com)
6
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 and/or sell copies of the Software, and to permit persons to whom the
12 Software is furnished to do so, subject to the following conditions:
13
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
16
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 DEALINGS IN THE SOFTWARE.
24 */
25
26 #include "threading/thread.h"
27 #include "threading/mutex_auto_lock.h"
28 #include "log.h"
29 #include "porting.h"
30
31 // for setName
32 #if defined(__linux__)
33         #include <sys/prctl.h>
34 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
35         #include <pthread_np.h>
36 #elif defined(_MSC_VER)
37         struct THREADNAME_INFO {
38                 DWORD dwType;     // Must be 0x1000
39                 LPCSTR szName;    // Pointer to name (in user addr space)
40                 DWORD dwThreadID; // Thread ID (-1=caller thread)
41                 DWORD dwFlags;    // Reserved for future use, must be zero
42         };
43 #endif
44
45 // for bindToProcessor
46 #if __FreeBSD_version >= 702106
47         typedef cpuset_t cpu_set_t;
48 #elif defined(__sun) || defined(sun)
49         #include <sys/types.h>
50         #include <sys/processor.h>
51         #include <sys/procset.h>
52 #elif defined(_AIX)
53         #include <sys/processor.h>
54         #include <sys/thread.h>
55 #elif defined(__APPLE__)
56         #include <mach/mach_init.h>
57         #include <mach/thread_act.h>
58 #endif
59
60
61 Thread::Thread(const std::string &name) :
62         m_name(name),
63         m_request_stop(false),
64         m_running(false)
65 {
66 #ifdef _AIX
67         m_kernel_thread_id = -1;
68 #endif
69 }
70
71
72 Thread::~Thread()
73 {
74         kill();
75
76         // Make sure start finished mutex is unlocked before it's destroyed
77         m_start_finished_mutex.try_lock();
78         m_start_finished_mutex.unlock();
79
80 }
81
82
83 bool Thread::start()
84 {
85         MutexAutoLock lock(m_mutex);
86
87         if (m_running)
88                 return false;
89
90         m_request_stop = false;
91
92         // The mutex may already be locked if the thread is being restarted
93         m_start_finished_mutex.try_lock();
94
95         try {
96                 m_thread_obj = new std::thread(threadProc, this);
97         } catch (const std::system_error &e) {
98                 return false;
99         }
100
101         // Allow spawned thread to continue
102         m_start_finished_mutex.unlock();
103
104         while (!m_running)
105                 sleep_ms(1);
106
107         m_joinable = true;
108
109         return true;
110 }
111
112
113 bool Thread::stop()
114 {
115         m_request_stop = true;
116         return true;
117 }
118
119
120 bool Thread::wait()
121 {
122         MutexAutoLock lock(m_mutex);
123
124         if (!m_joinable)
125                 return false;
126
127
128         m_thread_obj->join();
129
130         delete m_thread_obj;
131         m_thread_obj = nullptr;
132
133         assert(m_running == false);
134         m_joinable = false;
135         return true;
136 }
137
138
139 bool Thread::kill()
140 {
141         if (!m_running) {
142                 wait();
143                 return false;
144         }
145
146         m_running = false;
147
148 #if defined(_WIN32)
149         // See https://msdn.microsoft.com/en-us/library/hh920601.aspx#thread__native_handle_method
150         TerminateThread((HANDLE) m_thread_obj->native_handle(), 0);
151         CloseHandle((HANDLE) m_thread_obj->native_handle());
152 #else
153         // We need to pthread_kill instead on Android since NDKv5's pthread
154         // implementation is incomplete.
155 # ifdef __ANDROID__
156         pthread_kill(getThreadHandle(), SIGKILL);
157 # else
158         pthread_cancel(getThreadHandle());
159 # endif
160         wait();
161 #endif
162
163         m_retval       = nullptr;
164         m_joinable     = false;
165         m_request_stop = false;
166
167         return true;
168 }
169
170
171 bool Thread::getReturnValue(void **ret)
172 {
173         if (m_running)
174                 return false;
175
176         *ret = m_retval;
177         return true;
178 }
179
180
181 void Thread::threadProc(Thread *thr)
182 {
183 #ifdef _AIX
184         thr->m_kernel_thread_id = thread_self();
185 #endif
186
187         thr->setName(thr->m_name);
188
189         g_logger.registerThread(thr->m_name);
190         thr->m_running = true;
191
192         // Wait for the thread that started this one to finish initializing the
193         // thread handle so that getThreadId/getThreadHandle will work.
194         thr->m_start_finished_mutex.lock();
195
196         thr->m_retval = thr->run();
197
198         thr->m_running = false;
199         g_logger.deregisterThread();
200 }
201
202
203 void Thread::setName(const std::string &name)
204 {
205 #if defined(__linux__)
206
207         // It would be cleaner to do this with pthread_setname_np,
208         // which was added to glibc in version 2.12, but some major
209         // distributions are still runing 2.11 and previous versions.
210         prctl(PR_SET_NAME, name.c_str());
211
212 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
213
214         pthread_set_name_np(pthread_self(), name.c_str());
215
216 #elif defined(__NetBSD__)
217
218         pthread_setname_np(pthread_self(), name.c_str());
219
220 #elif defined(__APPLE__)
221
222         pthread_setname_np(name.c_str());
223
224 #elif defined(_MSC_VER)
225
226         // Windows itself doesn't support thread names,
227         // but the MSVC debugger does...
228         THREADNAME_INFO info;
229
230         info.dwType = 0x1000;
231         info.szName = name.c_str();
232         info.dwThreadID = -1;
233         info.dwFlags = 0;
234
235         __try {
236                 RaiseException(0x406D1388, 0,
237                         sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
238         } __except (EXCEPTION_CONTINUE_EXECUTION) {
239         }
240
241 #elif defined(_WIN32) || defined(__GNU__)
242
243         // These platforms are known to not support thread names.
244         // Silently ignore the request.
245
246 #else
247         #warning "Unrecognized platform, thread names will not be available."
248 #endif
249 }
250
251
252 unsigned int Thread::getNumberOfProcessors()
253 {
254         return std::thread::hardware_concurrency();
255 }
256
257
258 bool Thread::bindToProcessor(unsigned int proc_number)
259 {
260 #if defined(__ANDROID__)
261
262         return false;
263
264 #elif _MSC_VER
265
266         return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
267
268 #elif __MINGW32__
269
270         return SetThreadAffinityMask(pthread_gethandle(getThreadHandle()), 1 << proc_number);
271
272 #elif __FreeBSD_version >= 702106 || defined(__linux__)
273
274         cpu_set_t cpuset;
275
276         CPU_ZERO(&cpuset);
277         CPU_SET(proc_number, &cpuset);
278
279         return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
280
281 #elif defined(__sun) || defined(sun)
282
283         return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
284
285 #elif defined(_AIX)
286
287         return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
288
289 #elif defined(__hpux) || defined(hpux)
290
291         pthread_spu_t answer;
292
293         return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
294                         &answer, proc_number, getThreadHandle()) == 0;
295
296 #elif defined(__APPLE__)
297
298         struct thread_affinity_policy tapol;
299
300         thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
301         tapol.affinity_tag = proc_number + 1;
302         return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
303                         (thread_policy_t)&tapol,
304                         THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
305
306 #else
307
308         return false;
309
310 #endif
311 }
312
313
314 bool Thread::setPriority(int prio)
315 {
316 #ifdef _MSC_VER
317
318         return SetThreadPriority(getThreadHandle(), prio);
319
320 #elif __MINGW32__
321
322         return SetThreadPriority(pthread_gethandle(getThreadHandle()), prio);
323
324 #else
325
326         struct sched_param sparam;
327         int policy;
328
329         if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
330                 return false;
331
332         int min = sched_get_priority_min(policy);
333         int max = sched_get_priority_max(policy);
334
335         sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
336         return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;
337
338 #endif
339 }
340