Expand Up
@@ -26,48 +26,48 @@ DEALINGS IN THE SOFTWARE.
#include " threading/thread.h"
#include " threading/mutex_auto_lock.h"
#include " log.h"
#include " porting.h"
#if __cplusplus >= 201103L
#define UNUSED (expr ) do { (void )(expr); } while (0 )
#if USE_CPP11_THREADS
#include < chrono>
# else
# define UNUSED ( expr ) do { ( void )(expr); } while ( 0 )
# ifdef _WIN32
# ifndef _WIN32_WCE
#include < process.h >
# endif
# else
#include < ctime >
#include < cassert >
#include < cstdlib >
# 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>
// For getNumberOfProcessors
#include < unistd.h>
# if defined(__FreeBSD__) || defined(__APPLE__)
#include < sys/types.h>
#include < sys/sysctl.h>
# elif defined(_GNU_SOURCE)
#include < sys/sysinfo.h>
# endif
# endif
#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
// for setName
#if defined(linux) || defined(__linux)
#include < sys/prctl.h>
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
#include < pthread_np.h>
#elif defined(_MSC_VER)
struct THREADNAME_INFO {
DWORD dwType; // Must be 0x1000
LPCSTR szName; // Pointer to name (in user addr space)
DWORD dwType; // Must be 0x1000
LPCSTR szName; // Pointer to name (in user addr space)
DWORD dwThreadID; // Thread ID (-1=caller thread)
DWORD dwFlags; // Reserved for future use, must be zero
DWORD dwFlags; // Reserved for future use, must be zero
};
#endif
// For bindToProcessor
// for bindToProcessor
#if __FreeBSD_version >= 702106
typedef cpuset_t cpu_set_t ;
#elif defined(__linux) || defined(linux)
Expand All
@@ -78,195 +78,254 @@ DEALINGS IN THE SOFTWARE.
#include < sys/procset.h>
#elif defined(_AIX)
#include < sys/processor.h>
#include < sys/thread.h>
#elif defined(__APPLE__)
#include < mach/mach_init.h>
#include < mach/thread_act.h>
#endif
Thread::Thread (const std::string &name) :
name(name),
retval(NULL ),
request_stop(false ),
running(false )
#if __cplusplus >= 201103L
, thread(NULL )
#elif !defined(_WIN32)
, started(false )
m_name(name),
m_retval(NULL ),
m_request_stop(false ),
m_running(false )
{
#ifdef _AIX
m_kernel_thread_id = -1 ;
#endif
{}
#if USE_CPP11_THREADS
m_thread_obj = NULL ;
#endif
}
void Thread::wait ()
Thread::~Thread ()
{
#if __cplusplus >= 201103L
if (!thread || !thread->joinable ())
return ;
thread->join ();
#elif defined(_WIN32)
if (!running)
return ;
WaitForSingleObject (thread, INFINITE);
#else // pthread
void *status;
if (!started)
return ;
int ret = pthread_join (thread, &status);
assert (!ret);
UNUSED (ret);
started = false ;
#endif
kill ();
}
bool Thread::start ()
{
if (running)
MutexAutoLock lock (m_continue_mutex);
if (m_running)
return false ;
request_stop = false ;
#if __cplusplus >= 201103L
MutexAutoLock l (continue_mutex);
thread = new std::thread (theThread, this );
#elif defined(_WIN32)
MutexAutoLock l (continue_mutex);
# ifdef _WIN32_WCE
thread = CreateThread (NULL , 0 , theThread, this , 0 , &thread_id);
# else
thread = (HANDLE)_beginthreadex (NULL , 0 , theThread, this , 0 , &thread_id);
# endif
if (!thread)
cleanup ();
#if USE_CPP11_THREADS
try {
m_thread_obj = new std::thread (threadProc, this );
m_thread_id = m_thread->get_id ();
m_thread_handle = m_thread->native_handle ();
} except (const std::system_error &e) {
return false ;
#else
int status;
}
MutexAutoLock l (continue_mutex);
# elif USE_WIN_THREADS
status = pthread_create (&thread, NULL , theThread, this );
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
#if __cplusplus < 201103L
// Wait until running
while (!running) {
# ifdef _WIN32
Sleep (1 );
}
# else
struct timespec req, rem;
req.tv_sec = 0 ;
req.tv_nsec = 1000000 ;
nanosleep (&req, &rem);
}
started = true ;
# endif
m_thread_id = m_thread_handle;
#endif
while (!m_running)
sleep_ms (1 );
return true ;
}
bool Thread::stop ()
{
m_request_stop = true ;
return true ;
}
void Thread::wait ()
{
if (!m_running)
return ;
#if USE_CPP11_THREADS
m_thread_obj->join ();
#elif USE_WIN_THREADS
int ret == WaitForSingleObject (m_thread_handle, INFINITE);
assert (ret == WAIT_OBJECT_0);
UNUSED (ret);
#elif USE_POSIX_THREADS
int ret = pthread_join (m_thread_handle, NULL );
assert (ret == 0 );
UNUSED (ret);
#endif
assert (m_running == false );
return ;
}
bool Thread::kill ()
{
#ifdef _WIN32
if (!running)
return false ;
TerminateThread (getThreadHandle (), 0 );
CloseHandle (getThreadHandle ());
#else
if (!running) {
if (!m_running) {
wait ();
return false ;
}
#ifdef _WIN32
TerminateThread (m_thread_handle, 0 );
#else
// We need to pthread_kill instead on Android since NDKv5's pthread
// implementation is incomplete.
# ifdef __ANDROID__
pthread_kill (getThreadHandle () , SIGKILL);
pthread_kill (m_thread_handle , SIGKILL);
# else
pthread_cancel (getThreadHandle () );
pthread_cancel (m_thread_handle );
# endif
wait ();
#endif
#if __cplusplus >= 201103L
delete thread;
#endif
running = false ;
cleanup ();
return true ;
}
bool Thread::isSameThread ()
void Thread::cleanup ()
{
#if __cplusplus >= 201103L
return thread->get_id () == std::this_thread::get_id ();
#elif defined(_WIN32)
return GetCurrentThreadId () == thread_id;
#else
return pthread_equal (pthread_self (), thread);
#if USE_CPP11_THREADS
delete m_thread_obj;
m_thread_obj = NULL ;
#elif USE_WIN_THREADS
CloseHandle (m_thread_handle);
m_thread_handle = NULL ;
m_thread_id = -1 ;
#elif USE_POSIX_THREADS
// Can't do any cleanup for pthreads
#endif
m_name = " " ;
m_retval = NULL ;
m_running = false ;
m_request_stop = false ;
}
#if __cplusplus >= 201103L
void Thread::theThread (Thread *th)
bool Thread::getReturnValue (void **ret)
{
if (m_running)
return false ;
*ret = m_retval;
return true ;
}
bool Thread::isCurrentThread ()
{
return thr_is_current_thread (m_thread_id);
}
#if USE_CPP11_THREADS || USE_POSIX_THREADS
void *(Thread::threadProc)(void *param)
#elif defined(_WIN32_WCE)
DWORD WINAPI Thread::theThread ( void * param)
DWORD ( Thread::threadProc)(LPVOID param)
#elif defined(_WIN32)
UINT __stdcall Thread::theThread (void *param)
#else
void *Thread::theThread (void *param)
DWORD WINAPI (Thread::threadProc)(LPVOID param)
#endif
{
#if __cplusplus < 201103L
Thread *th = static_cast <Thread *>(param);
Thread *thr = (Thread *)param;
#ifdef _AIX
m_kernel_thread_id = thread_self ();
#endif
th->running = true ;
th->setName ();
g_logger.registerThread (th->name );
thr->setName (thr->m_name );
g_logger.registerThread (thr->m_name );
thr->m_running = true ;
th-> retval = th ->run ();
thr-> m_retval = thr ->run ();
thr->m_running = false ;
g_logger.deregisterThread ();
th->running = false ;
#if __cplusplus < 201103L
# ifdef _WIN32
CloseHandle (th->thread );
# endif
return NULL ;
#endif
}
void Thread::setName (const std::string &name)
{
#if defined(linux) || 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.
*/
// 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__)
pthread_set_name_np (pthread_self (), name.c_str ());
#elif defined(__NetBSD__)
pthread_setname_np (pthread_self (), name.c_str ());
#elif defined(__APPLE__)
pthread_setname_np (name.c_str ());
#elif defined(_MSC_VER)
// Windows itself doesn't support thread names,
// but the MSVC debugger does...
THREADNAME_INFO info;
info.dwType = 0x1000 ;
info.szName = name.c_str ();
info.dwThreadID = -1 ;
info.dwFlags = 0 ;
__try {
RaiseException (0x406D1388 , 0 , sizeof (info) / sizeof (DWORD), (ULONG_PTR *)&info);
RaiseException (0x406D1388 , 0 ,
sizeof (info) / sizeof (DWORD), (ULONG_PTR *)&info);
} __except (EXCEPTION_CONTINUE_EXECUTION) {
}
#elif defined(_WIN32) || defined(__GNU__)
// These platforms are known to not support thread names.
// Silently ignore the request.
#else
#warning "Unrecognized platform, thread names will not be available."
#endif
Expand All
@@ -276,79 +335,120 @@ void Thread::setName(const std::string &name)
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(__APPLE__)
unsigned int len, count;
len = sizeof (count);
return sysctlbyname (" hw.ncpu" , &count, &len, NULL , 0 );
#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
}
bool Thread::bindToProcessor (unsigned int num )
bool Thread::bindToProcessor (unsigned int proc_number )
{
#if defined(__ANDROID__)
return false ;
#elif defined(_WIN32)
return SetThreadAffinityMask (getThreadHandle (), 1 << num);
return SetThreadAffinityMask (m_thread_handle, 1 << proc_number);
#elif __FreeBSD_version >= 702106 || defined(__linux) || defined(linux)
cpu_set_t cpuset;
CPU_ZERO (&cpuset);
CPU_SET (num, &cpuset);
return pthread_setaffinity_np (getThreadHandle (), sizeof (cpuset),
&cpuset) == 0 ;
CPU_SET (proc_number, &cpuset);
return pthread_setaffinity_np (m_thread_handle, sizeof (cpuset), &cpuset) == 0 ;
#elif defined(__sun) || defined(sun)
return processor_bind (P_LWPID, MAKE_LWPID_PTHREAD (getThreadHandle ()),
num, NULL ) == 0
return processor_bind (P_LWPID, P_MYID, proc_number, NULL ) == 0
#elif defined(_AIX)
return bindprocessor (BINDTHREAD, (tid_t ) getThreadHandle (), pnumber) == 0 ;
return bindprocessor (BINDTHREAD, m_kernel_thread_id, proc_number) == 0 ;
#elif defined(__hpux) || defined(hpux)
pthread_spu_t answer;
return pthread_processor_bind_np (PTHREAD_BIND_ADVISORY_NP,
&answer, num, getThreadHandle ()) == 0 ;
&answer, proc_number, m_thread_handle) == 0 ;
#elif defined(__APPLE__)
struct thread_affinity_policy tapol;
thread_port_t threadport = pthread_mach_thread_np (getThreadHandle () );
tapol.affinity_tag = num + 1 ;
thread_port_t threadport = pthread_mach_thread_np (m_thread_handle );
tapol.affinity_tag = proc_number + 1 ;
return thread_policy_set (threadport, THREAD_AFFINITY_POLICY,
(thread_policy_t )&tapol,
THREAD_AFFINITY_POLICY_COUNT) == KERN_SUCCESS;
#else
return false ;
#endif
}
bool Thread::setPriority (int prio)
{
#if defined(_WIN32)
return SetThreadPriority (getThreadHandle (), prio);
return SetThreadPriority (m_thread_handle, prio);
#else
struct sched_param sparam;
int policy;
if (pthread_getschedparam (getThreadHandle () , &policy, &sparam) != 0 )
if (pthread_getschedparam (m_thread_handle , &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 (getThreadHandle (), policy, &sparam) == 0 ;
return pthread_setschedparam (m_thread_handle, policy, &sparam) == 0 ;
#endif
}