From e95c6d655331df4403faa8d13b4d79ecf367965a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 8 Mar 2026 14:31:33 +0000 Subject: [PATCH 1/4] wip semaphores --- include/hx/thread/CountingSemaphore.hpp | 27 ++++ src/hx/Thread.cpp | 136 ++---------------- src/hx/thread/CountingSemaphore.apple.cpp | 44 ++++++ src/hx/thread/CountingSemaphore.posix.cpp | 85 +++++++++++ .../thread/CountingSemaphore.unsupported.cpp | 23 +++ src/hx/thread/CountingSemaphore.win32.cpp | 62 ++++++++ toolchain/haxe-target.xml | 17 ++- 7 files changed, 270 insertions(+), 124 deletions(-) create mode 100644 include/hx/thread/CountingSemaphore.hpp create mode 100644 src/hx/thread/CountingSemaphore.apple.cpp create mode 100644 src/hx/thread/CountingSemaphore.posix.cpp create mode 100644 src/hx/thread/CountingSemaphore.unsupported.cpp create mode 100644 src/hx/thread/CountingSemaphore.win32.cpp diff --git a/include/hx/thread/CountingSemaphore.hpp b/include/hx/thread/CountingSemaphore.hpp new file mode 100644 index 000000000..34deb5545 --- /dev/null +++ b/include/hx/thread/CountingSemaphore.hpp @@ -0,0 +1,27 @@ +#pragma once + +#ifndef HXCPP_H +#include +#endif + +HX_DECLARE_CLASS2(hx, thread, CountingSemaphore) + +namespace hx +{ + namespace thread + { + struct CountingSemaphore_obj : public hx::Object + { + CountingSemaphore_obj(int value); + + void acquire(); + void release(); + bool tryAcquire(Null timeout); + + private: + struct Impl; + + Impl* impl; + }; + } +} \ No newline at end of file diff --git a/src/hx/Thread.cpp b/src/hx/Thread.cpp index fd885216e..f5eae2a36 100644 --- a/src/hx/Thread.cpp +++ b/src/hx/Thread.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include DECLARE_TLS_DATA(class hxThreadInfo, tlsCurrentThread); @@ -454,138 +455,29 @@ void __hxcpp_mutex_release(Dynamic inMutex) mutex->release(); } -#if defined(HX_LINUX) || defined(HX_ANDROID) -#define POSIX_SEMAPHORE -#include -#endif - -#if defined(HX_MACOS) || defined(IPHONE) || defined(APPLETV) -#define APPLE_SEMAPHORE -#include -#endif - -class hxSemaphore : public hx::Object { -public: - hx::InternalFinalizer *mFinalizer; -#ifdef HX_WINDOWS - HANDLE sem; -#elif defined (POSIX_SEMAPHORE) - sem_t sem; -#elif defined(APPLE_SEMAPHORE) - dispatch_semaphore_t sem; -#endif - bool valid; - - hxSemaphore(int value) { - mFinalizer = new hx::InternalFinalizer(this); - mFinalizer->mFinalizer = clean; -#ifdef HX_WINDOWS - sem = CreateSemaphoreW(NULL, value, 0x7FFFFFFF, NULL); -#elif defined(POSIX_SEMAPHORE) - sem_init(&sem, 0, value); -#elif defined(APPLE_SEMAPHORE) - sem = dispatch_semaphore_create(value); -#endif - valid = true; - } - - HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSemaphore }; - -#ifdef HXCPP_VISIT_ALLOCS - void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); } -#endif - - void Acquire() { - hx::EnterGCFreeZone(); -#if HX_WINDOWS - WaitForSingleObject(sem, INFINITE); -#elif defined(POSIX_SEMAPHORE) - sem_wait(&sem); -#elif defined(APPLE_SEMAPHORE) - dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); -#endif - hx::ExitGCFreeZone(); - } - - bool TryAcquire(double timeout) { - hx::AutoGCFreeZone blocking; -#ifdef HX_WINDOWS - return WaitForSingleObject(sem, (DWORD)((FLOAT)timeout * 1000.0)) == 0; -#elif defined(POSIX_SEMAPHORE) - if (timeout == 0) { - return sem_trywait(&sem) == 0; - } 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 sem_timedwait(&sem, &t) == 0; - } -#elif defined(APPLE_SEMAPHORE) - return dispatch_semaphore_wait( - sem, - dispatch_time(DISPATCH_TIME_NOW, - (int64_t)(timeout * 1000 * 1000 * 1000))) == 0; -#else - return false; -#endif - } - - void Release() { -#if HX_WINDOWS - ReleaseSemaphore(sem, 1, NULL); -#elif defined(POSIX_SEMAPHORE) - sem_post(&sem); -#elif defined(APPLE_SEMAPHORE) - dispatch_semaphore_signal(sem); -#endif - } - - static void clean(hx::Object *inObj) { - hxSemaphore *l = dynamic_cast(inObj); - if (l) { - if(l->valid) { -#ifdef HX_WINDOWS - CloseHandle(l->sem); -#elif defined(POSIX_SEMAPHORE) - sem_destroy(&l->sem); -#endif - l->valid = false; - } - } - } -}; +// --- Semaphore ------------------------------------------------------------ Dynamic __hxcpp_semaphore_create(int value) { - return new hxSemaphore(value); + return new hx::thread::CountingSemaphore_obj(value); } void __hxcpp_semaphore_acquire(Dynamic inSemaphore) { - hxSemaphore *semaphore = dynamic_cast(inSemaphore.mPtr); - if (!semaphore) - throw HX_INVALID_OBJECT; - semaphore->Acquire(); + auto semaphore = inSemaphore.Cast(); + + semaphore->acquire(); } bool __hxcpp_semaphore_try_acquire(Dynamic inSemaphore, double timeout) { - hxSemaphore *semaphore = dynamic_cast(inSemaphore.mPtr); - if (!semaphore) - throw HX_INVALID_OBJECT; - return semaphore->TryAcquire(timeout); + auto semaphore = inSemaphore.Cast(); + + return semaphore->tryAcquire(timeout); } void __hxcpp_semaphore_release(Dynamic inSemaphore) { - hxSemaphore *semaphore = dynamic_cast(inSemaphore.mPtr); - if (!semaphore) - throw HX_INVALID_OBJECT; - semaphore->Release(); + auto semaphore = inSemaphore.Cast(); + + semaphore->release(); } +// --- Condition ------------------------------------------------------------ + Dynamic __hxcpp_condition_create(void) { return new hx::thread::ConditionVariable_obj(); diff --git a/src/hx/thread/CountingSemaphore.apple.cpp b/src/hx/thread/CountingSemaphore.apple.cpp new file mode 100644 index 000000000..8f0cacfe1 --- /dev/null +++ b/src/hx/thread/CountingSemaphore.apple.cpp @@ -0,0 +1,44 @@ +#include +#include + +struct hx::thread::CountingSemaphore_obj::Impl +{ + dispatch_semaphore_t semaphore; + + static void finalise(hx::Object* obj) + { + delete reinterpret_cast(obj)->impl; + } +}; + +hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(new Impl()) +{ + impl->semaphore = dispatch_semaphore_create(value); + + hx::GCSetFinalizer(this, Impl::finalise); +} + +void hx::thread::CountingSemaphore_obj::acquire() +{ + hx::AutoGCFreeZone zone; + + if (0 != (dispatch_semaphore_wait(impl->semaphore, DISPATCH_TIME_FOREVER))) + { + hx::Throw(HX_CSTRING("Failed to wait for semaphore")); + } +} + +void hx::thread::CountingSemaphore_obj::release() +{ + dispatch_semaphore_signal(impl->semaphore); +} + +bool hx::thread::CountingSemaphore_obj::tryAcquire(Null timeout) +{ + hx::AutoGCFreeZone zone; + + return + (0 = dispatch_semaphore_wait( + impl->semaphore, + dispatch_time(DISPATCH_TIME_NOW, static_cast(timeout.Default(0)) * 1000 * 1000 * 1000))); +} \ No newline at end of file diff --git a/src/hx/thread/CountingSemaphore.posix.cpp b/src/hx/thread/CountingSemaphore.posix.cpp new file mode 100644 index 000000000..87294dbf4 --- /dev/null +++ b/src/hx/thread/CountingSemaphore.posix.cpp @@ -0,0 +1,85 @@ +#include +#include +#include +#include +#include + +struct hx::thread::CountingSemaphore_obj::Impl +{ + sem_t semaphore; + + static void finalise(hx::Object* obj) + { + auto impl = std::unique_ptr(reinterpret_cast(obj)->impl); + + sem_destroy(&impl->semaphore); + } +}; + +hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(new Impl()) +{ + if (0 != (sem_init(&impl->semaphore, false, 3))) + { + hx::Throw(HX_CSTRING("Failed to create semaphore")); + } + + hx::GCSetFinalizer(this, Impl::finalise); +} + +void hx::thread::CountingSemaphore_obj::acquire() +{ + hx::EnterGCFreeZone(); + + if (0 != sem_wait(&impl->semaphore)) + { + hx::Throw(HX_CSTRING("Failed to wait on semaphore")); + } + + hx::ExitGCFreeZone(); +} + +void hx::thread::CountingSemaphore_obj::release() +{ + if (0 != sem_post(&impl->semaphore)) + { + hx::Throw(HX_CSTRING("Failed to release semaphore")); + } +} + +bool hx::thread::CountingSemaphore_obj::tryAcquire(Null timeout) +{ + if (0 == timeout.Default(0)) + { + return 0 == sem_trywait(&impl->semaphore); + } + else + { + hx::EnterGCFreeZone(); + + struct timeval tv; + struct timespec t; + auto delta = timeout.value; + 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; + + switch (sem_timedwait(&impl->semaphore, &t)) + { + case 0: + hx::ExitGCFreeZone(); + return true; + case ETIMEDOUT: + hx::ExitGCFreeZone(); + return false; + default: + hx::ExitGCFreeZone(); + return hx::Throw(HX_CSTRING("Failed to wait for semaphore")); + } + } +} \ No newline at end of file diff --git a/src/hx/thread/CountingSemaphore.unsupported.cpp b/src/hx/thread/CountingSemaphore.unsupported.cpp new file mode 100644 index 000000000..fe8e42aa7 --- /dev/null +++ b/src/hx/thread/CountingSemaphore.unsupported.cpp @@ -0,0 +1,23 @@ +#include +#include + +struct hx::thread::CountingSemaphore_obj::Impl {}; + +hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(nullptr) {} + +void hx::thread::CountingSemaphore_obj::acquire() +{ + hx::Throw(HX_CSTRING("Unsupported platform")); +} + +void hx::thread::CountingSemaphore_obj::release() +{ + hx::Throw(HX_CSTRING("Unsupported platform")); +} + +bool hx::thread::CountingSemaphore_obj::tryAcquire(Null timeout) +{ + hx::Throw(HX_CSTRING("Unsupported platform")); + + return false; +} \ No newline at end of file diff --git a/src/hx/thread/CountingSemaphore.win32.cpp b/src/hx/thread/CountingSemaphore.win32.cpp new file mode 100644 index 000000000..e158a6b56 --- /dev/null +++ b/src/hx/thread/CountingSemaphore.win32.cpp @@ -0,0 +1,62 @@ +#include +#include +#include +#include + +struct hx::thread::CountingSemaphore_obj::Impl +{ + HANDLE semaphore; + + static void finalise(hx::Object* obj) + { + auto impl = std::unique_ptr(reinterpret_cast(obj)->impl); + + CloseHandle(impl->semaphore); + } +}; + +hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(new Impl()) +{ + if (nullptr == (impl->semaphore = CreateSemaphoreW(nullptr, value, 0x7FFFFFF, nullptr))) + { + hx::Throw(HX_CSTRING("Failed to create semaphore")); + } + + hx::GCSetFinalizer(this, Impl::finalise); +} + +void hx::thread::CountingSemaphore_obj::acquire() +{ + hx::AutoGCFreeZone zone; + + if (NO_ERROR != WaitForSingleObject(impl->semaphore, INFINITE)) + { + hx::Throw(HX_CSTRING("Failed to wait for semaphore")); + } +} + +void hx::thread::CountingSemaphore_obj::release() +{ + if (false == ReleaseSemaphore(impl->semaphore, 1, nullptr)) + { + hx::Throw(HX_CSTRING("Failed to release semaphore")); + } +} + +bool hx::thread::CountingSemaphore_obj::tryAcquire(Null timeout) +{ + hx::EnterGCFreeZone(); + + switch (WaitForSingleObject(impl->semaphore, static_cast(timeout.Default(0) * 1000))) + { + case NO_ERROR: + hx::ExitGCFreeZone(); + return true; + case WAIT_TIMEOUT: + hx::ExitGCFreeZone(); + return false; + default: + hx::ExitGCFreeZone(); + return hx::Throw(HX_CSTRING("Failed to wait for semaphore")); + } +} \ No newline at end of file diff --git a/toolchain/haxe-target.xml b/toolchain/haxe-target.xml index 11dd88576..73a649f8b 100644 --- a/toolchain/haxe-target.xml +++ b/toolchain/haxe-target.xml @@ -208,8 +208,21 @@ - - + + + +
+ +
+
+ +
+
+ +
+
+ +
From cc3b85f8619cbe90a001ac676585a362e2df938a Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 8 Mar 2026 14:41:02 +0000 Subject: [PATCH 2/4] Missing include in apple implementation --- src/hx/thread/CountingSemaphore.apple.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hx/thread/CountingSemaphore.apple.cpp b/src/hx/thread/CountingSemaphore.apple.cpp index 8f0cacfe1..0523ad225 100644 --- a/src/hx/thread/CountingSemaphore.apple.cpp +++ b/src/hx/thread/CountingSemaphore.apple.cpp @@ -1,5 +1,6 @@ #include #include +#include struct hx::thread::CountingSemaphore_obj::Impl { From 4f84ea838de92715c000136bd44b82354cf55d20 Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 8 Mar 2026 14:56:24 +0000 Subject: [PATCH 3/4] Fix bad equality symbol --- src/hx/thread/CountingSemaphore.apple.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hx/thread/CountingSemaphore.apple.cpp b/src/hx/thread/CountingSemaphore.apple.cpp index 0523ad225..169f7c23a 100644 --- a/src/hx/thread/CountingSemaphore.apple.cpp +++ b/src/hx/thread/CountingSemaphore.apple.cpp @@ -23,7 +23,7 @@ void hx::thread::CountingSemaphore_obj::acquire() { hx::AutoGCFreeZone zone; - if (0 != (dispatch_semaphore_wait(impl->semaphore, DISPATCH_TIME_FOREVER))) + if (0 != dispatch_semaphore_wait(impl->semaphore, DISPATCH_TIME_FOREVER)) { hx::Throw(HX_CSTRING("Failed to wait for semaphore")); } @@ -39,7 +39,7 @@ bool hx::thread::CountingSemaphore_obj::tryAcquire(Null timeout) hx::AutoGCFreeZone zone; return - (0 = dispatch_semaphore_wait( + (0 == dispatch_semaphore_wait( impl->semaphore, dispatch_time(DISPATCH_TIME_NOW, static_cast(timeout.Default(0)) * 1000 * 1000 * 1000))); } \ No newline at end of file From 2bd564f6c095b727d6930476f9d768cf3bcc168d Mon Sep 17 00:00:00 2001 From: Aidan Lee Date: Sun, 8 Mar 2026 15:38:33 +0000 Subject: [PATCH 4/4] Fix some gc zone mismatches --- src/hx/thread/CountingSemaphore.apple.cpp | 5 ++++- src/hx/thread/CountingSemaphore.posix.cpp | 1 + src/hx/thread/CountingSemaphore.win32.cpp | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/hx/thread/CountingSemaphore.apple.cpp b/src/hx/thread/CountingSemaphore.apple.cpp index 169f7c23a..766ef5dce 100644 --- a/src/hx/thread/CountingSemaphore.apple.cpp +++ b/src/hx/thread/CountingSemaphore.apple.cpp @@ -21,12 +21,15 @@ hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(new I void hx::thread::CountingSemaphore_obj::acquire() { - hx::AutoGCFreeZone zone; + hx::EnterGCFreeZone(); if (0 != dispatch_semaphore_wait(impl->semaphore, DISPATCH_TIME_FOREVER)) { + hx::ExitGCFreeZone(); hx::Throw(HX_CSTRING("Failed to wait for semaphore")); } + + hx::ExitGCFreeZone(); } void hx::thread::CountingSemaphore_obj::release() diff --git a/src/hx/thread/CountingSemaphore.posix.cpp b/src/hx/thread/CountingSemaphore.posix.cpp index 87294dbf4..db264945d 100644 --- a/src/hx/thread/CountingSemaphore.posix.cpp +++ b/src/hx/thread/CountingSemaphore.posix.cpp @@ -32,6 +32,7 @@ void hx::thread::CountingSemaphore_obj::acquire() if (0 != sem_wait(&impl->semaphore)) { + hx::ExitGCFreeZone(); hx::Throw(HX_CSTRING("Failed to wait on semaphore")); } diff --git a/src/hx/thread/CountingSemaphore.win32.cpp b/src/hx/thread/CountingSemaphore.win32.cpp index e158a6b56..471cde866 100644 --- a/src/hx/thread/CountingSemaphore.win32.cpp +++ b/src/hx/thread/CountingSemaphore.win32.cpp @@ -27,10 +27,11 @@ hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(new I void hx::thread::CountingSemaphore_obj::acquire() { - hx::AutoGCFreeZone zone; + hx::EnterGCFreeZone(); if (NO_ERROR != WaitForSingleObject(impl->semaphore, INFINITE)) { + hx::ExitGCFreeZone(); hx::Throw(HX_CSTRING("Failed to wait for semaphore")); } }