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__)
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__)
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;
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();
114 MutexAutoLock lock(m_mutex);
119 m_request_stop = false;
121 // The mutex may already be locked if the thread is being restarted
122 m_start_finished_mutex.try_lock();
124 #if USE_CPP11_THREADS
127 m_thread_obj = new std::thread(threadProc, this);
128 } catch (const std::system_error &e) {
132 #elif USE_WIN_THREADS
134 m_thread_handle = CreateThread(NULL, 0, threadProc, this, 0, &m_thread_id);
135 if (!m_thread_handle)
138 #elif USE_POSIX_THREADS
140 int status = pthread_create(&m_thread_handle, NULL, threadProc, this);
146 // Allow spawned thread to continue
147 m_start_finished_mutex.unlock();
160 m_request_stop = true;
167 MutexAutoLock lock(m_mutex);
172 #if USE_CPP11_THREADS
174 m_thread_obj->join();
179 #elif USE_WIN_THREADS
181 int ret = WaitForSingleObject(m_thread_handle, INFINITE);
182 assert(ret == WAIT_OBJECT_0);
185 CloseHandle(m_thread_handle);
186 m_thread_handle = NULL;
189 #elif USE_POSIX_THREADS
191 int ret = pthread_join(m_thread_handle, NULL);
197 assert(m_running == false);
213 TerminateThread(m_thread_handle, 0);
214 CloseHandle(m_thread_handle);
216 // We need to pthread_kill instead on Android since NDKv5's pthread
217 // implementation is incomplete.
219 pthread_kill(getThreadHandle(), SIGKILL);
221 pthread_cancel(getThreadHandle());
228 m_request_stop = false;
234 bool Thread::getReturnValue(void **ret)
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)
252 Thread *thr = (Thread *)param;
255 thr->m_kernel_thread_id = thread_self();
258 thr->setName(thr->m_name);
260 g_logger.registerThread(thr->m_name);
261 thr->m_running = true;
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();
267 thr->m_retval = thr->run();
269 thr->m_running = false;
270 g_logger.deregisterThread();
272 // 0 is returned here to avoid an unnecessary ifdef clause
277 void Thread::setName(const std::string &name)
279 #if defined(__linux__)
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());
286 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
288 pthread_set_name_np(pthread_self(), name.c_str());
290 #elif defined(__NetBSD__)
292 pthread_setname_np(pthread_self(), name.c_str());
294 #elif defined(__APPLE__)
296 pthread_setname_np(name.c_str());
298 #elif defined(_MSC_VER)
300 // Windows itself doesn't support thread names,
301 // but the MSVC debugger does...
302 THREADNAME_INFO info;
304 info.dwType = 0x1000;
305 info.szName = name.c_str();
306 info.dwThreadID = -1;
310 RaiseException(0x406D1388, 0,
311 sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
312 } __except (EXCEPTION_CONTINUE_EXECUTION) {
315 #elif defined(_WIN32) || defined(__GNU__)
317 // These platforms are known to not support thread names.
318 // Silently ignore the request.
321 #warning "Unrecognized platform, thread names will not be available."
326 unsigned int Thread::getNumberOfProcessors()
328 #if USE_CPP11_THREADS
330 return std::thread::hardware_concurrency();
332 #elif USE_WIN_THREADS
335 GetSystemInfo(&sysinfo);
336 return sysinfo.dwNumberOfProcessors;
338 #elif defined(_SC_NPROCESSORS_ONLN)
340 return sysconf(_SC_NPROCESSORS_ONLN);
342 #elif defined(__FreeBSD__) || defined(__NetBSD__) || \
343 defined(__DragonFly__) || defined(__APPLE__)
345 unsigned int num_cpus = 1;
346 size_t len = sizeof(num_cpus);
352 sysctl(mib, 2, &num_cpus, &len, NULL, 0);
355 #elif defined(_GNU_SOURCE)
359 #elif defined(PTW32_VERSION) || defined(__hpux)
361 return pthread_num_processors_np();
371 bool Thread::bindToProcessor(unsigned int proc_number)
373 #if defined(__ANDROID__)
377 #elif USE_WIN_THREADS
379 return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
381 #elif __FreeBSD_version >= 702106 || defined(__linux__)
386 CPU_SET(proc_number, &cpuset);
388 return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
390 #elif defined(__sun) || defined(sun)
392 return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
396 return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
398 #elif defined(__hpux) || defined(hpux)
400 pthread_spu_t answer;
402 return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
403 &answer, proc_number, getThreadHandle()) == 0;
405 #elif defined(__APPLE__)
407 struct thread_affinity_policy tapol;
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;
423 bool Thread::setPriority(int prio)
427 return SetThreadPriority(getThreadHandle(), prio);
431 struct sched_param sparam;
434 if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
437 int min = sched_get_priority_min(policy);
438 int max = sched_get_priority_max(policy);
440 sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
441 return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;