459 lines
8.9 KiB
C
Raw Normal View History

2025-01-22 16:18:30 +01:00
#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