forked from LeenkxTeam/LNXSDK
		
	
		
			
	
	
		
			459 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			459 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | #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 <kinc/threads/atomic.h>
 | ||
|  | #include <kinc/threads/event.h>
 | ||
|  | #include <kinc/threads/mutex.h>
 | ||
|  | #include <kinc/threads/thread.h>
 | ||
|  | 
 | ||
|  | #elif defined(HX_WINRT)
 | ||
|  | 
 | ||
|  | #include <windows.h>
 | ||
|  | #include <process.h>
 | ||
|  | #include <mutex>
 | ||
|  | 
 | ||
|  | #elif defined(_WIN32)
 | ||
|  | 
 | ||
|  | #ifdef HXCPP_WINXP_COMPAT
 | ||
|  | #undef _WIN32_WINNT
 | ||
|  | #define _WIN32_WINNT 0x0400
 | ||
|  | #else
 | ||
|  | #undef _WIN32_WINNT
 | ||
|  | #define _WIN32_WINNT 0x0600
 | ||
|  | #endif
 | ||
|  | 
 | ||
|  | #include <windows.h>
 | ||
|  | #include <process.h>
 | ||
|  | #else
 | ||
|  | #include <errno.h>
 | ||
|  | #include <pthread.h>
 | ||
|  | #include <sys/time.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | #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<typename LOCKABLE> | ||
|  | struct TAutoLock | ||
|  | { | ||
|  |    TAutoLock(LOCKABLE &inMutex) : mMutex(inMutex) { mMutex.Lock(); } | ||
|  |    ~TAutoLock() { mMutex.Unlock(); } | ||
|  |    void Lock() { mMutex.Lock(); } | ||
|  |    void Unlock() { mMutex.Unlock(); } | ||
|  | 
 | ||
|  |    LOCKABLE &mMutex; | ||
|  | }; | ||
|  | 
 | ||
|  | typedef TAutoLock<HxMutex> 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 <kinc/threads/thread.h>
 | ||
|  | 
 | ||
|  | 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
 |