#include "TinyJS/TinyJS_Threading.h" #undef HAVE_THREADING #if !defined(NO_THREADING) && !defined(HAVE_CUSTOM_THREADING_IMPL) # define HAVE_THREADING # ifdef HAVE_CXX_THREADS # include # else # if defined(WIN32) && !defined(HAVE_PTHREAD) # include # else # include # ifndef HAVE_PTHREAD # define HAVE_PTHREAD # endif # endif # endif #endif #ifdef HAVE_THREADING ////////////////////////////////////////////////////////////////////////// // Mutex ////////////////////////////////////////////////////////////////////////// #ifndef HAVE_CXX_THREADS #ifndef HAVE_PTHREAD // simple mutex 4 windows //# define pthread_mutex_t HANDLE //# define pthread_mutex_init(m, a) *(m) = CreateMutex(NULL, false, NULL) //# define pthread_mutex_destroy(m) CloseHandle(*(m)); //# define pthread_mutex_lock(m) WaitForSingleObject(*(m), INFINITE); //# define pthread_mutex_unlock(m) ReleaseMutex(*(m)); # define pthread_mutex_t CRITICAL_SECTION # define pthread_mutex_init(m, a) { InitializeCriticalSection(m); 0; } # define pthread_mutex_destroy(m) do {} while(0) # define pthread_mutex_lock(m) EnterCriticalSection(m) # define pthread_mutex_unlock(m) LeaveCriticalSection(m) #endif class CScriptMutex_impl : public CScriptMutex::CScriptMutex_t { public: CScriptMutex_impl() { pthread_mutex_init(&mutex, NULL); } ~CScriptMutex_impl() { pthread_mutex_destroy(&mutex); } void lock() { pthread_mutex_lock(&mutex); } void unlock() { pthread_mutex_unlock(&mutex); } void *getRealMutex() { return &mutex; } pthread_mutex_t mutex; }; CScriptMutex::CScriptMutex() { mutex = new CScriptMutex_impl; } CScriptMutex::~CScriptMutex() { delete mutex; } #endif /*HAVE_CXX_THREADS*/ ////////////////////////////////////////////////////////////////////////// // CondVar ////////////////////////////////////////////////////////////////////////// #ifndef HAVE_CXX_THREADS #ifndef HAVE_PTHREAD // simple conditional Variable 4 windows # define pthread_cond_t CONDITION_VARIABLE # define pthread_cond_init(c, a) InitializeConditionVariable(c) # define pthread_cond_destroy(c) do {} while(0) # define pthread_cond_wait(c, m) SleepConditionVariableCS(c, m, INFINITE) # define pthread_cond_signal(c) WakeConditionVariable(c); #endif class CScriptCondVar_impl : public CScriptCondVar::CScriptCondVar_t { public: CScriptCondVar_impl(CScriptCondVar *_this) : This(_this) { pthread_cond_init(&cond, NULL); } ~CScriptCondVar_impl() { pthread_cond_destroy(&cond); } CScriptCondVar *This; void notify_one() { pthread_cond_signal(&cond); } void wait(CScriptUniqueLock &Lock) { pthread_cond_wait(&cond, (pthread_mutex_t *)Lock.mutex->getRealMutex()); } pthread_cond_t cond; }; CScriptCondVar::CScriptCondVar() { condVar = new CScriptCondVar_impl(this); } CScriptCondVar::~CScriptCondVar() { delete condVar; } #endif /*HAVE_CXX_THREADS*/ ////////////////////////////////////////////////////////////////////////// // Threading ////////////////////////////////////////////////////////////////////////// #ifdef HAVE_CXX_THREADS # define pthread_attr_t int # define pthread_attr_init(a) do {} while(0) # define pthread_attr_destroy(a) do {} while(0) # define pthread_t std::thread # define pthread_create(t, attr, fnc, a) *(t) = std::thread(fnc, this); # define pthread_join(t, v) t.join(); #elif !defined(HAVE_PTHREAD) // simple pthreads 4 windows # define pthread_attr_t SIZE_T # define pthread_attr_init(attr) (*attr=0) # define pthread_attr_destroy(a) do {} while(0) # define pthread_attr_setstacksize(attr, stack) *attr=stack; # define pthread_t HANDLE # define pthread_create(t, attr, fnc, a) *(t) = CreateThread(NULL, attr ? *((pthread_attr_t*)attr) : 0, (LPTHREAD_START_ROUTINE)fnc, a, 0, NULL) # define pthread_join(t, v) WaitForSingleObject(t, INFINITE), GetExitCodeThread(t,(LPDWORD)v), CloseHandle(t) #endif class CScriptThread_impl : public CScriptThread::CScriptThread_t { public: CScriptThread_impl(CScriptThread *_this) : retvar((void*)-1), activ(false), running(false), started(false), This(_this) {} ~CScriptThread_impl() {} void Run() { if(started) return; activ = true; // pthread_attr_t attribute; // pthread_attr_init(&attribute); // pthread_attr_setstacksize(&attribute,1024); pthread_create(&thread, NULL /*&attribute*/, (void*(*)(void*))ThreadFnc, this); // pthread_attr_destroy(&attribute); while(!started); } int Stop(bool Wait) { if(!running) return started ? retValue() : -1; activ = false; if(Wait) { pthread_join(thread, &retvar); } return (int)retvar; } int retValue() { return (int)retvar; } bool isActiv() { return activ; } bool isRunning() { return running; } bool isStarted() { return started; } static void *ThreadFnc(CScriptThread_impl *This) { This->running = This->started = true; This->retvar = (void*)This->This->ThreadFnc(); This->running = false; This->This->ThreadFncFinished(); return This->retvar; } void *retvar; bool activ; bool running; bool started; CScriptThread *This; pthread_t thread; }; CScriptThread::CScriptThread() { thread = new CScriptThread_impl(this); } CScriptThread::~CScriptThread() { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" delete thread; #pragma GCC diagnostic pop } void CScriptThread::ThreadFncFinished() {} CScriptCoroutine::StopIteration_t CScriptCoroutine::StopIteration; bool CScriptCoroutine::next() { if(!isStarted()) { Run(); wake_main.wait(); } else if(isRunning()) { wake_thread.post(); wake_main.wait(); } else return false; if(!isRunning()) return false; return true; } bool CScriptCoroutine::yield_no_throw() { wake_main.post(); wake_thread.wait(); return isActiv(); } void CScriptCoroutine::yield() { wake_main.post(); wake_thread.wait(); if(!isActiv()) { throw StopIteration; } } int CScriptCoroutine::ThreadFnc() { int ret=-1; try { ret = Coroutine(); } catch(StopIteration_t &) { return 0; } catch(std::exception & e) { printf("CScriptCoroutine has received an uncaught exception: %s\n", e.what()); return -1; } catch(...) { printf("CScriptCoroutine has received an uncaught and unknown exception\n"); return -1; } return ret; } void CScriptCoroutine::ThreadFncFinished() { wake_main.post(); } #endif // HAVE_THREADING