Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions include/hx/thread/CountingSemaphore.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#ifndef HXCPP_H
#include <hxcpp.h>
#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<double> timeout);

private:
struct Impl;

Impl* impl;
};
}
}
136 changes: 14 additions & 122 deletions src/hx/Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <time.h>
#include <hx/thread/ConditionVariable.hpp>
#include <hx/thread/RecursiveMutex.hpp>
#include <hx/thread/CountingSemaphore.hpp>
#include <atomic>

DECLARE_TLS_DATA(class hxThreadInfo, tlsCurrentThread);
Expand Down Expand Up @@ -454,138 +455,29 @@ void __hxcpp_mutex_release(Dynamic inMutex)
mutex->release();
}

#if defined(HX_LINUX) || defined(HX_ANDROID)
#define POSIX_SEMAPHORE
#include <semaphore.h>
#endif

#if defined(HX_MACOS) || defined(IPHONE) || defined(APPLETV)
#define APPLE_SEMAPHORE
#include <dispatch/dispatch.h>
#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<hxSemaphore *>(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<hxSemaphore *>(inSemaphore.mPtr);
if (!semaphore)
throw HX_INVALID_OBJECT;
semaphore->Acquire();
auto semaphore = inSemaphore.Cast<hx::thread::CountingSemaphore>();

semaphore->acquire();
}
bool __hxcpp_semaphore_try_acquire(Dynamic inSemaphore, double timeout) {
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
if (!semaphore)
throw HX_INVALID_OBJECT;
return semaphore->TryAcquire(timeout);
auto semaphore = inSemaphore.Cast<hx::thread::CountingSemaphore>();

return semaphore->tryAcquire(timeout);
}
void __hxcpp_semaphore_release(Dynamic inSemaphore) {
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
if (!semaphore)
throw HX_INVALID_OBJECT;
semaphore->Release();
auto semaphore = inSemaphore.Cast<hx::thread::CountingSemaphore>();

semaphore->release();
}

// --- Condition ------------------------------------------------------------

Dynamic __hxcpp_condition_create(void)
{
return new hx::thread::ConditionVariable_obj();
Expand Down
48 changes: 48 additions & 0 deletions src/hx/thread/CountingSemaphore.apple.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <hxcpp.h>
#include <dispatch/dispatch.h>
#include <hx/thread/CountingSemaphore.hpp>

struct hx::thread::CountingSemaphore_obj::Impl
{
dispatch_semaphore_t semaphore;

static void finalise(hx::Object* obj)
{
delete reinterpret_cast<hx::thread::CountingSemaphore_obj*>(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<double> timeout)
{
hx::AutoGCFreeZone zone;

return
(0 == dispatch_semaphore_wait(
impl->semaphore,
dispatch_time(DISPATCH_TIME_NOW, static_cast<int64_t>(timeout.Default(0)) * 1000 * 1000 * 1000)));
}
86 changes: 86 additions & 0 deletions src/hx/thread/CountingSemaphore.posix.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#include <hxcpp.h>
#include <semaphore.h>
#include <sys/time.h>
#include <memory>
#include <hx/thread/CountingSemaphore.hpp>

struct hx::thread::CountingSemaphore_obj::Impl
{
sem_t semaphore;

static void finalise(hx::Object* obj)
{
auto impl = std::unique_ptr<Impl>(reinterpret_cast<hx::thread::CountingSemaphore_obj*>(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<double> 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"));
}
}
}
23 changes: 23 additions & 0 deletions src/hx/thread/CountingSemaphore.unsupported.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <hxcpp.h>
#include <hx/thread/CountingSemaphore.hpp>

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<double> timeout)
{
hx::Throw(HX_CSTRING("Unsupported platform"));

return false;
}
Loading