#include "log.h"
#include "porting.h"
-#define UNUSED(expr) do { (void)(expr); } while (0)
-
-#if USE_CPP11_THREADS
- #include <chrono>
- #include <system_error>
-#elif USE_WIN_THREADS
- #ifndef _WIN32_WCE
- #include <process.h>
- #endif
-#elif USE_POSIX_THREADS
- #include <time.h>
- #include <assert.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <sys/time.h>
-
- #if defined(__FreeBSD__) || defined(__APPLE__)
- #include <sys/types.h>
- #include <sys/sysctl.h>
- #elif defined(_GNU_SOURCE)
- #include <sys/sysinfo.h>
- #endif
-#endif
-
-
// for setName
-#if defined(linux) || defined(__linux)
+#if defined(__linux__)
#include <sys/prctl.h>
-#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
#include <pthread_np.h>
+#elif defined(__NetBSD__)
+ #include <sched.h>
#elif defined(_MSC_VER)
struct THREADNAME_INFO {
DWORD dwType; // Must be 0x1000
// for bindToProcessor
#if __FreeBSD_version >= 702106
typedef cpuset_t cpu_set_t;
-#elif defined(__linux) || defined(linux)
- #include <sched.h>
#elif defined(__sun) || defined(sun)
#include <sys/types.h>
#include <sys/processor.h>
Thread::Thread(const std::string &name) :
m_name(name),
- m_retval(NULL),
- m_joinable(false),
m_request_stop(false),
m_running(false)
{
Thread::~Thread()
{
- kill();
+ // kill the thread if running
+ if (!m_running) {
+ wait();
+ } else {
+
+ m_running = false;
+
+#if defined(_WIN32)
+ // See https://msdn.microsoft.com/en-us/library/hh920601.aspx#thread__native_handle_method
+ TerminateThread((HANDLE) m_thread_obj->native_handle(), 0);
+ CloseHandle((HANDLE) m_thread_obj->native_handle());
+#else
+ // We need to pthread_kill instead on Android since NDKv5's pthread
+ // implementation is incomplete.
+# ifdef __ANDROID__
+ pthread_kill(getThreadHandle(), SIGKILL);
+# else
+ pthread_cancel(getThreadHandle());
+# endif
+ wait();
+#endif
+ }
+
+ // Make sure start finished mutex is unlocked before it's destroyed
+ if (m_start_finished_mutex.try_lock())
+ m_start_finished_mutex.unlock();
+
}
m_request_stop = false;
-#if USE_CPP11_THREADS
+ // The mutex may already be locked if the thread is being restarted
+ m_start_finished_mutex.try_lock();
try {
m_thread_obj = new std::thread(threadProc, this);
return false;
}
-#elif USE_WIN_THREADS
-
- m_thread_handle = CreateThread(NULL, 0, threadProc, this, 0, &m_thread_id);
- if (!m_thread_handle)
- return false;
-
-#elif USE_POSIX_THREADS
-
- int status = pthread_create(&m_thread_handle, NULL, threadProc, this);
- if (status)
- return false;
-
-#endif
-
while (!m_running)
sleep_ms(1);
+ // Allow spawned thread to continue
+ m_start_finished_mutex.unlock();
+
m_joinable = true;
return true;
if (!m_joinable)
return false;
-#if USE_CPP11_THREADS
m_thread_obj->join();
delete m_thread_obj;
- m_thread_obj = NULL;
-
-#elif USE_WIN_THREADS
-
- int ret = WaitForSingleObject(m_thread_handle, INFINITE);
- assert(ret == WAIT_OBJECT_0);
- UNUSED(ret);
-
- CloseHandle(m_thread_handle);
- m_thread_handle = NULL;
- m_thread_id = -1;
-
-#elif USE_POSIX_THREADS
-
- int ret = pthread_join(m_thread_handle, NULL);
- assert(ret == 0);
- UNUSED(ret);
-
-#endif
+ m_thread_obj = nullptr;
assert(m_running == false);
m_joinable = false;
}
-bool Thread::kill()
-{
- if (!m_running) {
- wait();
- return false;
- }
-
- m_running = false;
-
-#ifdef _WIN32
- TerminateThread(m_thread_handle, 0);
- CloseHandle(m_thread_handle);
-#else
- // We need to pthread_kill instead on Android since NDKv5's pthread
- // implementation is incomplete.
-# ifdef __ANDROID__
- pthread_kill(m_thread_handle, SIGKILL);
-# else
- pthread_cancel(m_thread_handle);
-# endif
- wait();
-#endif
-
- m_retval = NULL;
- m_joinable = false;
- m_request_stop = false;
-
- return true;
-}
-
bool Thread::getReturnValue(void **ret)
{
}
-#if USE_CPP11_THREADS || USE_POSIX_THREADS
-void *Thread::threadProc(void *param)
-#elif defined(_WIN32_WCE)
-DWORD Thread::threadProc(LPVOID param)
-#elif defined(_WIN32)
-DWORD WINAPI Thread::threadProc(LPVOID param)
-#endif
+void Thread::threadProc(Thread *thr)
{
- Thread *thr = (Thread *)param;
-
#ifdef _AIX
- m_kernel_thread_id = thread_self();
+ thr->m_kernel_thread_id = thread_self();
#endif
thr->setName(thr->m_name);
g_logger.registerThread(thr->m_name);
thr->m_running = true;
+ // Wait for the thread that started this one to finish initializing the
+ // thread handle so that getThreadId/getThreadHandle will work.
+ thr->m_start_finished_mutex.lock();
+
thr->m_retval = thr->run();
thr->m_running = false;
+ // Unlock m_start_finished_mutex to prevent data race condition on Windows.
+ // On Windows with VS2017 build TerminateThread is called and this mutex is not
+ // released. We try to unlock it from caller thread and it's refused by system.
+ thr->m_start_finished_mutex.unlock();
g_logger.deregisterThread();
-
- // 0 is returned here to avoid an unnecessary ifdef clause
- return 0;
}
void Thread::setName(const std::string &name)
{
-#if defined(linux) || defined(__linux)
+#if defined(__linux__)
// It would be cleaner to do this with pthread_setname_np,
// which was added to glibc in version 2.12, but some major
// distributions are still runing 2.11 and previous versions.
prctl(PR_SET_NAME, name.c_str());
-#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
pthread_set_name_np(pthread_self(), name.c_str());
#elif defined(__NetBSD__)
- pthread_setname_np(pthread_self(), name.c_str());
+ pthread_setname_np(pthread_self(), "%s", const_cast<char*>(name.c_str()));
#elif defined(__APPLE__)
pthread_setname_np(name.c_str());
+#elif defined(__HAIKU__)
+
+ rename_thread(find_thread(NULL), name.c_str());
+
#elif defined(_MSC_VER)
// Windows itself doesn't support thread names,
unsigned int Thread::getNumberOfProcessors()
{
-#if __cplusplus >= 201103L
-
return std::thread::hardware_concurrency();
-
-#elif defined(_SC_NPROCESSORS_ONLN)
-
- return sysconf(_SC_NPROCESSORS_ONLN);
-
-#elif defined(__FreeBSD__) || defined(__NetBSD__) || \
- defined(__DragonFly__) || defined(__APPLE__)
-
- unsigned int num_cpus = 1;
- size_t len = sizeof(num_cpus);
-
- int mib[2];
- mib[0] = CTL_HW;
- mib[1] = HW_NCPU;
-
- sysctl(mib, 2, &num_cpus, &len, NULL, 0);
- return num_cpus;
-
-#elif defined(_GNU_SOURCE)
-
- return get_nprocs();
-
-#elif defined(_WIN32)
-
- SYSTEM_INFO sysinfo;
- GetSystemInfo(&sysinfo);
- return sysinfo.dwNumberOfProcessors;
-
-#elif defined(PTW32_VERSION) || defined(__hpux)
-
- return pthread_num_processors_np();
-
-#else
-
- return 1;
-
-#endif
}
return false;
-#elif defined(_WIN32)
+#elif _MSC_VER
+
+ return SetThreadAffinityMask(getThreadHandle(), 1 << proc_number);
+
+#elif __MINGW32__
- return SetThreadAffinityMask(m_thread_handle, 1 << proc_number);
+ return SetThreadAffinityMask(pthread_gethandle(getThreadHandle()), 1 << proc_number);
-#elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
+#elif __FreeBSD_version >= 702106 || defined(__linux__) || defined(__DragonFly__)
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(proc_number, &cpuset);
- return pthread_setaffinity_np(m_thread_handle, sizeof(cpuset), &cpuset) == 0;
+ return pthread_setaffinity_np(getThreadHandle(), sizeof(cpuset), &cpuset) == 0;
+#elif defined(__NetBSD__)
+ cpuset_t *cpuset = cpuset_create();
+ if (cpuset == NULL)
+ return false;
+ int r = pthread_setaffinity_np(getThreadHandle(), cpuset_size(cpuset), cpuset);
+ cpuset_destroy(cpuset);
+ return r == 0;
#elif defined(__sun) || defined(sun)
return processor_bind(P_LWPID, P_MYID, proc_number, NULL) == 0
pthread_spu_t answer;
return pthread_processor_bind_np(PTHREAD_BIND_ADVISORY_NP,
- &answer, proc_number, m_thread_handle) == 0;
+ &answer, proc_number, getThreadHandle()) == 0;
#elif defined(__APPLE__)
struct thread_affinity_policy tapol;
- thread_port_t threadport = pthread_mach_thread_np(m_thread_handle);
+ thread_port_t threadport = pthread_mach_thread_np(getThreadHandle());
tapol.affinity_tag = proc_number + 1;
return thread_policy_set(threadport, THREAD_AFFINITY_POLICY,
(thread_policy_t)&tapol,
bool Thread::setPriority(int prio)
{
-#if defined(_WIN32)
+#ifdef _MSC_VER
+
+ return SetThreadPriority(getThreadHandle(), prio);
+
+#elif __MINGW32__
- return SetThreadPriority(m_thread_handle, prio);
+ return SetThreadPriority(pthread_gethandle(getThreadHandle()), prio);
#else
struct sched_param sparam;
int policy;
- if (pthread_getschedparam(m_thread_handle, &policy, &sparam) != 0)
+ if (pthread_getschedparam(getThreadHandle(), &policy, &sparam) != 0)
return false;
int min = sched_get_priority_min(policy);
int max = sched_get_priority_max(policy);
sparam.sched_priority = min + prio * (max - min) / THREAD_PRIORITY_HIGHEST;
- return pthread_setschedparam(m_thread_handle, policy, &sparam) == 0;
+ return pthread_setschedparam(getThreadHandle(), policy, &sparam) == 0;
#endif
}