#ifdef HX_THREAD_H_OVERRIDE // Users can define their own header to use here, but there is no API // compatibility gaurantee for future changes. #include HX_THREAD_H_OVERRIDE #else #ifndef HX_THREAD_H #define HX_THREAD_H #ifndef HXCPP_HEADER_VERSION #include "hx/HeaderVersion.h" #endif #if defined(KORE) #include #include #include #include #elif defined(HX_WINRT) #include #include #include #elif defined(_WIN32) #ifdef HXCPP_WINXP_COMPAT #undef _WIN32_WINNT #define _WIN32_WINNT 0x0400 #else #undef _WIN32_WINNT #define _WIN32_WINNT 0x0600 #endif #include #include #else #include #include #include #include #define HXCPP_PTHREADS #endif #ifdef RegisterClass #undef RegisterClass #endif #if defined(KORE) struct HxMutex { HxMutex() { kinc_mutex_init(&mutex); } ~HxMutex() { kinc_mutex_destroy(&mutex); } void Lock() { kinc_mutex_lock(&mutex); } void Unlock() { kinc_mutex_unlock(&mutex); } bool TryLock() { return kinc_mutex_try_to_lock(&mutex); } void Clean() { kinc_mutex_destroy(&mutex); } private: kinc_mutex_t mutex; }; #define THREAD_FUNC_TYPE void #define THREAD_FUNC_RET return; inline bool HxCreateDetachedThread(void (*func)(void *), void *param) { kinc_thread_t thread; kinc_thread_init(&thread, func, param); return true; } #elif defined(HX_WINDOWS) struct HxMutex { HxMutex() { mValid = true; #ifdef HX_WINRT InitializeCriticalSectionEx(&mCritSec,4000,0); #else InitializeCriticalSection(&mCritSec); #endif } ~HxMutex() { if (mValid) DeleteCriticalSection(&mCritSec); } void Lock() { EnterCriticalSection(&mCritSec); } void Unlock() { LeaveCriticalSection(&mCritSec); } bool TryLock() { return TryEnterCriticalSection(&mCritSec); } bool IsValid() { return mValid; } void Clean() { if (mValid) { DeleteCriticalSection(&mCritSec); mValid = false; } } bool mValid; CRITICAL_SECTION mCritSec; }; #define THREAD_FUNC_TYPE DWORD WINAPI #define THREAD_FUNC_RET return 0; inline bool HxCreateDetachedThread(DWORD (WINAPI *func)(void *), void *param) { return (CreateThread(NULL, 0, func, param, 0, 0) != 0); } #else struct HxMutex { HxMutex() { pthread_mutexattr_t mta; pthread_mutexattr_init(&mta); pthread_mutexattr_settype(&mta, PTHREAD_MUTEX_RECURSIVE); mValid = pthread_mutex_init(&mMutex,&mta) ==0; } ~HxMutex() { if (mValid) pthread_mutex_destroy(&mMutex); } void Lock() { pthread_mutex_lock(&mMutex); } void Unlock() { pthread_mutex_unlock(&mMutex); } bool TryLock() { return !pthread_mutex_trylock(&mMutex); } bool IsValid() { return mValid; } void Clean() { if (mValid) pthread_mutex_destroy(&mMutex); mValid = 0; } bool mValid; pthread_mutex_t mMutex; }; #define THREAD_FUNC_TYPE void * #define THREAD_FUNC_RET return 0; inline bool HxCreateDetachedThread(void *(*func)(void *), void *param) { pthread_t t; pthread_attr_t attr; if (pthread_attr_init(&attr) != 0) return false; #ifdef PTHREAD_CREATE_DETACHED if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) return false; #endif if (pthread_create(&t, &attr, func, param) != 0 ) return false; if (pthread_attr_destroy(&attr) != 0) return false; return true; } #endif template struct TAutoLock { TAutoLock(LOCKABLE &inMutex) : mMutex(inMutex) { mMutex.Lock(); } ~TAutoLock() { mMutex.Unlock(); } void Lock() { mMutex.Lock(); } void Unlock() { mMutex.Unlock(); } LOCKABLE &mMutex; }; typedef TAutoLock AutoLock; #if defined(KORE) struct HxSemaphore { HxSemaphore() { kinc_event_init(&event, true); } ~HxSemaphore() { kinc_event_destroy(&event); } void Set() { kinc_event_signal(&event); } void Wait() { kinc_event_wait(&event); } bool WaitSeconds(double inSeconds) { return kinc_event_try_to_wait(&event, inSeconds); } void Reset() { kinc_event_reset(&event); } void Clean() { kinc_event_destroy(&event); } private: kinc_event_t event; }; struct ThreadPoolSignal { ThreadPoolSignal() { kinc_event_init(&event, true); } ~ThreadPoolSignal() { } void Set() { kinc_event_signal(&event); } void Wait() { kinc_event_wait(&event); } bool WaitSeconds(double inSeconds) { return kinc_event_try_to_wait(&event, inSeconds); } void Reset() { kinc_event_reset(&event); } void Clean() { kinc_event_destroy(&event); } private: kinc_event_t event; }; #elif defined(HX_WINDOWS) struct HxSemaphore { HxSemaphore() { #ifdef HX_WINRT mSemaphore = CreateEventEx(nullptr,nullptr,0,EVENT_ALL_ACCESS); #else mSemaphore = CreateEvent(0,0,0,0); #endif } ~HxSemaphore() { if (mSemaphore) CloseHandle(mSemaphore); } void Set() { SetEvent(mSemaphore); } void Wait() { #ifdef HX_WINRT WaitForSingleObjectEx(mSemaphore,INFINITE,false); #else WaitForSingleObject(mSemaphore,INFINITE); #endif } // Returns true on success, false on timeout bool WaitSeconds(double inSeconds) { #ifdef HX_WINRT return WaitForSingleObjectEx(mSemaphore,inSeconds*1000.0,false) != WAIT_TIMEOUT; #else return WaitForSingleObject(mSemaphore,inSeconds*1000.0) != WAIT_TIMEOUT; #endif } void Reset() { ResetEvent(mSemaphore); } void Clean() { if (mSemaphore) CloseHandle(mSemaphore); mSemaphore = 0; } HANDLE mSemaphore; }; #else #define HX_THREAD_SEMAPHORE_LOCKABLE struct HxSemaphore { HxSemaphore() { mSet = false; mValid = true; pthread_cond_init(&mCondition,0); } ~HxSemaphore() { if (mValid) { pthread_cond_destroy(&mCondition); } } // For autolock inline operator HxMutex &() { return mMutex; } void Set() { AutoLock lock(mMutex); if (!mSet) { mSet = true; pthread_cond_signal( &mCondition ); } } void QSet() { mSet = true; pthread_cond_signal( &mCondition ); } void Reset() { AutoLock lock(mMutex); mSet = false; } void QReset() { mSet = false; } void Wait() { AutoLock lock(mMutex); while( !mSet ) pthread_cond_wait( &mCondition, &mMutex.mMutex ); mSet = false; } // when we already hold the mMutex lock ... void QWait() { while( !mSet ) pthread_cond_wait( &mCondition, &mMutex.mMutex ); mSet = false; } // Returns true if the wait was success, false on timeout. bool WaitSeconds(double inSeconds) { struct timeval tv; gettimeofday(&tv, 0); int isec = (int)inSeconds; int usec = (int)((inSeconds-isec)*1000000.0); timespec spec; spec.tv_nsec = (tv.tv_usec + usec) * 1000; if (spec.tv_nsec>1000000000) { spec.tv_nsec-=1000000000; isec++; } spec.tv_sec = tv.tv_sec + isec; AutoLock lock(mMutex); int result = 0; // Wait for set to be true... while( !mSet && (result=pthread_cond_timedwait( &mCondition, &mMutex.mMutex, &spec )) != ETIMEDOUT) { if (result!=0) { // Error - something's gone wrong... /* if (result==EINVAL) printf("ERROR: Condition EINVAL\n"); else if (result==EPERM) printf("ERROR: Condition EPERM\n"); else printf("ERROR: Condition unknown error\n"); */ break; } // Condition signalled - but try mSet again ... } bool wasSet = mSet; mSet = false; return wasSet; } void Clean() { mMutex.Clean(); if (mValid) { mValid = false; pthread_cond_destroy(&mCondition); } } HxMutex mMutex; pthread_cond_t mCondition; bool mSet; bool mValid; }; #endif #if defined(KORE) #include inline void HxSleep(unsigned int ms) { kinc_thread_sleep(ms); } #elif defined HX_WINRT inline void HxSleep(unsigned int ms) { ::Sleep(ms); } #elif defined HX_WINDOWS inline void HxSleep(unsigned int ms) { ::Sleep(ms); } #else inline void HxSleep(unsigned int ms) { struct timespec t; struct timespec tmp; t.tv_sec = 0; t.tv_nsec = ms * 1000000; nanosleep(&t, &tmp); } #endif #endif #endif