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) :
65 m_request_stop(false),
69 m_kernel_thread_id = -1;
78 // Make sure start finished mutex is unlocked before it's destroyed
79 m_start_finished_mutex.try_lock();
80 m_start_finished_mutex.unlock();
87 MutexAutoLock lock(m_mutex);
92 m_request_stop = false;
94 // The mutex may already be locked if the thread is being restarted
95 m_start_finished_mutex.try_lock();
98 m_thread_obj = new std::thread(threadProc, this);
99 } catch (const std::system_error &e) {
103 // Allow spawned thread to continue
104 m_start_finished_mutex.unlock();
117 m_request_stop = true;
124 MutexAutoLock lock(m_mutex);
130 m_thread_obj->join();
135 assert(m_running == false);
151 // See https://msdn.microsoft.com/en-us/library/hh920601.aspx#thread__native_handle_method
152 TerminateThread((HANDLE) m_thread_obj->native_handle(), 0);
153 CloseHandle((HANDLE) m_thread_obj->native_handle());
155 // We need to pthread_kill instead on Android since NDKv5's pthread
156 // implementation is incomplete.
158 pthread_kill(getThreadHandle(), SIGKILL);
160 pthread_cancel(getThreadHandle());
167 m_request_stop = false;
173 bool Thread::getReturnValue(void **ret)
183 void *Thread::threadProc(void *param)
185 Thread *thr = (Thread *)param;
188 thr->m_kernel_thread_id = thread_self();
191 thr->setName(thr->m_name);
193 g_logger.registerThread(thr->m_name);
194 thr->m_running = true;
196 // Wait for the thread that started this one to finish initializing the
197 // thread handle so that getThreadId/getThreadHandle will work.
198 thr->m_start_finished_mutex.lock();
200 thr->m_retval = thr->run();
202 thr->m_running = false;
203 g_logger.deregisterThread();
205 // 0 is returned here to avoid an unnecessary ifdef clause
210 void Thread::setName(const std::string &name)
212 #if defined(__linux__)
214 // It would be cleaner to do this with pthread_setname_np,
215 // which was added to glibc in version 2.12, but some major
216 // distributions are still runing 2.11 and previous versions.
217 prctl(PR_SET_NAME, name.c_str());
219 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
221 pthread_set_name_np(pthread_self(), name.c_str());
223 #elif defined(__NetBSD__)
225 pthread_setname_np(pthread_self(), name.c_str());
227 #elif defined(__APPLE__)
229 pthread_setname_np(name.c_str());
231 #elif defined(_MSC_VER)
233 // Windows itself doesn't support thread names,
234 // but the MSVC debugger does...
235 THREADNAME_INFO info;
237 info.dwType = 0x1000;
238 info.szName = name.c_str();
239 info.dwThreadID = -1;
243 RaiseException(0x406D1388, 0,
244 sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
245 } __except (EXCEPTION_CONTINUE_EXECUTION) {
248 #elif defined(_WIN32) || defined(__GNU__)
250 // These platforms are known to not support thread names.
251 // Silently ignore the request.
254 #warning "Unrecognized platform, thread names will not be available."
259 unsigned int Thread::getNumberOfProcessors()
261 return std::thread::hardware_concurrency();
265 bool Thread::bindToProcessor(unsigned int proc_number)
267 #if defined(__ANDROID__)
271 #elif USE_WIN_THREADS
273 return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
275 #elif __FreeBSD_version >= 702106 || defined(__linux__)
280 CPU_SET(proc_number, &cpuset);
282 return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
284 #elif defined(__sun) || defined(sun)
286 return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
290 return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
292 #elif defined(__hpux) || defined(hpux)
294 pthread_spu_t answer;
296 return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
297 &answer, proc_number, getThreadHandle()) == 0;
299 #elif defined(__APPLE__)
301 struct thread_affinity_policy tapol;
303 thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
304 tapol.affinity_tag = proc_number + 1;
305 return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
306 (thread_policy_t)&tapol,
307 THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
317 bool Thread::setPriority(int prio)
321 return SetThreadPriority(getThreadHandle(), prio);
325 struct sched_param sparam;
328 if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
331 int min = sched_get_priority_min(policy);
332 int max = sched_get_priority_max(policy);
334 sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
335 return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;