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
 |