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