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..766ef5dce --- /dev/null +++ b/src/hx/thread/CountingSemaphore.apple.cpp @@ -0,0 +1,48 @@ +#include +#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::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() +{ + 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..db264945d --- /dev/null +++ b/src/hx/thread/CountingSemaphore.posix.cpp @@ -0,0 +1,86 @@ +#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::ExitGCFreeZone(); + 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..471cde866 --- /dev/null +++ b/src/hx/thread/CountingSemaphore.win32.cpp @@ -0,0 +1,63 @@ +#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::EnterGCFreeZone(); + + if (NO_ERROR != WaitForSingleObject(impl->semaphore, INFINITE)) + { + hx::ExitGCFreeZone(); + 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 @@ - - + + + +
+ +
+
+ +
+
+ +
+
+ +