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"
32 #if defined(__linux__)
33 #include <sys/prctl.h>
34 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
35 #include <pthread_np.h>
36 #elif defined(_MSC_VER)
37 struct THREADNAME_INFO {
38 DWORD dwType; // Must be 0x1000
39 LPCSTR szName; // Pointer to name (in user addr space)
40 DWORD dwThreadID; // Thread ID (-1=caller thread)
41 DWORD dwFlags; // Reserved for future use, must be zero
45 // for bindToProcessor
46 #if __FreeBSD_version >= 702106
47 typedef cpuset_t cpu_set_t;
48 #elif defined(__sun) || defined(sun)
49 #include <sys/types.h>
50 #include <sys/processor.h>
51 #include <sys/procset.h>
53 #include <sys/processor.h>
54 #include <sys/thread.h>
55 #elif defined(__APPLE__)
56 #include <mach/mach_init.h>
57 #include <mach/thread_act.h>
61 Thread::Thread(const std::string &name) :
63 m_request_stop(false),
67 m_kernel_thread_id = -1;
76 // Make sure start finished mutex is unlocked before it's destroyed
77 m_start_finished_mutex.try_lock();
78 m_start_finished_mutex.unlock();
85 MutexAutoLock lock(m_mutex);
90 m_request_stop = false;
92 // The mutex may already be locked if the thread is being restarted
93 m_start_finished_mutex.try_lock();
96 m_thread_obj = new std::thread(threadProc, this);
97 } catch (const std::system_error &e) {
101 // Allow spawned thread to continue
102 m_start_finished_mutex.unlock();
115 m_request_stop = true;
122 MutexAutoLock lock(m_mutex);
128 m_thread_obj->join();
131 m_thread_obj = nullptr;
133 assert(m_running == false);
149 // See https://msdn.microsoft.com/en-us/library/hh920601.aspx#thread__native_handle_method
150 TerminateThread((HANDLE) m_thread_obj->native_handle(), 0);
151 CloseHandle((HANDLE) m_thread_obj->native_handle());
153 // We need to pthread_kill instead on Android since NDKv5's pthread
154 // implementation is incomplete.
156 pthread_kill(getThreadHandle(), SIGKILL);
158 pthread_cancel(getThreadHandle());
165 m_request_stop = false;
171 bool Thread::getReturnValue(void **ret)
181 void Thread::threadProc(Thread *thr)
184 thr->m_kernel_thread_id = thread_self();
187 thr->setName(thr->m_name);
189 g_logger.registerThread(thr->m_name);
190 thr->m_running = true;
192 // Wait for the thread that started this one to finish initializing the
193 // thread handle so that getThreadId/getThreadHandle will work.
194 thr->m_start_finished_mutex.lock();
196 thr->m_retval = thr->run();
198 thr->m_running = false;
199 g_logger.deregisterThread();
203 void Thread::setName(const std::string &name)
205 #if defined(__linux__)
207 // It would be cleaner to do this with pthread_setname_np,
208 // which was added to glibc in version 2.12, but some major
209 // distributions are still runing 2.11 and previous versions.
210 prctl(PR_SET_NAME, name.c_str());
212 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
214 pthread_set_name_np(pthread_self(), name.c_str());
216 #elif defined(__NetBSD__)
218 pthread_setname_np(pthread_self(), name.c_str());
220 #elif defined(__APPLE__)
222 pthread_setname_np(name.c_str());
224 #elif defined(_MSC_VER)
226 // Windows itself doesn't support thread names,
227 // but the MSVC debugger does...
228 THREADNAME_INFO info;
230 info.dwType = 0x1000;
231 info.szName = name.c_str();
232 info.dwThreadID = -1;
236 RaiseException(0x406D1388, 0,
237 sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
238 } __except (EXCEPTION_CONTINUE_EXECUTION) {
241 #elif defined(_WIN32) || defined(__GNU__)
243 // These platforms are known to not support thread names.
244 // Silently ignore the request.
247 #warning "Unrecognized platform, thread names will not be available."
252 unsigned int Thread::getNumberOfProcessors()
254 return std::thread::hardware_concurrency();
258 bool Thread::bindToProcessor(unsigned int proc_number)
260 #if defined(__ANDROID__)
266 return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
270 return SetThreadAffinityMask(pthread_gethandle(getThreadHandle()), 1 << proc_number);
272 #elif __FreeBSD_version >= 702106 || defined(__linux__)
277 CPU_SET(proc_number, &cpuset);
279 return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
281 #elif defined(__sun) || defined(sun)
283 return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
287 return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
289 #elif defined(__hpux) || defined(hpux)
291 pthread_spu_t answer;
293 return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
294 &answer, proc_number, getThreadHandle()) == 0;
296 #elif defined(__APPLE__)
298 struct thread_affinity_policy tapol;
300 thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
301 tapol.affinity_tag = proc_number + 1;
302 return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
303 (thread_policy_t)&tapol,
304 THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
314 bool Thread::setPriority(int prio)
318 return SetThreadPriority(getThreadHandle(), prio);
322 return SetThreadPriority(pthread_gethandle(getThreadHandle()), prio);
326 struct sched_param sparam;
329 if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
332 int min = sched_get_priority_min(policy);
333 int max = sched_get_priority_max(policy);
335 sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
336 return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;