4f4c9474afe0f1a5ddb90330960defd63bd68979
[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__)
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__)
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_joinable(false),
92         m_request_stop(false),
93         m_running(false)
94 {
95 #ifdef _AIX
96         m_kernel_thread_id = -1;
97 #endif
98 }
99
100
101 Thread::~Thread()
102 {
103         kill();
104
105         // Make sure start finished mutex is unlocked before it's destroyed
106         m_start_finished_mutex.try_lock();
107         m_start_finished_mutex.unlock();
108
109 }
110
111
112 bool Thread::start()
113 {
114         MutexAutoLock lock(m_mutex);
115
116         if (m_running)
117                 return false;
118
119         m_request_stop = false;
120
121         // The mutex may already be locked if the thread is being restarted
122         m_start_finished_mutex.try_lock();
123
124 #if USE_CPP11_THREADS
125
126         try {
127                 m_thread_obj = new std::thread(threadProc, this);
128         } catch (const std::system_error &e) {
129                 return false;
130         }
131
132 #elif USE_WIN_THREADS
133
134         m_thread_handle = CreateThread(NULL, 0, threadProc, this, 0, &m_thread_id);
135         if (!m_thread_handle)
136                 return false;
137
138 #elif USE_POSIX_THREADS
139
140         int status = pthread_create(&m_thread_handle, NULL, threadProc, this);
141         if (status)
142                 return false;
143
144 #endif
145
146         // Allow spawned thread to continue
147         m_start_finished_mutex.unlock();
148
149         while (!m_running)
150                 sleep_ms(1);
151
152         m_joinable = true;
153
154         return true;
155 }
156
157
158 bool Thread::stop()
159 {
160         m_request_stop = true;
161         return true;
162 }
163
164
165 bool Thread::wait()
166 {
167         MutexAutoLock lock(m_mutex);
168
169         if (!m_joinable)
170                 return false;
171
172 #if USE_CPP11_THREADS
173
174         m_thread_obj->join();
175
176         delete m_thread_obj;
177         m_thread_obj = NULL;
178
179 #elif USE_WIN_THREADS
180
181         int ret = WaitForSingleObject(m_thread_handle, INFINITE);
182         assert(ret == WAIT_OBJECT_0);
183         UNUSED(ret);
184
185         CloseHandle(m_thread_handle);
186         m_thread_handle = NULL;
187         m_thread_id = -1;
188
189 #elif USE_POSIX_THREADS
190
191         int ret = pthread_join(m_thread_handle, NULL);
192         assert(ret == 0);
193         UNUSED(ret);
194
195 #endif
196
197         assert(m_running == false);
198         m_joinable = false;
199         return true;
200 }
201
202
203 bool Thread::kill()
204 {
205         if (!m_running) {
206                 wait();
207                 return false;
208         }
209
210         m_running = false;
211
212 #if USE_WIN_THREADS
213         TerminateThread(m_thread_handle, 0);
214         CloseHandle(m_thread_handle);
215 #else
216         // We need to pthread_kill instead on Android since NDKv5's pthread
217         // implementation is incomplete.
218 # ifdef __ANDROID__
219         pthread_kill(getThreadHandle(), SIGKILL);
220 # else
221         pthread_cancel(getThreadHandle());
222 # endif
223         wait();
224 #endif
225
226         m_retval       = NULL;
227         m_joinable     = false;
228         m_request_stop = false;
229
230         return true;
231 }
232
233
234 bool Thread::getReturnValue(void **ret)
235 {
236         if (m_running)
237                 return false;
238
239         *ret = m_retval;
240         return true;
241 }
242
243
244 #if USE_CPP11_THREADS || USE_POSIX_THREADS
245 void *Thread::threadProc(void *param)
246 #elif defined(_WIN32_WCE)
247 DWORD Thread::threadProc(LPVOID param)
248 #elif defined(_WIN32)
249 DWORD WINAPI Thread::threadProc(LPVOID param)
250 #endif
251 {
252         Thread *thr = (Thread *)param;
253
254 #ifdef _AIX
255         m_kernel_thread_id = thread_self();
256 #endif
257
258         thr->setName(thr->m_name);
259
260         g_logger.registerThread(thr->m_name);
261         thr->m_running = true;
262
263         // Wait for the thread that started this one to finish initializing the
264         // thread handle so that getThreadId/getThreadHandle will work.
265         thr->m_start_finished_mutex.lock();
266
267         thr->m_retval = thr->run();
268
269         thr->m_running = false;
270         g_logger.deregisterThread();
271
272         // 0 is returned here to avoid an unnecessary ifdef clause
273         return 0;
274 }
275
276
277 void Thread::setName(const std::string &name)
278 {
279 #if defined(__linux__)
280
281         // It would be cleaner to do this with pthread_setname_np,
282         // which was added to glibc in version 2.12, but some major
283         // distributions are still runing 2.11 and previous versions.
284         prctl(PR_SET_NAME, name.c_str());
285
286 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
287
288         pthread_set_name_np(pthread_self(), name.c_str());
289
290 #elif defined(__NetBSD__)
291
292         pthread_setname_np(pthread_self(), name.c_str());
293
294 #elif defined(__APPLE__)
295
296         pthread_setname_np(name.c_str());
297
298 #elif defined(_MSC_VER)
299
300         // Windows itself doesn't support thread names,
301         // but the MSVC debugger does...
302         THREADNAME_INFO info;
303
304         info.dwType = 0x1000;
305         info.szName = name.c_str();
306         info.dwThreadID = -1;
307         info.dwFlags = 0;
308
309         __try {
310                 RaiseException(0x406D1388, 0,
311                         sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
312         } __except (EXCEPTION_CONTINUE_EXECUTION) {
313         }
314
315 #elif defined(_WIN32) || defined(__GNU__)
316
317         // These platforms are known to not support thread names.
318         // Silently ignore the request.
319
320 #else
321         #warning "Unrecognized platform, thread names will not be available."
322 #endif
323 }
324
325
326 unsigned int Thread::getNumberOfProcessors()
327 {
328 #if USE_CPP11_THREADS
329
330         return std::thread::hardware_concurrency();
331
332 #elif USE_WIN_THREADS
333
334         SYSTEM_INFO sysinfo;
335         GetSystemInfo(&sysinfo);
336         return sysinfo.dwNumberOfProcessors;
337
338 #elif defined(_SC_NPROCESSORS_ONLN)
339
340         return sysconf(_SC_NPROCESSORS_ONLN);
341
342 #elif defined(__FreeBSD__) || defined(__NetBSD__) || \
343         defined(__DragonFly__) || defined(__APPLE__)
344
345         unsigned int num_cpus = 1;
346         size_t len = sizeof(num_cpus);
347
348         int mib[2];
349         mib[0] = CTL_HW;
350         mib[1] = HW_NCPU;
351
352         sysctl(mib, 2, &num_cpus, &len, NULL, 0);
353         return num_cpus;
354
355 #elif defined(_GNU_SOURCE)
356
357         return get_nprocs();
358
359 #elif defined(PTW32_VERSION) || defined(__hpux)
360
361         return pthread_num_processors_np();
362
363 #else
364
365         return 1;
366
367 #endif
368 }
369
370
371 bool Thread::bindToProcessor(unsigned int proc_number)
372 {
373 #if defined(__ANDROID__)
374
375         return false;
376
377 #elif USE_WIN_THREADS
378
379         return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
380
381 #elif __FreeBSD_version >= 702106 || defined(__linux__)
382
383         cpu_set_t cpuset;
384
385         CPU_ZERO(&cpuset);
386         CPU_SET(proc_number, &cpuset);
387
388         return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
389
390 #elif defined(__sun) || defined(sun)
391
392         return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
393
394 #elif defined(_AIX)
395
396         return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
397
398 #elif defined(__hpux) || defined(hpux)
399
400         pthread_spu_t answer;
401
402         return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
403                         &answer, proc_number, getThreadHandle()) == 0;
404
405 #elif defined(__APPLE__)
406
407         struct thread_affinity_policy tapol;
408
409         thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
410         tapol.affinity_tag = proc_number + 1;
411         return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
412                         (thread_policy_t)&tapol,
413                         THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
414
415 #else
416
417         return false;
418
419 #endif
420 }
421
422
423 bool Thread::setPriority(int prio)
424 {
425 #if USE_WIN_THREADS
426
427         return SetThreadPriority(getThreadHandle(), prio);
428
429 #else
430
431         struct sched_param sparam;
432         int policy;
433
434         if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
435                 return false;
436
437         int min = sched_get_priority_min(policy);
438         int max = sched_get_priority_max(policy);
439
440         sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
441         return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;
442
443 #endif
444 }
445