Fix == to =
[oweals/minetest.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 #define UNUSED(expr) do { (void)(expr); } while (0)
32
33 #if USE_CPP11_THREADS
34         #include <chrono>
35         #include <system_error>
36 #elif USE_WIN_THREADS
37         #ifndef _WIN32_WCE
38                 #include <process.h>
39         #endif
40 #elif USE_POSIX_THREADS
41         #include <time.h>
42         #include <assert.h>
43         #include <stdlib.h>
44         #include <unistd.h>
45         #include <sys/time.h>
46
47         #if defined(__FreeBSD__) || defined(__APPLE__)
48                 #include <sys/types.h>
49                 #include <sys/sysctl.h>
50         #elif defined(_GNU_SOURCE)
51                 #include <sys/sysinfo.h>
52         #endif
53 #endif
54
55
56 // for setName
57 #if defined(linux) || defined(__linux)
58         #include <sys/prctl.h>
59 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
60         #include <pthread_np.h>
61 #elif defined(_MSC_VER)
62         struct THREADNAME_INFO {
63                 DWORD dwType;     // Must be 0x1000
64                 LPCSTR szName;    // Pointer to name (in user addr space)
65                 DWORD dwThreadID; // Thread ID (-1=caller thread)
66                 DWORD dwFlags;    // Reserved for future use, must be zero
67         };
68 #endif
69
70 // for bindToProcessor
71 #if __FreeBSD_version >= 702106
72         typedef cpuset_t cpu_set_t;
73 #elif defined(__linux) || defined(linux)
74         #include <sched.h>
75 #elif defined(__sun) || defined(sun)
76         #include <sys/types.h>
77         #include <sys/processor.h>
78         #include <sys/procset.h>
79 #elif defined(_AIX)
80         #include <sys/processor.h>
81         #include <sys/thread.h>
82 #elif defined(__APPLE__)
83         #include <mach/mach_init.h>
84         #include <mach/thread_act.h>
85 #endif
86
87
88 Thread::Thread(const std::string &name) :
89         m_name(name),
90         m_retval(NULL),
91         m_request_stop(false),
92         m_running(false)
93 {
94 #ifdef _AIX
95         m_kernel_thread_id = -1;
96 #endif
97
98 #if USE_CPP11_THREADS
99         m_thread_obj = NULL;
100 #endif
101 }
102
103
104 Thread::~Thread()
105 {
106         kill();
107 }
108
109
110 bool Thread::start()
111 {
112         MutexAutoLock lock(m_continue_mutex);
113
114         if (m_running)
115                 return false;
116
117         cleanup();
118
119 #if USE_CPP11_THREADS
120
121         try {
122                 m_thread_obj    = new std::thread(threadProc, this);
123                 m_thread_id     = m_thread->get_id();
124                 m_thread_handle = m_thread->native_handle();
125         } except (const std::system_error &e) {
126                 return false;
127         }
128
129 #elif USE_WIN_THREADS
130
131         m_thread_handle = CreateThread(NULL, 0, threadProc, this, 0, &m_thread_id);
132         if (!m_thread_handle)
133                 return false;
134
135 #elif USE_POSIX_THREADS
136
137         int status = pthread_create(&m_thread_handle, NULL, threadProc, this);
138         if (status)
139                 return false;
140
141         m_thread_id = m_thread_handle;
142
143 #endif
144
145         while (!m_running)
146                 sleep_ms(1);
147
148         return true;
149 }
150
151
152 bool Thread::stop()
153 {
154         m_request_stop = true;
155         return true;
156 }
157
158
159 void Thread::wait()
160 {
161         if (!m_running)
162                 return;
163
164 #if USE_CPP11_THREADS
165
166         m_thread_obj->join();
167
168 #elif USE_WIN_THREADS
169
170         int ret = WaitForSingleObject(m_thread_handle, INFINITE);
171         assert(ret == WAIT_OBJECT_0);
172         UNUSED(ret);
173
174 #elif USE_POSIX_THREADS
175
176         int ret = pthread_join(m_thread_handle, NULL);
177         assert(ret == 0);
178         UNUSED(ret);
179
180 #endif
181
182         assert(m_running == false);
183
184         return;
185 }
186
187
188 bool Thread::kill()
189 {
190         if (!m_running) {
191                 wait();
192                 return false;
193         }
194
195 #ifdef _WIN32
196         TerminateThread(m_thread_handle, 0);
197 #else
198
199         // We need to pthread_kill instead on Android since NDKv5's pthread
200         // implementation is incomplete.
201 # ifdef __ANDROID__
202         pthread_kill(m_thread_handle, SIGKILL);
203 # else
204         pthread_cancel(m_thread_handle);
205 # endif
206
207         wait();
208 #endif
209
210         cleanup();
211
212         return true;
213 }
214
215
216 void Thread::cleanup()
217 {
218 #if USE_CPP11_THREADS
219
220         delete m_thread_obj;
221         m_thread_obj = NULL;
222
223 #elif USE_WIN_THREADS
224
225         CloseHandle(m_thread_handle);
226         m_thread_handle = NULL;
227         m_thread_id = -1;
228
229 #elif USE_POSIX_THREADS
230
231         // Can't do any cleanup for pthreads
232
233 #endif
234
235         m_name         = "";
236         m_retval       = NULL;
237         m_running      = false;
238         m_request_stop = false;
239 }
240
241
242 bool Thread::getReturnValue(void **ret)
243 {
244         if (m_running)
245                 return false;
246
247         *ret = m_retval;
248         return true;
249 }
250
251
252 bool Thread::isCurrentThread()
253 {
254         return thr_is_current_thread(m_thread_id);
255 }
256
257
258 #if USE_CPP11_THREADS || USE_POSIX_THREADS
259         void *(Thread::threadProc)(void *param)
260 #elif defined(_WIN32_WCE)
261         DWORD (Thread::threadProc)(LPVOID param)
262 #elif defined(_WIN32)
263         DWORD WINAPI (Thread::threadProc)(LPVOID param)
264 #endif
265 {
266         Thread *thr = (Thread *)param;
267
268 #ifdef _AIX
269         m_kernel_thread_id = thread_self();
270 #endif
271
272         thr->setName(thr->m_name);
273
274         g_logger.registerThread(thr->m_name);
275         thr->m_running = true;
276
277         thr->m_retval = thr->run();
278
279         thr->m_running = false;
280         g_logger.deregisterThread();
281
282         return NULL;
283 }
284
285
286 void Thread::setName(const std::string &name)
287 {
288 #if defined(linux) || defined(__linux)
289
290         // It would be cleaner to do this with pthread_setname_np,
291         // which was added to glibc in version 2.12, but some major
292         // distributions are still runing 2.11 and previous versions.
293         prctl(PR_SET_NAME, name.c_str());
294
295 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
296
297         pthread_set_name_np(pthread_self(), name.c_str());
298
299 #elif defined(__NetBSD__)
300
301         pthread_setname_np(pthread_self(), name.c_str());
302
303 #elif defined(__APPLE__)
304
305         pthread_setname_np(name.c_str());
306
307 #elif defined(_MSC_VER)
308
309         // Windows itself doesn't support thread names,
310         // but the MSVC debugger does...
311         THREADNAME_INFO info;
312
313         info.dwType = 0x1000;
314         info.szName = name.c_str();
315         info.dwThreadID = -1;
316         info.dwFlags = 0;
317
318         __try {
319                 RaiseException(0x406D1388, 0,
320                         sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
321         } __except (EXCEPTION_CONTINUE_EXECUTION) {
322         }
323
324 #elif defined(_WIN32) || defined(__GNU__)
325
326         // These platforms are known to not support thread names.
327         // Silently ignore the request.
328
329 #else
330         #warning "Unrecognized platform, thread names will not be available."
331 #endif
332 }
333
334
335 unsigned int Thread::getNumberOfProcessors()
336 {
337 #if __cplusplus >= 201103L
338
339         return std::thread::hardware_concurrency();
340
341 #elif defined(_SC_NPROCESSORS_ONLN)
342
343         return sysconf(_SC_NPROCESSORS_ONLN);
344
345 #elif defined(__FreeBSD__) || defined(__NetBSD__) || \
346         defined(__DragonFly__) || defined(__APPLE__)
347
348         unsigned int num_cpus = 1;
349         size_t len = sizeof(num_cpus);
350
351         int mib[2];
352         mib[0] = CTL_HW;
353         mib[1] = HW_NCPU;
354
355         sysctl(mib, 2, &num_cpus, &len, NULL, 0);
356         return num_cpus;
357
358 #elif defined(_GNU_SOURCE)
359
360         return get_nprocs();
361
362 #elif defined(_WIN32)
363
364         SYSTEM_INFO sysinfo;
365         GetSystemInfo(&sysinfo);
366         return sysinfo.dwNumberOfProcessors;
367
368 #elif defined(PTW32_VERSION) || defined(__hpux)
369
370         return pthread_num_processors_np();
371
372 #else
373
374         return 1;
375
376 #endif
377 }
378
379
380 bool Thread::bindToProcessor(unsigned int proc_number)
381 {
382 #if defined(__ANDROID__)
383
384         return false;
385
386 #elif defined(_WIN32)
387
388         return SetThreadAffinityMask(m_thread_handle, 1 << proc_number);
389
390 #elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
391
392         cpu_set_t cpuset;
393
394         CPU_ZERO(&cpuset);
395         CPU_SET(proc_number, &cpuset);
396
397         return pthread_setaffinity_np(m_thread_handle, sizeof(cpuset), &cpuset) == 0;
398
399 #elif defined(__sun) || defined(sun)
400
401         return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
402
403 #elif defined(_AIX)
404
405         return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
406
407 #elif defined(__hpux) || defined(hpux)
408
409         pthread_spu_t answer;
410
411         return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
412                         &answer, proc_number, m_thread_handle) == 0;
413
414 #elif defined(__APPLE__)
415
416         struct thread_affinity_policy tapol;
417
418         thread_port_t threadport = pthread_mach_thread_np(m_thread_handle);
419         tapol.affinity_tag = proc_number + 1;
420         return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
421                         (thread_policy_t)&tapol,
422                         THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
423
424 #else
425
426         return false;
427
428 #endif
429 }
430
431
432 bool Thread::setPriority(int prio)
433 {
434 #if defined(_WIN32)
435
436         return SetThreadPriority(m_thread_handle, prio);
437
438 #else
439
440         struct sched_param sparam;
441         int policy;
442
443         if (pthread_getschedparam(m_thread_handle, &policy, &sparam) != 0)
444                 return false;
445
446         int min = sched_get_priority_min(policy);
447         int max = sched_get_priority_max(policy);
448
449         sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
450         return pthread_setschedparam(m_thread_handle, policy, &sparam) == 0;
451
452 #endif
453 }
454