diff --git a/include/hx/thread/ConditionVariable.hpp b/include/hx/thread/ConditionVariable.hpp new file mode 100644 index 000000000..aef1f83e1 --- /dev/null +++ b/include/hx/thread/ConditionVariable.hpp @@ -0,0 +1,30 @@ +#pragma once + +#ifndef HXCPP_H +#include +#endif + +HX_DECLARE_CLASS2(hx, thread, ConditionVariable) + +namespace hx +{ + namespace thread + { + struct ConditionVariable_obj : public hx::Object + { + ConditionVariable_obj(); + + void acquire(); + bool tryAcquire(); + void release(); + void wait(); + void signal(); + void broadcast(); + + private: + struct Impl; + + Impl* impl; + }; + } +} \ No newline at end of file diff --git a/include/hx/thread/RecursiveMutex.hpp b/include/hx/thread/RecursiveMutex.hpp new file mode 100644 index 000000000..f2bac5c97 --- /dev/null +++ b/include/hx/thread/RecursiveMutex.hpp @@ -0,0 +1,27 @@ +#pragma once + +#ifndef HXCPP_H +#include +#endif + +HX_DECLARE_CLASS2(hx, thread, RecursiveMutex) + +namespace hx +{ + namespace thread + { + struct RecursiveMutex_obj : public hx::Object + { + RecursiveMutex_obj(); + + void acquire(); + void release(); + bool tryAcquire(); + + private: + struct Impl; + + Impl* impl; + }; + } +} \ No newline at end of file diff --git a/src/hx/Debug.cpp b/src/hx/Debug.cpp index 25c7d4dba..403bf8118 100644 --- a/src/hx/Debug.cpp +++ b/src/hx/Debug.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #if defined(HXCPP_CATCH_SEGV) && !defined(_MSC_VER) @@ -45,7 +46,7 @@ namespace hx const char* EXTERN_CLASS_NAME = "extern"; #ifdef HXCPP_STACK_IDS -static HxMutex sStackMapMutex; +static std::mutex sStackMapMutex; typedef UnorderedMap StackMap; static StackMap sStackMap; #endif @@ -245,9 +246,10 @@ void StackContext::onThreadAttach() #ifdef HXCPP_STACK_IDS mThreadId = __hxcpp_GetCurrentThreadNumber(); - sStackMapMutex.Lock(); - sStackMap[mThreadId] = this; - sStackMapMutex.Unlock(); + { + std::lock_guard guard(sStackMapMutex); + sStackMap[mThreadId] = this; + } #endif #ifdef HXCPP_DEBUGGER @@ -302,9 +304,10 @@ void StackContext::onThreadDetach() #endif #ifdef HXCPP_STACK_IDS - sStackMapMutex.Lock(); - sStackMap.erase(mThreadId); - sStackMapMutex.Unlock(); + { + std::lock_guard guard(sStackMapMutex); + sStackMap.erase(mThreadId); + } mThreadId = 0; #endif @@ -317,18 +320,17 @@ void StackContext::onThreadDetach() void StackContext::getAllStackIds( QuickVec &outIds ) { outIds.clear(); - sStackMapMutex.Lock(); + + std::lock_guard guard(sStackMapMutex); + for(StackMap::iterator i=sStackMap.begin(); i!=sStackMap.end(); ++i) outIds.push(i->first); - sStackMapMutex.Unlock(); } StackContext *StackContext::getStackForId(int id) { - sStackMapMutex.Lock(); - StackContext *result = sStackMap[id]; - sStackMapMutex.Unlock(); - return result; + std::lock_guard guard(sStackMapMutex); + return sStackMap[id]; } #endif diff --git a/src/hx/Debugger.cpp b/src/hx/Debugger.cpp index 3887541a4..374248272 100644 --- a/src/hx/Debugger.cpp +++ b/src/hx/Debugger.cpp @@ -7,7 +7,7 @@ #include #include #include - +#include // Newer versions of haxe compiler will set these too (or might be null for haxe 3.0) static const char **__all_files_fullpath = 0; @@ -84,7 +84,7 @@ static void read_memory_barrier() const char *_hx_dbg_find_scriptable_class_name(String className); -static HxMutex gMutex; +static std::mutex gMutex; static std::map gMap; static std::list gList; @@ -106,7 +106,7 @@ class DebuggerContext // Waiting for continue bool mWaiting; - HxMutex mWaitMutex; + std::mutex mWaitMutex; HxSemaphore mWaitSemaphore; int mContinueCount; bool mAttached; @@ -130,10 +130,10 @@ class DebuggerContext mStackContext = inStack; mThreadNumber = mStackContext->mThreadId; mStatus = DBG_STATUS_RUNNING; - gMutex.Lock(); + gMutex.lock(); gList.push_back(this); gMap[mThreadNumber] = this; - gMutex.Unlock(); + gMutex.unlock(); // Note that there is a race condition here. If the debugger is // "detaching" at this exact moment, it might set the event handler to @@ -152,11 +152,11 @@ class DebuggerContext void detach() { mAttached = false; - gMutex.Lock(); + gMutex.lock(); gList.remove(this); gMap.erase(mThreadNumber); mBreakpoints = ReleaseBreakpointsLocked(mBreakpoints); - gMutex.Unlock(); + gMutex.unlock(); reset(); Dynamic handler = hx::g_eventNotificationHandler; @@ -200,7 +200,7 @@ class DebuggerContext // to hold the lock during the entire process as this could block // threads from actually evaluating breakpoints. std::vector threadNumbers; - gMutex.Lock(); + gMutex.lock(); std::list::iterator iter = gList.begin(); while (iter != gList.end()) { DebuggerContext *stack = *iter++; @@ -209,7 +209,7 @@ class DebuggerContext } threadNumbers.push_back(stack->mThreadNumber); } - gMutex.Unlock(); + gMutex.unlock(); // Now wait no longer than 2 seconds total for all threads to // be stopped. If any thread times out, then stop immediately. @@ -222,20 +222,20 @@ class DebuggerContext HxSemaphore timeoutSem; int i = 0; while (i < size) { - gMutex.Lock(); + gMutex.lock(); DebuggerContext *stack = gMap[threadNumbers[i]]; if (!stack) { // The thread went away while we were working! - gMutex.Unlock(); + gMutex.unlock(); i += 1; continue; } if (stack->mWaiting) { - gMutex.Unlock(); + gMutex.unlock(); i += 1; continue; } - gMutex.Unlock(); + gMutex.unlock(); if (timeSlicesLeft == 0) { // The 2 seconds have expired, give up return; @@ -258,7 +258,7 @@ class DebuggerContext count = 1; } - mWaitMutex.Lock(); + mWaitMutex.lock(); if (mWaiting) { mWaiting = false; @@ -266,7 +266,7 @@ class DebuggerContext mWaitSemaphore.Set(); } - mWaitMutex.Unlock(); + mWaitMutex.unlock(); } @@ -282,9 +282,9 @@ class DebuggerContext // This thread cannot stop while making the callback mCanStop = false; - mWaitMutex.Lock(); + mWaitMutex.lock(); mWaiting = true; - mWaitMutex.Unlock(); + mWaitMutex.unlock(); // Call the handler to announce the status. StackFrame *frame = mStackContext->getCurrentStackFrame(); @@ -299,17 +299,17 @@ class DebuggerContext { // Wait until the debugger thread sets mWaiting to false and signals // the semaphore - mWaitMutex.Lock(); + mWaitMutex.lock(); while (mWaiting) { - mWaitMutex.Unlock(); + mWaitMutex.unlock(); hx::EnterGCFreeZone(); mWaitSemaphore.Wait(); hx::ExitGCFreeZone(); - mWaitMutex.Lock(); + mWaitMutex.lock(); } - mWaitMutex.Unlock(); + mWaitMutex.unlock(); } // Save the breakpoint status in the call stack so that queries for @@ -380,7 +380,7 @@ class Breakpoints return -1; } - gMutex.Lock(); + gMutex.lock(); int ret = gNextBreakpointNumber++; @@ -398,7 +398,7 @@ class Breakpoints // gShouldCallHandleBreakpoints update before gBreakpoints has updated gShouldCallHandleBreakpoints = true; - gMutex.Unlock(); + gMutex.unlock(); return ret; } @@ -418,7 +418,7 @@ class Breakpoints return -1; } - gMutex.Lock(); + gMutex.lock(); int ret = gNextBreakpointNumber++; @@ -436,14 +436,14 @@ class Breakpoints // gShouldCallHandleBreakpoints update before gBreakpoints has updated gShouldCallHandleBreakpoints = true; - gMutex.Unlock(); + gMutex.unlock(); return ret; } static void DeleteAll() { - gMutex.Lock(); + gMutex.lock(); Breakpoints *newBreakpoints = new Breakpoints(); @@ -459,12 +459,12 @@ class Breakpoints // gShouldCallHandleBreakpoints update before gStepType has updated gShouldCallHandleBreakpoints = (gStepType != STEP_NONE) || (sExecutionTrace==exeTraceLines); - gMutex.Unlock(); + gMutex.unlock(); } static void Delete(int number) { - gMutex.Lock(); + gMutex.lock(); if (gBreakpoints->HasBreakpoint(number)) { // Replace mBreakpoints with a copy and remove the breakpoint @@ -489,7 +489,7 @@ class Breakpoints } } - gMutex.Unlock(); + gMutex.unlock(); } static void BreakNow(bool wait) @@ -515,7 +515,7 @@ class Breakpoints gShouldCallHandleBreakpoints = !gBreakpoints->IsEmpty() || (sExecutionTrace==exeTraceLines); - gMutex.Lock(); + gMutex.lock(); // All threads get continued, but specialThreadNumber only for count std::list::iterator iter = gList.begin(); @@ -529,7 +529,7 @@ class Breakpoints } } - gMutex.Unlock(); + gMutex.unlock(); } static void StepThread(int threadNumber, StepType stepType, int stepCount) @@ -539,7 +539,7 @@ class Breakpoints gStepType = stepType; gStepCount = stepCount; - gMutex.Lock(); + gMutex.lock(); std::list::iterator iter = gList.begin(); while (iter != gList.end()) { @@ -550,7 +550,7 @@ class Breakpoints break; } } - gMutex.Unlock(); + gMutex.unlock(); } @@ -603,7 +603,7 @@ class Breakpoints // If the current thread has never gotten a reference to // breakpoints, get a reference to the current breakpoints if (!breakpoints) { - gMutex.Lock(); + gMutex.lock(); // Get break points and ref it breakpoints = gBreakpoints; // This read memory barrier ensures that old values within @@ -612,7 +612,7 @@ class Breakpoints read_memory_barrier(); stack->mDebugger->mBreakpoints = breakpoints; breakpoints->AddRef(); - gMutex.Unlock(); + gMutex.unlock(); } // Else if the current thread's breakpoints number is out of date, // release the reference on that and get the new breakpoints. @@ -621,7 +621,7 @@ class Breakpoints // until it "sees" a newer gBreakpoints. Without memory barriers, // this could theoretically be indefinitely. else if (breakpoints != gBreakpoints) { - gMutex.Lock(); + gMutex.lock(); // Release ref on current break points breakpoints->RemoveRef(); // Get new break points and ref it @@ -632,7 +632,7 @@ class Breakpoints read_memory_barrier(); stack->mDebugger->mBreakpoints = breakpoints; breakpoints->AddRef(); - gMutex.Unlock(); + gMutex.unlock(); } // If there are breakpoints, then may need to break in one @@ -968,11 +968,11 @@ static Dynamic GetThreadInfo(int threadNumber, bool unsafe) DebuggerContext *stack = 0; - gMutex.Lock(); + gMutex.lock(); if (gMap.count(threadNumber) == 0) { - gMutex.Unlock(); + gMutex.unlock(); return null(); } else @@ -980,7 +980,7 @@ static Dynamic GetThreadInfo(int threadNumber, bool unsafe) if ((stack->mStatus == DBG_STATUS_RUNNING) && !unsafe) { - gMutex.Unlock(); + gMutex.unlock(); return null(); } @@ -988,7 +988,7 @@ static Dynamic GetThreadInfo(int threadNumber, bool unsafe) // converted is either for a thread that is not running (and thus // the stack cannot be altered while the conversion is in progress), // or unsafe mode has been invoked - gMutex.Unlock(); + gMutex.unlock(); Dynamic ret = g_newThreadInfoFunction @@ -1018,7 +1018,7 @@ static Dynamic GetThreadInfo(int threadNumber, bool unsafe) // Gets a ThreadInfo for each Thread static ::Array GetThreadInfos() { - gMutex.Lock(); + gMutex.lock(); // Latch the current thread numbers from the current list of call // stacks. @@ -1029,7 +1029,7 @@ static ::Array GetThreadInfos() threadNumbers.push_back(stack->mThreadNumber); } - gMutex.Unlock(); + gMutex.unlock(); ::Array ret = Array_obj::__new(); @@ -1052,7 +1052,7 @@ static ::Array GetStackVariables(int threadNumber, { ::Array ret = Array_obj::__new(); - gMutex.Lock(); + gMutex.lock(); std::list::iterator iter = gList.begin(); while (iter != gList.end()) { @@ -1060,7 +1060,7 @@ static ::Array GetStackVariables(int threadNumber, if (ctx->mThreadNumber == threadNumber) { if ((ctx->mStatus == DBG_STATUS_RUNNING) && !unsafe) { ret->push(markThreadNotStopped); - gMutex.Unlock(); + gMutex.unlock(); return ret; } StackContext *stack = ctx->mStackContext; @@ -1084,7 +1084,7 @@ static ::Array GetStackVariables(int threadNumber, } } - gMutex.Unlock(); + gMutex.unlock(); return ret; } @@ -1100,10 +1100,10 @@ static Dynamic GetVariableValue(int threadNumber, int stackFrameNumber, DebuggerContext *ctx; - gMutex.Lock(); + gMutex.lock(); if (gMap.count(threadNumber) == 0) { - gMutex.Unlock(); + gMutex.unlock(); return markNonexistent; } else { @@ -1111,12 +1111,12 @@ static Dynamic GetVariableValue(int threadNumber, int stackFrameNumber, } if ((ctx->mStatus == DBG_STATUS_RUNNING) && !unsafe) { - gMutex.Unlock(); + gMutex.unlock(); return markThreadNotStopped; } // Don't need the lock any more, the thread is not running - gMutex.Unlock(); + gMutex.unlock(); StackContext *stack = ctx->mStackContext; @@ -1163,10 +1163,10 @@ static Dynamic SetVariableValue(int threadNumber, int stackFrameNumber, DebuggerContext *ctx; - gMutex.Lock(); + gMutex.lock(); if (gMap.count(threadNumber) == 0) { - gMutex.Unlock(); + gMutex.unlock(); return null(); } else { @@ -1174,12 +1174,12 @@ static Dynamic SetVariableValue(int threadNumber, int stackFrameNumber, } if ((ctx->mStatus == DBG_STATUS_RUNNING) && !unsafe) { - gMutex.Unlock(); + gMutex.unlock(); return markThreadNotStopped; } // Don't need the lock any more, the thread is not running - gMutex.Unlock(); + gMutex.unlock(); StackContext *stack = ctx->mStackContext; // Check to ensure that the stack frame is valid diff --git a/src/hx/Profiler.cpp b/src/hx/Profiler.cpp index 63ce38595..d5cd809d3 100644 --- a/src/hx/Profiler.cpp +++ b/src/hx/Profiler.cpp @@ -3,7 +3,7 @@ #include #include #include - +#include #ifdef HX_WINRT @@ -43,24 +43,21 @@ class Profiler mDumpFile = inDumpFile; // When a profiler exists, the profiler thread needs to exist - gThreadMutex.Lock(); + + std::lock_guard lock(gThreadMutex); gThreadRefCount += 1; if (gThreadRefCount == 1) { HxCreateDetachedThread(ProfileMainLoop, 0); } - - gThreadMutex.Unlock(); } ~Profiler() { - gThreadMutex.Lock(); + std::lock_guard lock(gThreadMutex); gThreadRefCount -= 1; - - gThreadMutex.Unlock(); } void sample(hx::StackContext *stack) @@ -235,11 +232,11 @@ class Profiler int mT0; std::map mProfileStats; - static HxMutex gThreadMutex; + static std::mutex gThreadMutex; static int gThreadRefCount; static int gProfileClock; }; -/* static */ HxMutex Profiler::gThreadMutex; +/* static */ std::mutex Profiler::gThreadMutex; /* static */ int Profiler::gThreadRefCount; /* static */ int Profiler::gProfileClock; diff --git a/src/hx/StdLibs.cpp b/src/hx/StdLibs.cpp index c3984cc10..43993910b 100644 --- a/src/hx/StdLibs.cpp +++ b/src/hx/StdLibs.cpp @@ -30,6 +30,7 @@ typedef int64_t __int64; #include #include #include +#include #ifdef HX_ANDROID @@ -785,7 +786,7 @@ Dynamic __hxcpp_create_var_args(Dynamic &inArrayFunc) -static HxMutex sgFieldMapMutex; +static std::mutex sgFieldMapMutex; typedef std::map StringToField; @@ -809,7 +810,7 @@ const String &__hxcpp_field_from_id( int f ) int __hxcpp_field_to_id( const char *inFieldName ) { - AutoLock lock(sgFieldMapMutex); + std::lock_guard lock(sgFieldMapMutex); if (!sgFieldToStringAlloc) { diff --git a/src/hx/Telemetry.cpp b/src/hx/Telemetry.cpp index 593299a4c..c49035061 100644 --- a/src/hx/Telemetry.cpp +++ b/src/hx/Telemetry.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace hx @@ -62,23 +63,19 @@ class Telemetry Stash(); // When a profiler exists, the profiler thread needs to exist - gThreadMutex.Lock(); + std::lock_guard lock(gThreadMutex); gThreadRefCount += 1; if (gThreadRefCount == 1) { HxCreateDetachedThread(ProfileMainLoop, 0); } - - gThreadMutex.Unlock(); } ~Telemetry() { - gThreadMutex.Lock(); + std::lock_guard lock(gThreadMutex); gThreadRefCount -= 1; - - gThreadMutex.Unlock(); } // todo @@ -110,7 +107,7 @@ class Telemetry stash->gcoverhead = gcOverhead*1000000; // usec gcOverhead = 0; - alloc_mutex.Lock(); + alloc_mutex.lock(); if (_last_obj!=0) lookup_last_object_type(); @@ -122,7 +119,7 @@ class Telemetry allocation_data = new std::vector(); } - alloc_mutex.Unlock(); + alloc_mutex.unlock(); int i,size; stash->names = 0; @@ -146,18 +143,19 @@ class Telemetry allocStacksStashed = allocStacks.size(); } - gStashMutex.Lock(); - stashed.push_back(*stash); - gStashMutex.Unlock(); + { + std::lock_guard lock(gStashMutex); + + stashed.push_back(*stash); + } IgnoreAllocs(-1); } TelemetryFrame* Dump() { - gStashMutex.Lock(); + std::lock_guard lock(gStashMutex); if (stashed.size()<1) { - gStashMutex.Unlock(); return 0; } @@ -171,7 +169,6 @@ class Telemetry stashed.pop_front(); // Destroy item that was Dumped last call front = &stashed.front(); - gStashMutex.Unlock(); //printf(" -- dumped stash, allocs=%d, alloc[max]=%d\n", front->allocations->size(), front->allocations->size()>0 ? front->allocations->at(front->allocations->size()-1) : 0); @@ -200,7 +197,7 @@ class Telemetry const char* type = "_uninitialized"; int obj_id = __hxt_ptr_id(_last_obj); - alloc_mutex.Lock(); + alloc_mutex.lock(); std::map::iterator exist = alloc_map.find(_last_obj); if (exist != alloc_map.end() && _last_obj!=(NULL)) { type = "_unknown"; @@ -218,7 +215,7 @@ class Telemetry //printf("Updating last allocation %016lx type to %s\n", _last_obj, type); } } - alloc_mutex.Unlock(); + alloc_mutex.unlock(); allocation_data->at(_last_loc+2) = GetNameIdx(type); _last_obj = 0; } @@ -255,7 +252,7 @@ class Telemetry double t0 = __hxcpp_time_stamp(); Telemetry* telemetry = 0; - alloc_mutex.Lock(); + alloc_mutex.lock(); std::map::iterator iter = alloc_map.begin(); while (iter != alloc_map.end()) { void* obj = iter->first; @@ -272,7 +269,7 @@ class Telemetry iter++; } } - alloc_mutex.Unlock(); + alloc_mutex.unlock(); // Report overhead on one of the telemetry instances // TODO: something better? @@ -338,19 +335,19 @@ class Telemetry std::vector *allocation_data; - static HxMutex gStashMutex; - static HxMutex gThreadMutex; + static std::recursive_mutex gStashMutex; + static std::recursive_mutex gThreadMutex; static int gThreadRefCount; static int gProfileClock; - static HxMutex alloc_mutex; + static std::recursive_mutex alloc_mutex; static std::map alloc_map; }; -/* static */ HxMutex Telemetry::gStashMutex; -/* static */ HxMutex Telemetry::gThreadMutex; +/* static */ std::recursive_mutex Telemetry::gStashMutex; +/* static */ std::recursive_mutex Telemetry::gThreadMutex; /* static */ int Telemetry::gThreadRefCount; /* static */ int Telemetry::gProfileClock; -/* static */ HxMutex Telemetry::alloc_mutex; +/* static */ std::recursive_mutex Telemetry::alloc_mutex; /* static */ std::map Telemetry::alloc_map; @@ -483,14 +480,14 @@ void hx::Telemetry::HXTAllocation(void* obj, size_t inSize, const char* type) // ExternalInterface.external_handler()), etc #ifndef HXCPP_PROFILE_EXTERNS if (stack->getCurrentStackFrame()->position->className==hx::EXTERN_CLASS_NAME) { - alloc_mutex.Unlock(); + alloc_mutex.unlock(); return; } #endif int obj_id = __hxt_ptr_id(obj); - alloc_mutex.Lock(); + alloc_mutex.lock(); // HXT debug: Check for id collision #ifdef HXCPP_TELEMETRY_DEBUG @@ -524,7 +521,7 @@ void hx::Telemetry::HXTAllocation(void* obj, size_t inSize, const char* type) //printf("Tracking alloc %s at %016lx, id=%016lx, s=%d for telemetry %016lx, ts=%f\n", type, obj, obj_id, inSize, this, __hxcpp_time_stamp()); - alloc_mutex.Unlock(); + alloc_mutex.unlock(); } void hx::Telemetry::HXTRealloc(void* old_obj, void* new_obj, int new_size) @@ -533,7 +530,7 @@ void hx::Telemetry::HXTRealloc(void* old_obj, void* new_obj, int new_size) int old_obj_id = __hxt_ptr_id(old_obj); int new_obj_id = __hxt_ptr_id(new_obj); - alloc_mutex.Lock(); + alloc_mutex.lock(); // Only track reallocations of objects currently known to be allocated std::map::iterator exist = alloc_map.find(old_obj); @@ -559,7 +556,7 @@ void hx::Telemetry::HXTRealloc(void* old_obj, void* new_obj, int new_size) HXTReclaimInternal(old_obj); // count old as reclaimed } else { //printf("Not tracking re-alloc of untracked %016lx, id=%016lx\n", old_obj, old_obj_id); - alloc_mutex.Unlock(); + alloc_mutex.unlock(); return; } @@ -568,7 +565,7 @@ void hx::Telemetry::HXTRealloc(void* old_obj, void* new_obj, int new_size) //printf("Tracking re-alloc from %016lx, id=%016lx to %016lx, id=%016lx at %f\n", old_obj, old_obj_id, new_obj, new_obj_id, __hxcpp_time_stamp()); - alloc_mutex.Unlock(); + alloc_mutex.unlock(); } } // end namespace hx diff --git a/src/hx/TelemetryTracy.cpp b/src/hx/TelemetryTracy.cpp index 4058ac842..e73d1a4c3 100644 --- a/src/hx/TelemetryTracy.cpp +++ b/src/hx/TelemetryTracy.cpp @@ -1,8 +1,8 @@ #include #include -#include #include +#include namespace { @@ -15,7 +15,7 @@ namespace std::vector created; hx::QuickVec largeAllocs; - HxMutex largeAllocsLock; + std::mutex largeAllocsLock; bool isLargeObject(void* ptr) { @@ -69,7 +69,7 @@ void __hxt_gc_alloc(void* obj, int inSize) #ifdef HXCPP_TRACY_MEMORY if (isLargeObject(obj)) { - AutoLock lock(largeAllocsLock); + std::lock_guard lock(largeAllocsLock); largeAllocs.push(obj); @@ -86,7 +86,7 @@ void __hxt_gc_alloc(void* obj, int inSize) void __hxt_gc_free_large(void* obj) { - AutoLock lock(largeAllocsLock); + std::lock_guard lock(largeAllocsLock); for (auto i = 0; i < largeAllocs.size(); i++) { diff --git a/src/hx/Thread.cpp b/src/hx/Thread.cpp index f8fd39acc..fd885216e 100644 --- a/src/hx/Thread.cpp +++ b/src/hx/Thread.cpp @@ -2,13 +2,14 @@ #include #include +#include +#include +#include DECLARE_TLS_DATA(class hxThreadInfo, tlsCurrentThread); -// g_threadInfoMutex allows atomic access to g_nextThreadNumber -static HxMutex g_threadInfoMutex; // Thread number 0 is reserved for the main thread -static int g_nextThreadNumber = 1; +static std::atomic_int g_nextThreadNumber(1); // How to manage hxThreadInfo references for non haxe threads (main, extenal)? @@ -295,9 +296,7 @@ Dynamic __hxcpp_thread_create(Dynamic inStart) #ifdef EMSCRIPTEN return hx::Throw( HX_CSTRING("Threads are not supported on Emscripten") ); #else - g_threadInfoMutex.Lock(); int threadNumber = g_nextThreadNumber++; - g_threadInfoMutex.Unlock(); hxThreadInfo *info = new hxThreadInfo(inStart, threadNumber); @@ -432,74 +431,27 @@ void __hxcpp_tls_set(int inID,Dynamic inVal) // --- Mutex ------------------------------------------------------------ -class hxMutex : public hx::Object -{ -public: - - hxMutex() - { - mFinalizer = new hx::InternalFinalizer(this); - mFinalizer->mFinalizer = clean; - } - - HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdMutex }; - - #ifdef HXCPP_VISIT_ALLOCS - void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); } - #endif - - hx::InternalFinalizer *mFinalizer; - - static void clean(hx::Object *inObj) - { - hxMutex *m = dynamic_cast(inObj); - if (m) m->mMutex.Clean(); - } - bool Try() - { - return mMutex.TryLock(); - } - void Acquire() - { - hx::EnterGCFreeZone(); - mMutex.Lock(); - hx::ExitGCFreeZone(); - } - void Release() - { - mMutex.Unlock(); - } - - - HxMutex mMutex; -}; - - - Dynamic __hxcpp_mutex_create() { - return new hxMutex; + return new hx::thread::RecursiveMutex_obj(); } void __hxcpp_mutex_acquire(Dynamic inMutex) { - hxMutex *mutex = dynamic_cast(inMutex.mPtr); - if (!mutex) - throw HX_INVALID_OBJECT; - mutex->Acquire(); + auto mutex = inMutex.Cast(); + + mutex->acquire(); } bool __hxcpp_mutex_try(Dynamic inMutex) { - hxMutex *mutex = dynamic_cast(inMutex.mPtr); - if (!mutex) - throw HX_INVALID_OBJECT; - return mutex->Try(); + auto mutex = inMutex.Cast(); + + return mutex->tryAcquire(); } void __hxcpp_mutex_release(Dynamic inMutex) { - hxMutex *mutex = dynamic_cast(inMutex.mPtr); - if (!mutex) - throw HX_INVALID_OBJECT; - return mutex->Release(); + auto mutex = inMutex.Cast(); + + mutex->release(); } #if defined(HX_LINUX) || defined(HX_ANDROID) @@ -634,197 +586,49 @@ void __hxcpp_semaphore_release(Dynamic inSemaphore) { semaphore->Release(); } -class hxCondition : public hx::Object { -public: -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - CRITICAL_SECTION cs; - CONDITION_VARIABLE cond; -#endif -#else - pthread_cond_t *cond; - pthread_mutex_t *mutex; -#endif - hx::InternalFinalizer *mFinalizer; - hxCondition() { - mFinalizer = new hx::InternalFinalizer(this); - mFinalizer->mFinalizer = clean; -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - InitializeCriticalSection(&cs); - InitializeConditionVariable(&cond); -#else - throw Dynamic(HX_CSTRING("Condition variables are not supported on Windows XP")); -#endif -#else - pthread_condattr_t cond_attr; - pthread_condattr_init(&cond_attr); - cond = new pthread_cond_t(); - pthread_cond_init(cond, &cond_attr); - pthread_condattr_destroy(&cond_attr); - pthread_mutexattr_t mutex_attr; - pthread_mutexattr_init(&mutex_attr); - mutex = new pthread_mutex_t(); - pthread_mutex_init(mutex, &mutex_attr); - pthread_mutexattr_destroy(&mutex_attr); -#endif - } - - HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdCondition }; - -#ifdef HXCPP_VISIT_ALLOCS - void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); } -#endif - static void clean(hx::Object *inObj) { - hxCondition *cond = dynamic_cast(inObj); - if (cond) { -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - DeleteCriticalSection(&cond->cs); -#endif -#else - pthread_cond_destroy(cond->cond); - delete cond->cond; - pthread_mutex_destroy(cond->mutex); - delete cond->mutex; -#endif - } - } - - void Acquire() { - hx::EnterGCFreeZone(); -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - EnterCriticalSection(&cs); -#endif -#else - pthread_mutex_lock(mutex); -#endif - hx::ExitGCFreeZone(); - } - - bool TryAcquire() { -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - return (bool)TryEnterCriticalSection(&cs); -#else - return false; -#endif -#else - return pthread_mutex_trylock(mutex); -#endif - } - - void Release() { -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - LeaveCriticalSection(&cs); -#endif -#else - pthread_mutex_unlock(mutex); -#endif - } - - void Wait() { - hx::EnterGCFreeZone(); -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - SleepConditionVariableCS(&cond,&cs,INFINITE); -#endif -#else - pthread_cond_wait(cond, mutex); -#endif - hx::ExitGCFreeZone(); - } - - bool TimedWait(double timeout) { - hx::AutoGCFreeZone blocking; -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - return (bool)SleepConditionVariableCS(&cond, &cs, (DWORD)((FLOAT)timeout * 1000.0)); -#else - return false; -#endif -#else - struct timeval tv; - struct timespec t; - double delta = timeout; - int idelta = (int)delta, idelta2; - delta -= idelta; - delta *= 1.0e9; - gettimeofday(&tv, NULL); - delta += tv.tv_usec * 1000.0; - idelta2 = (int)(delta / 1e9); - delta -= idelta2 * 1e9; - t.tv_sec = tv.tv_sec + idelta + idelta2; - t.tv_nsec = (long)delta; - return pthread_cond_timedwait(cond, mutex, &t); -#endif - } - void Signal() { -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - WakeConditionVariable(&cond); -#endif -#else - pthread_cond_signal(cond); -#endif - } - void Broadcast() { -#ifdef HX_WINDOWS -#ifndef HXCPP_WINXP_COMPAT - WakeAllConditionVariable(&cond); -#endif -#else - pthread_cond_broadcast(cond); -#endif - } -}; - -Dynamic __hxcpp_condition_create(void) { - return new hxCondition; +Dynamic __hxcpp_condition_create(void) +{ + return new hx::thread::ConditionVariable_obj(); } -void __hxcpp_condition_acquire(Dynamic inCond) { - hxCondition *cond = dynamic_cast(inCond.mPtr); - if (!cond) - throw HX_INVALID_OBJECT; - cond->Acquire(); +void __hxcpp_condition_acquire(Dynamic inCond) +{ + auto condition = inCond.Cast(); + + condition->acquire(); } -bool __hxcpp_condition_try_acquire(Dynamic inCond) { - hxCondition *cond = dynamic_cast(inCond.mPtr); - if (!cond) - throw HX_INVALID_OBJECT; - return cond->TryAcquire(); +bool __hxcpp_condition_try_acquire(Dynamic inCond) +{ + auto condition = inCond.Cast(); + + return condition->tryAcquire(); } -void __hxcpp_condition_release(Dynamic inCond) { - hxCondition *cond = dynamic_cast(inCond.mPtr); - if (!cond) - throw HX_INVALID_OBJECT; - cond->Release(); +void __hxcpp_condition_release(Dynamic inCond) +{ + auto condition = inCond.Cast(); + + condition->release(); } -void __hxcpp_condition_wait(Dynamic inCond) { - hxCondition *cond = dynamic_cast(inCond.mPtr); - if (!cond) - throw HX_INVALID_OBJECT; - cond->Wait(); +void __hxcpp_condition_wait(Dynamic inCond) +{ + auto condition = inCond.Cast(); + + condition->wait(); } -bool __hxcpp_condition_timed_wait(Dynamic inCond, double timeout) { - hxCondition *cond = dynamic_cast(inCond.mPtr); - if (!cond) - throw HX_INVALID_OBJECT; - return cond->TimedWait(timeout); +bool __hxcpp_condition_timed_wait(Dynamic inCond, double timeout) +{ + return hx::Throw(HX_CSTRING("Not Implemented")); } -void __hxcpp_condition_signal(Dynamic inCond) { - hxCondition *cond = dynamic_cast(inCond.mPtr); - if (!cond) - throw HX_INVALID_OBJECT; - cond->Signal(); +void __hxcpp_condition_signal(Dynamic inCond) +{ + auto condition = inCond.Cast(); + + condition->signal(); } -void __hxcpp_condition_broadcast(Dynamic inCond) { - hxCondition *cond = dynamic_cast(inCond.mPtr); - if (!cond) - throw HX_INVALID_OBJECT; - cond->Broadcast(); +void __hxcpp_condition_broadcast(Dynamic inCond) +{ + auto condition = inCond.Cast(); + + condition->broadcast(); } // --- Lock ------------------------------------------------------------ diff --git a/src/hx/gc/Immix.cpp b/src/hx/gc/Immix.cpp index 3cb68b8dd..0f7b41c6b 100644 --- a/src/hx/gc/Immix.cpp +++ b/src/hx/gc/Immix.cpp @@ -6,6 +6,8 @@ #include "../Hash.h" #include "GcRegCapture.h" #include +#include +#include #ifdef EMSCRIPTEN #include @@ -392,8 +394,8 @@ static int sgTimeToNextTableUpdate = 1; -HxMutex *gThreadStateChangeLock=0; -HxMutex *gSpecialObjectLock=0; +std::mutex *gThreadStateChangeLock=nullptr; +std::mutex *gSpecialObjectLock=nullptr; class LocalAllocator; enum LocalAllocState { lasNew, lasRunning, lasStopped, lasWaiting, lasTerminal }; @@ -570,24 +572,7 @@ enum AllocType { allocNone, allocString, allocObject, allocMarked }; struct BlockDataInfo *gBlockStack = 0; typedef hx::QuickVec ObjectStack; - -typedef HxMutex ThreadPoolLock; - -static ThreadPoolLock sThreadPoolLock; - -#if !defined(HX_WINDOWS) && !defined(EMSCRIPTEN) && \ - !defined(__SNC__) && !defined(__ORBIS__) -#define HX_GC_PTHREADS -typedef pthread_cond_t ThreadPoolSignal; -inline void WaitThreadLocked(ThreadPoolSignal &ioSignal) -{ - pthread_cond_wait(&ioSignal, sThreadPoolLock.mMutex); -} -#else -typedef HxSemaphore ThreadPoolSignal; -#endif - -typedef TAutoLock ThreadPoolAutoLock; +static std::mutex sThreadPoolLock; // For threaded marking/block reclaiming static unsigned int sRunningThreads = 0; @@ -614,20 +599,16 @@ static bool sgThreadPoolAbort = false; // Pthreads enters the sleep state while holding a mutex, so it no cost to update // the sleeping state and thereby avoid over-signalling the condition -bool sThreadSleeping[MAX_GC_THREADS]; -ThreadPoolSignal sThreadWake[MAX_GC_THREADS]; -bool sThreadJobDoneSleeping = false; -ThreadPoolSignal sThreadJobDone; +bool sThreadSleeping[MAX_GC_THREADS]; +std::condition_variable_any* sThreadWake[MAX_GC_THREADS]; +bool sThreadJobDoneSleeping = false; +std::condition_variable_any* sThreadJobDone; -static inline void SignalThreadPool(ThreadPoolSignal &ioSignal, bool sThreadSleeping) +static inline void SignalThreadPool(std::condition_variable_any* ioSignal, bool sThreadSleeping) { - #ifdef HX_GC_PTHREADS - if (sThreadSleeping) - pthread_cond_signal(&ioSignal); - #else - ioSignal.Set(); - #endif + if (sThreadSleeping) + ioSignal->notify_one(); } static void wakeThreadLocked(int inThreadId) @@ -1555,7 +1536,7 @@ struct GlobalChunks if (MAX_GC_THREADS>1 && sLazyThreads) { - ThreadPoolAutoLock l(sThreadPoolLock); + std::lock_guard l(sThreadPoolLock); #ifdef PROFILE_THREAD_USAGE #define CHECK_THREAD_WAKE(tid) \ @@ -1729,7 +1710,7 @@ struct GlobalChunks return result; } } - ThreadPoolAutoLock l(sThreadPoolLock); + std::lock_guard l(sThreadPoolLock); completeThreadLocked(inThreadId); } return result; @@ -2386,7 +2367,7 @@ void MarkStringArray(String *inPtr, int inLength, hx::MarkContext *__inCtx) // --- Roots ------------------------------- -FILE_SCOPE HxMutex *sGCRootLock = 0; +FILE_SCOPE std::mutex* sGCRootLock = nullptr; typedef hx::UnorderedSet RootSet; static RootSet sgRootSet; @@ -2395,20 +2376,20 @@ static OffsetRootSet *sgOffsetRootSet=0; void GCAddRoot(hx::Object **inRoot) { - AutoLock lock(*sGCRootLock); + std::lock_guard lock(*sGCRootLock); sgRootSet.insert(inRoot); } void GCRemoveRoot(hx::Object **inRoot) { - AutoLock lock(*sGCRootLock); + std::lock_guard lock(*sGCRootLock); sgRootSet.erase(inRoot); } void GcAddOffsetRoot(void *inRoot, int inOffset) { - AutoLock lock(*sGCRootLock); + std::lock_guard lock(*sGCRootLock); if (!sgOffsetRootSet) sgOffsetRootSet = new OffsetRootSet(); (*sgOffsetRootSet)[inRoot] = inOffset; @@ -2416,13 +2397,13 @@ void GcAddOffsetRoot(void *inRoot, int inOffset) void GcSetOffsetRoot(void *inRoot, int inOffset) { - AutoLock lock(*sGCRootLock); + std::lock_guard lock(*sGCRootLock); (*sgOffsetRootSet)[inRoot] = inOffset; } void GcRemoveOffsetRoot(void *inRoot) { - AutoLock lock(*sGCRootLock); + std::lock_guard lock(*sGCRootLock); OffsetRootSet::iterator r = sgOffsetRootSet->find(inRoot); sgOffsetRootSet->erase(r); } @@ -2436,7 +2417,7 @@ void GcRemoveOffsetRoot(void *inRoot) class WeakRef; typedef hx::QuickVec WeakRefs; -FILE_SCOPE HxMutex *sFinalizerLock = 0; +FILE_SCOPE std::mutex *sFinalizerLock = 0; FILE_SCOPE WeakRefs sWeakRefs; class WeakRef : public hx::Object @@ -2449,9 +2430,8 @@ class WeakRef : public hx::Object mRef = inRef; if (mRef.mPtr) { - sFinalizerLock->Lock(); + std::lock_guard lock(*sFinalizerLock); sWeakRefs.push(this); - sFinalizerLock->Unlock(); } } @@ -2500,7 +2480,7 @@ InternalFinalizer::InternalFinalizer(hx::Object *inObj, finalizer inFinalizer) mFinalizer = inFinalizer; // Ensure this survives generational collect - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); sgFinalizers->push(this); } @@ -2797,7 +2777,7 @@ void GCSetFinalizer( hx::Object *obj, hx::finalizer f ) if (((unsigned int *)obj)[-1] & HX_GC_CONST_ALLOC_BIT) throw Dynamic(HX_CSTRING("set_finalizer - invalid const object")); - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); if (f==0) { FinalizerMap::iterator i = sFinalizerMap.find(obj); @@ -2817,7 +2797,7 @@ void GCSetHaxeFinalizer( hx::Object *obj, HaxeFinalizer f ) if (((unsigned int *)obj)[-1] & HX_GC_CONST_ALLOC_BIT) throw Dynamic(HX_CSTRING("set_finalizer - invalid const object")); - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); if (f==0) { HaxeFinalizerMap::iterator i = sHaxeFinalizerMap.find(obj); @@ -2835,13 +2815,13 @@ void GCDoNotKill(hx::Object *inObj) if (((unsigned int *)inObj)[-1] & HX_GC_CONST_ALLOC_BIT) throw Dynamic(HX_CSTRING("doNotKill - invalid const object")); - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); sMakeZombieSet.insert(inObj); } hx::Object *GCGetNextZombie() { - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); if (sZombieList.empty()) return 0; hx::Object *result = sZombieList.pop(); @@ -2850,13 +2830,13 @@ hx::Object *GCGetNextZombie() void RegisterWeakHash(HashBase *inHash) { - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); sWeakHashList.push(inHash); } void RegisterWeakHash(HashBase *inHash) { - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); sWeakHashList.push(inHash); } @@ -3153,12 +3133,12 @@ class GlobalAllocator { if (!gThreadStateChangeLock) { - gThreadStateChangeLock = new HxMutex(); - gSpecialObjectLock = new HxMutex(); + gThreadStateChangeLock = new std::mutex(); + gSpecialObjectLock = new std::mutex(); } // Until we add ourselves, the collector will not wait // on us - ie, we are assumed ot be in a GC free zone. - AutoLock lock(*gThreadStateChangeLock); + std::lock_guard lock(*gThreadStateChangeLock); mLocalAllocs.push(inAlloc); // TODO Attach debugger } @@ -3181,7 +3161,7 @@ class GlobalAllocator LocalAllocator *GetPooledAllocator() { - AutoLock lock(*gThreadStateChangeLock); + std::lock_guard lock(*gThreadStateChangeLock); for(int p=0;p=largeObjectRecycle.size() || largeObjectRecycle[i][0] != inSize ) continue; @@ -3295,7 +3275,7 @@ class GlobalAllocator if (isLocked) { - mLargeListLock.Unlock(); + mLargeListLock.unlock(); isLocked = false; } @@ -3320,13 +3300,13 @@ class GlobalAllocator #endif if (do_lock && !isLocked) - mLargeListLock.Lock(); + mLargeListLock.lock(); mLargeList.push(result); mLargeAllocated += inSize; if (do_lock) - mLargeListLock.Unlock(); + mLargeListLock.unlock(); #ifdef HXCPP_TELEMETRY __hxt_gc_alloc(result + 2, inSize); @@ -3363,12 +3343,12 @@ class GlobalAllocator #endif if (do_lock) - mLargeListLock.Lock(); + mLargeListLock.lock(); mLargeAllocated += inDelta; if (do_lock) - mLargeListLock.Unlock(); + mLargeListLock.unlock(); } // Gets a block with the 'zeroLock' acquired, which means the zeroing thread @@ -3614,7 +3594,7 @@ class GlobalAllocator #ifndef HXCPP_SINGLE_THREADED_APP hx::EnterGCFreeZone(); - gThreadStateChangeLock->Lock(); + gThreadStateChangeLock->lock(); hx::ExitGCFreeZoneLocked(); result = GetNextFree(inRequiredBytes); @@ -3663,7 +3643,7 @@ class GlobalAllocator mCurrentRowsInUse += result->GetFreeRows(); #ifndef HXCPP_SINGLE_THREADED_APP - gThreadStateChangeLock->Unlock(); + gThreadStateChangeLock->unlock(); #endif @@ -4214,7 +4194,7 @@ class GlobalAllocator void *GetIDObject(int inIndex) { - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); if (inIndex<0 || inIndex>hx::sIdObjectMap.size()) return 0; return hx::sIdObjectMap[inIndex]; @@ -4222,7 +4202,7 @@ class GlobalAllocator int GetObjectID(void * inPtr) { - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); hx::ObjectIdMap::iterator i = hx::sObjectIdMap.find( (hx::Object *)inPtr ); if (i!=hx::sObjectIdMap.end()) return i->second; @@ -4441,7 +4421,7 @@ class GlobalAllocator if (mZeroListQueue + mThreadJobId < mZeroList.size()) { // Wake zeroing thread - ThreadPoolAutoLock l(sThreadPoolLock); + std::lock_guard l(sThreadPoolLock); if (!(sRunningThreads & 0x01)) { #ifdef PROFILE_THREAD_USAGE @@ -4456,7 +4436,7 @@ class GlobalAllocator void finishThreadJob(int inId) { - ThreadPoolAutoLock l(sThreadPoolLock); + std::lock_guard l(sThreadPoolLock); if (sRunningThreads & (1< l(sThreadPoolLock); + int count = 0; - // May be woken multiple times if sRunningThreads is set to 0 then 1 before we sleep - sThreadSleeping[inId] = true; - // Spurious wake? - while( !(sRunningThreads & (1<wait(sThreadPoolLock, [&inId]() { return sRunningThreads & (1 << inId); }); + + sThreadSleeping[inId] = false; } @@ -4552,19 +4525,18 @@ class GlobalAllocator { void *info = (void *)(size_t)inId; - #ifdef HX_GC_PTHREADS - pthread_cond_init(&sThreadWake[inId],0); - sThreadSleeping[inId] = false; - if (inId==0) - pthread_cond_init(&sThreadJobDone,0); - - pthread_t result = 0; - int created = pthread_create(&result,0,SThreadLoop,info); - bool ok = created==0; - #elif defined(EMSCRIPTEN) + #if defined(EMSCRIPTEN) // Only one thread #else - bool ok = HxCreateDetachedThread(SThreadLoop, info); + sThreadWake[inId] = new std::condition_variable_any(); + if (0 == inId) + { + sThreadJobDone = new std::condition_variable_any(); + } + + sThreadSleeping[inId] = false; + + HxCreateDetachedThread(SThreadLoop, info); #endif } @@ -4579,7 +4551,7 @@ class GlobalAllocator sgThreadPoolAbort = true; if (sgThreadPoolJob==tpjAsyncZeroJit) { - ThreadPoolAutoLock l(sThreadPoolLock); + std::lock_guard l(sThreadPoolLock); // Thread will be waiting, but not finished if (sRunningThreads & 0x1) { @@ -4591,16 +4563,10 @@ class GlobalAllocator } - #ifdef HX_GC_PTHREADS - ThreadPoolAutoLock lock(sThreadPoolLock); + std::lock_guard l(sThreadPoolLock); sThreadJobDoneSleeping = true; - while(sRunningThreads) - WaitThreadLocked(sThreadJobDone); + sThreadJobDone->wait(sThreadPoolLock, []() { return sRunningThreads == false; }); sThreadJobDoneSleeping = false; - #else - while(sRunningThreads) - sThreadJobDone.Wait(); - #endif sgThreadPoolAbort = false; sAllThreads = 0; sgThreadPoolJob = tpjNone; @@ -4623,10 +4589,7 @@ class GlobalAllocator CreateWorker(i); } - #ifdef HX_GC_PTHREADS - ThreadPoolAutoLock lock(sThreadPoolLock); - #endif - + std::lock_guard l(sThreadPoolLock); sgThreadPoolJob = inJob; @@ -4646,15 +4609,9 @@ class GlobalAllocator if (inWait) { // Join the workers... - #ifdef HX_GC_PTHREADS sThreadJobDoneSleeping = true; - while(sRunningThreads) - WaitThreadLocked(sThreadJobDone); + sThreadJobDone->wait(sThreadPoolLock, []() { return sRunningThreads == false; }); sThreadJobDoneSleeping = false; - #else - while(sRunningThreads) - sThreadJobDone.Wait(); - #endif sAllThreads = 0; sgThreadPoolJob = tpjNone; @@ -4864,12 +4821,12 @@ class GlobalAllocator { if (inLocked) { - gThreadStateChangeLock->Unlock(); + gThreadStateChangeLock->unlock(); hx::PauseForCollect(); hx::EnterGCFreeZone(); - gThreadStateChangeLock->Lock(); + gThreadStateChangeLock->lock(); hx::ExitGCFreeZoneLocked(); } else @@ -4888,7 +4845,7 @@ class GlobalAllocator this_local = (LocalAllocator *)(hx::ImmixAllocator *)hx::tlsStackContext; if (!inLocked) - gThreadStateChangeLock->Lock(); + gThreadStateChangeLock->lock(); for(int i=0;iUnlock(); + gThreadStateChangeLock->unlock(); #else #ifdef HXCPP_SCRIPTABLE hx::gMainThreadContext->byteMarkId = hx::gByteMarkID; @@ -5623,7 +5580,7 @@ class GlobalAllocator volatile int mZeroListQueue; LargeList mLargeList; - HxMutex mLargeListLock; + std::mutex mLargeListLock; hx::QuickVec mLocalAllocs; LocalAllocator *mLocalPool[LOCAL_POOL_SIZE]; hx::QuickVec largeObjectRecycle; @@ -5900,7 +5857,7 @@ class LocalAllocator : public hx::StackContext EnterGCFreeZone(); #endif - AutoLock lock(*gThreadStateChangeLock); + std::lock_guard lock(*gThreadStateChangeLock); #ifdef HX_WINDOWS mID = 0; @@ -6127,7 +6084,7 @@ class LocalAllocator : public hx::StackContext if (!mGCFreeZone) CriticalGCError("GCFree Zone mismatch"); - AutoLock lock(*gThreadStateChangeLock); + std::lock_guard lock(*gThreadStateChangeLock); mReadyForCollect.Reset(); mGCFreeZone = false; #endif @@ -6603,8 +6560,8 @@ void InitAlloc() sgAllocInit = true; sGlobalAlloc = new GlobalAllocator(); sgFinalizers = new FinalizerList(); - sFinalizerLock = new HxMutex(); - sGCRootLock = new HxMutex(); + sFinalizerLock = new std::mutex(); + sGCRootLock = new std::mutex(); hx::Object tmp; void **stack = *(void ***)(&tmp); sgObject_root = stack[0]; @@ -7039,13 +6996,13 @@ void __hxcpp_set_finalizer(Dynamic inObj, void *inFunc) void __hxcpp_add_member_finalizer(hx::Object *inObject, _hx_member_finalizer f, bool inPin) { - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); hx::sFinalizableList.push( hx::Finalizable(inObject, f, inPin) ); } void __hxcpp_add_alloc_finalizer(void *inAlloc, _hx_alloc_finalizer f, bool inPin) { - AutoLock lock(*gSpecialObjectLock); + std::lock_guard lock(*gSpecialObjectLock); hx::sFinalizableList.push( hx::Finalizable(inAlloc, f, inPin) ); } diff --git a/src/hx/thread/ConditionVariable.cpp b/src/hx/thread/ConditionVariable.cpp new file mode 100644 index 000000000..3bfe2c1a4 --- /dev/null +++ b/src/hx/thread/ConditionVariable.cpp @@ -0,0 +1,55 @@ +#include +#include "hx/thread/ConditionVariable.hpp" +#include +#include +#include + +struct hx::thread::ConditionVariable_obj::Impl +{ + std::mutex mutex; + std::condition_variable_any condition; +}; + +hx::thread::ConditionVariable_obj::ConditionVariable_obj() : impl(new Impl()) +{ + GCSetFinalizer(this, [](hx::Object* obj) + { + auto condition = reinterpret_cast(obj); + + delete condition->impl; + }); +} + +void hx::thread::ConditionVariable_obj::acquire() +{ + hx::AutoGCFreeZone zone; + + impl->mutex.lock(); +} + +bool hx::thread::ConditionVariable_obj::tryAcquire() +{ + return impl->mutex.try_lock(); +} + +void hx::thread::ConditionVariable_obj::release() +{ + impl->mutex.unlock(); +} + +void hx::thread::ConditionVariable_obj::wait() +{ + hx::AutoGCFreeZone zone; + + impl->condition.wait(impl->mutex); +} + +void hx::thread::ConditionVariable_obj::signal() +{ + impl->condition.notify_one(); +} + +void hx::thread::ConditionVariable_obj::broadcast() +{ + impl->condition.notify_all(); +} diff --git a/src/hx/thread/RecursiveMutex.cpp b/src/hx/thread/RecursiveMutex.cpp new file mode 100644 index 000000000..67a141e21 --- /dev/null +++ b/src/hx/thread/RecursiveMutex.cpp @@ -0,0 +1,35 @@ +#include +#include "hx/thread/RecursiveMutex.hpp" +#include + +struct hx::thread::RecursiveMutex_obj::Impl +{ + std::recursive_mutex mutex; +}; + +hx::thread::RecursiveMutex_obj::RecursiveMutex_obj() : impl(new Impl()) +{ + GCSetFinalizer(this, [](hx::Object* obj) + { + auto mutex = reinterpret_cast(obj); + + delete mutex->impl; + }); +} + +void hx::thread::RecursiveMutex_obj::acquire() +{ + hx::AutoGCFreeZone zone; + + impl->mutex.lock(); +} + +void hx::thread::RecursiveMutex_obj::release() +{ + impl->mutex.unlock(); +} + +bool hx::thread::RecursiveMutex_obj::tryAcquire() +{ + return impl->mutex.try_lock(); +} diff --git a/toolchain/haxe-target.xml b/toolchain/haxe-target.xml index 09d933727..11dd88576 100644 --- a/toolchain/haxe-target.xml +++ b/toolchain/haxe-target.xml @@ -75,6 +75,8 @@ + +
@@ -206,6 +208,9 @@ + + +