2 This file is a part of the JThread package, which contains some object-
3 oriented thread wrappers for different thread implementations.
5 Copyright (c) 2000-2006 Jori Liesenborgs (jori.liesenborgs@gmail.com)
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:
14 The above copyright notice and this permission notice shall be included in
15 all copies or substantial portions of the Software.
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.
26 #include "threading/thread.h"
27 #include "threading/mutex_auto_lock.h"
31 #define UNUSED(expr) do { (void)(expr); } while (0)
35 #include <system_error>
40 #elif USE_POSIX_THREADS
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>
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
70 // for bindToProcessor
71 #if __FreeBSD_version >= 702106
72 typedef cpuset_t cpu_set_t;
73 #elif defined(__linux) || defined(linux)
75 #elif defined(__sun) || defined(sun)
76 #include <sys/types.h>
77 #include <sys/processor.h>
78 #include <sys/procset.h>
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>
88 Thread::Thread(const std::string &name) :
92 m_request_stop(false),
96 m_kernel_thread_id = -1;
109 MutexAutoLock lock(m_mutex);
114 m_request_stop = false;
116 #if USE_CPP11_THREADS
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) {
126 #elif USE_WIN_THREADS
128 m_thread_handle = CreateThread(NULL, 0, threadProc, this, 0, &m_thread_id);
129 if (!m_thread_handle)
132 #elif USE_POSIX_THREADS
134 int status = pthread_create(&m_thread_handle, NULL, threadProc, this);
138 m_thread_id = m_thread_handle;
153 m_request_stop = true;
160 MutexAutoLock lock(m_mutex);
165 #if USE_CPP11_THREADS
167 m_thread_obj->join();
172 #elif USE_WIN_THREADS
174 int ret = WaitForSingleObject(m_thread_handle, INFINITE);
175 assert(ret == WAIT_OBJECT_0);
178 CloseHandle(m_thread_handle);
179 m_thread_handle = NULL;
182 #elif USE_POSIX_THREADS
184 int ret = pthread_join(m_thread_handle, NULL);
190 assert(m_running == false);
206 TerminateThread(m_thread_handle, 0);
207 CloseHandle(m_thread_handle);
209 // We need to pthread_kill instead on Android since NDKv5's pthread
210 // implementation is incomplete.
212 pthread_kill(m_thread_handle, SIGKILL);
214 pthread_cancel(m_thread_handle);
221 m_request_stop = false;
227 bool Thread::getReturnValue(void **ret)
237 bool Thread::isCurrentThread()
239 return thr_is_current_thread(m_thread_id);
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)
251 Thread *thr = (Thread *)param;
254 m_kernel_thread_id = thread_self();
257 thr->setName(thr->m_name);
259 g_logger.registerThread(thr->m_name);
260 thr->m_running = true;
262 thr->m_retval = thr->run();
264 thr->m_running = false;
265 g_logger.deregisterThread();
267 // 0 is returned here to avoid an unnecessary ifdef clause
272 void Thread::setName(const std::string &name)
274 #if defined(linux) || defined(__linux)
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());
281 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
283 pthread_set_name_np(pthread_self(), name.c_str());
285 #elif defined(__NetBSD__)
287 pthread_setname_np(pthread_self(), name.c_str());
289 #elif defined(__APPLE__)
291 pthread_setname_np(name.c_str());
293 #elif defined(_MSC_VER)
295 // Windows itself doesn't support thread names,
296 // but the MSVC debugger does...
297 THREADNAME_INFO info;
299 info.dwType = 0x1000;
300 info.szName = name.c_str();
301 info.dwThreadID = -1;
305 RaiseException(0x406D1388, 0,
306 sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
307 } __except (EXCEPTION_CONTINUE_EXECUTION) {
310 #elif defined(_WIN32) || defined(__GNU__)
312 // These platforms are known to not support thread names.
313 // Silently ignore the request.
316 #warning "Unrecognized platform, thread names will not be available."
321 unsigned int Thread::getNumberOfProcessors()
323 #if __cplusplus >= 201103L
325 return std::thread::hardware_concurrency();
327 #elif defined(_SC_NPROCESSORS_ONLN)
329 return sysconf(_SC_NPROCESSORS_ONLN);
331 #elif defined(__FreeBSD__) || defined(__NetBSD__) || \
332 defined(__DragonFly__) || defined(__APPLE__)
334 unsigned int num_cpus = 1;
335 size_t len = sizeof(num_cpus);
341 sysctl(mib, 2, &num_cpus, &len, NULL, 0);
344 #elif defined(_GNU_SOURCE)
348 #elif defined(_WIN32)
351 GetSystemInfo(&sysinfo);
352 return sysinfo.dwNumberOfProcessors;
354 #elif defined(PTW32_VERSION) || defined(__hpux)
356 return pthread_num_processors_np();
366 bool Thread::bindToProcessor(unsigned int proc_number)
368 #if defined(__ANDROID__)
372 #elif defined(_WIN32)
374 return SetThreadAffinityMask(m_thread_handle, 1 << proc_number);
376 #elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
381 CPU_SET(proc_number, &cpuset);
383 return pthread_setaffinity_np(m_thread_handle, sizeof(cpuset), &cpuset) == 0;
385 #elif defined(__sun) || defined(sun)
387 return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
391 return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
393 #elif defined(__hpux) || defined(hpux)
395 pthread_spu_t answer;
397 return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
398 &answer, proc_number, m_thread_handle) == 0;
400 #elif defined(__APPLE__)
402 struct thread_affinity_policy tapol;
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;
418 bool Thread::setPriority(int prio)
422 return SetThreadPriority(m_thread_handle, prio);
426 struct sched_param sparam;
429 if (pthread_getschedparam(m_thread_handle, &policy, &sparam) != 0)
432 int min = sched_get_priority_min(policy);
433 int max = sched_get_priority_max(policy);
435 sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
436 return pthread_setschedparam(m_thread_handle, policy, &sparam) == 0;