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 if (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 // Unlock m_start_finished_mutex to prevent data race condition on Windows.
200 // On Windows with VS2017 build TerminateThread is called and this mutex is not
201 // released. We try to unlock it from caller thread and it's refused by system.
202 thr->m_start_finished_mutex.unlock();
203 g_logger.deregisterThread();
207 void Thread::setName(const std::string &name)
209 #if defined(__linux__)
211 // It would be cleaner to do this with pthread_setname_np,
212 // which was added to glibc in version 2.12, but some major
213 // distributions are still runing 2.11 and previous versions.
214 prctl(PR_SET_NAME, name.c_str());
216 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
218 pthread_set_name_np(pthread_self(), name.c_str());
220 #elif defined(__NetBSD__)
222 pthread_setname_np(pthread_self(), name.c_str());
224 #elif defined(__APPLE__)
226 pthread_setname_np(name.c_str());
228 #elif defined(_MSC_VER)
230 // Windows itself doesn't support thread names,
231 // but the MSVC debugger does...
232 THREADNAME_INFO info;
234 info.dwType = 0x1000;
235 info.szName = name.c_str();
236 info.dwThreadID = -1;
240 RaiseException(0x406D1388, 0,
241 sizeof(info) / sizeof(DWORD), (ULONG_PTR *)&info);
242 } __except (EXCEPTION_CONTINUE_EXECUTION) {
245 #elif defined(_WIN32) || defined(__GNU__)
247 // These platforms are known to not support thread names.
248 // Silently ignore the request.
251 #warning "Unrecognized platform, thread names will not be available."
256 unsigned int Thread::getNumberOfProcessors()
258 return std::thread::hardware_concurrency();
262 bool Thread::bindToProcessor(unsigned int proc_number)
264 #if defined(__ANDROID__)
270 return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
274 return SetThreadAffinityMask(pthread_gethandle(getThreadHandle()), 1 << proc_number);
276 #elif __FreeBSD_version >= 702106 || defined(__linux__)
281 CPU_SET(proc_number, &cpuset);
283 return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
285 #elif defined(__sun) || defined(sun)
287 return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
291 return bindprocessor(BINDTHREAD, m_kernel_thread_id, proc_number) == 0;
293 #elif defined(__hpux) || defined(hpux)
295 pthread_spu_t answer;
297 return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
298 &answer, proc_number, getThreadHandle()) == 0;
300 #elif defined(__APPLE__)
302 struct thread_affinity_policy tapol;
304 thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
305 tapol.affinity_tag = proc_number + 1;
306 return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
307 (thread_policy_t)&tapol,
308 THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
318 bool Thread::setPriority(int prio)
322 return SetThreadPriority(getThreadHandle(), prio);
326 return SetThreadPriority(pthread_gethandle(getThreadHandle()), prio);
330 struct sched_param sparam;
333 if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
336 int min = sched_get_priority_min(policy);
337 int max = sched_get_priority_max(policy);
339 sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
340 return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;