Skip to content

Commit 4249ea6

Browse files
Aidan63Aidan Lee
andauthored
Typed semaphores (HaxeFoundation#1314)
* wip semaphores * Missing include in apple implementation * Fix bad equality symbol * Fix some gc zone mismatches --------- Co-authored-by: Aidan Lee <aidan.lee@evcam.com>
1 parent 7ea4343 commit 4249ea6

7 files changed

Lines changed: 276 additions & 124 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#pragma once
2+
3+
#ifndef HXCPP_H
4+
#include <hxcpp.h>
5+
#endif
6+
7+
HX_DECLARE_CLASS2(hx, thread, CountingSemaphore)
8+
9+
namespace hx
10+
{
11+
namespace thread
12+
{
13+
struct CountingSemaphore_obj : public hx::Object
14+
{
15+
CountingSemaphore_obj(int value);
16+
17+
void acquire();
18+
void release();
19+
bool tryAcquire(Null<double> timeout);
20+
21+
private:
22+
struct Impl;
23+
24+
Impl* impl;
25+
};
26+
}
27+
}

src/hx/Thread.cpp

Lines changed: 14 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <time.h>
55
#include <hx/thread/ConditionVariable.hpp>
66
#include <hx/thread/RecursiveMutex.hpp>
7+
#include <hx/thread/CountingSemaphore.hpp>
78
#include <atomic>
89

910
DECLARE_TLS_DATA(class hxThreadInfo, tlsCurrentThread);
@@ -454,138 +455,29 @@ void __hxcpp_mutex_release(Dynamic inMutex)
454455
mutex->release();
455456
}
456457

457-
#if defined(HX_LINUX) || defined(HX_ANDROID)
458-
#define POSIX_SEMAPHORE
459-
#include <semaphore.h>
460-
#endif
461-
462-
#if defined(HX_MACOS) || defined(IPHONE) || defined(APPLETV)
463-
#define APPLE_SEMAPHORE
464-
#include <dispatch/dispatch.h>
465-
#endif
466-
467-
class hxSemaphore : public hx::Object {
468-
public:
469-
hx::InternalFinalizer *mFinalizer;
470-
#ifdef HX_WINDOWS
471-
HANDLE sem;
472-
#elif defined (POSIX_SEMAPHORE)
473-
sem_t sem;
474-
#elif defined(APPLE_SEMAPHORE)
475-
dispatch_semaphore_t sem;
476-
#endif
477-
bool valid;
478-
479-
hxSemaphore(int value) {
480-
mFinalizer = new hx::InternalFinalizer(this);
481-
mFinalizer->mFinalizer = clean;
482-
#ifdef HX_WINDOWS
483-
sem = CreateSemaphoreW(NULL, value, 0x7FFFFFFF, NULL);
484-
#elif defined(POSIX_SEMAPHORE)
485-
sem_init(&sem, 0, value);
486-
#elif defined(APPLE_SEMAPHORE)
487-
sem = dispatch_semaphore_create(value);
488-
#endif
489-
valid = true;
490-
}
491-
492-
HX_IS_INSTANCE_OF enum { _hx_ClassId = hx::clsIdSemaphore };
493-
494-
#ifdef HXCPP_VISIT_ALLOCS
495-
void __Visit(hx::VisitContext *__inCtx) { mFinalizer->Visit(__inCtx); }
496-
#endif
497-
498-
void Acquire() {
499-
hx::EnterGCFreeZone();
500-
#if HX_WINDOWS
501-
WaitForSingleObject(sem, INFINITE);
502-
#elif defined(POSIX_SEMAPHORE)
503-
sem_wait(&sem);
504-
#elif defined(APPLE_SEMAPHORE)
505-
dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
506-
#endif
507-
hx::ExitGCFreeZone();
508-
}
509-
510-
bool TryAcquire(double timeout) {
511-
hx::AutoGCFreeZone blocking;
512-
#ifdef HX_WINDOWS
513-
return WaitForSingleObject(sem, (DWORD)((FLOAT)timeout * 1000.0)) == 0;
514-
#elif defined(POSIX_SEMAPHORE)
515-
if (timeout == 0) {
516-
return sem_trywait(&sem) == 0;
517-
} else {
518-
struct timeval tv;
519-
struct timespec t;
520-
double delta = timeout;
521-
int idelta = (int)delta, idelta2;
522-
delta -= idelta;
523-
delta *= 1.0e9;
524-
gettimeofday(&tv, NULL);
525-
delta += tv.tv_usec * 1000.0;
526-
idelta2 = (int)(delta / 1e9);
527-
delta -= idelta2 * 1e9;
528-
t.tv_sec = tv.tv_sec + idelta + idelta2;
529-
t.tv_nsec = (long)delta;
530-
return sem_timedwait(&sem, &t) == 0;
531-
}
532-
#elif defined(APPLE_SEMAPHORE)
533-
return dispatch_semaphore_wait(
534-
sem,
535-
dispatch_time(DISPATCH_TIME_NOW,
536-
(int64_t)(timeout * 1000 * 1000 * 1000))) == 0;
537-
#else
538-
return false;
539-
#endif
540-
}
541-
542-
void Release() {
543-
#if HX_WINDOWS
544-
ReleaseSemaphore(sem, 1, NULL);
545-
#elif defined(POSIX_SEMAPHORE)
546-
sem_post(&sem);
547-
#elif defined(APPLE_SEMAPHORE)
548-
dispatch_semaphore_signal(sem);
549-
#endif
550-
}
551-
552-
static void clean(hx::Object *inObj) {
553-
hxSemaphore *l = dynamic_cast<hxSemaphore *>(inObj);
554-
if (l) {
555-
if(l->valid) {
556-
#ifdef HX_WINDOWS
557-
CloseHandle(l->sem);
558-
#elif defined(POSIX_SEMAPHORE)
559-
sem_destroy(&l->sem);
560-
#endif
561-
l->valid = false;
562-
}
563-
}
564-
}
565-
};
458+
// --- Semaphore ------------------------------------------------------------
566459

567460
Dynamic __hxcpp_semaphore_create(int value) {
568-
return new hxSemaphore(value);
461+
return new hx::thread::CountingSemaphore_obj(value);
569462
}
570463
void __hxcpp_semaphore_acquire(Dynamic inSemaphore) {
571-
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
572-
if (!semaphore)
573-
throw HX_INVALID_OBJECT;
574-
semaphore->Acquire();
464+
auto semaphore = inSemaphore.Cast<hx::thread::CountingSemaphore>();
465+
466+
semaphore->acquire();
575467
}
576468
bool __hxcpp_semaphore_try_acquire(Dynamic inSemaphore, double timeout) {
577-
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
578-
if (!semaphore)
579-
throw HX_INVALID_OBJECT;
580-
return semaphore->TryAcquire(timeout);
469+
auto semaphore = inSemaphore.Cast<hx::thread::CountingSemaphore>();
470+
471+
return semaphore->tryAcquire(timeout);
581472
}
582473
void __hxcpp_semaphore_release(Dynamic inSemaphore) {
583-
hxSemaphore *semaphore = dynamic_cast<hxSemaphore *>(inSemaphore.mPtr);
584-
if (!semaphore)
585-
throw HX_INVALID_OBJECT;
586-
semaphore->Release();
474+
auto semaphore = inSemaphore.Cast<hx::thread::CountingSemaphore>();
475+
476+
semaphore->release();
587477
}
588478

479+
// --- Condition ------------------------------------------------------------
480+
589481
Dynamic __hxcpp_condition_create(void)
590482
{
591483
return new hx::thread::ConditionVariable_obj();
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <hxcpp.h>
2+
#include <dispatch/dispatch.h>
3+
#include <hx/thread/CountingSemaphore.hpp>
4+
5+
struct hx::thread::CountingSemaphore_obj::Impl
6+
{
7+
dispatch_semaphore_t semaphore;
8+
9+
static void finalise(hx::Object* obj)
10+
{
11+
delete reinterpret_cast<hx::thread::CountingSemaphore_obj*>(obj)->impl;
12+
}
13+
};
14+
15+
hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(new Impl())
16+
{
17+
impl->semaphore = dispatch_semaphore_create(value);
18+
19+
hx::GCSetFinalizer(this, Impl::finalise);
20+
}
21+
22+
void hx::thread::CountingSemaphore_obj::acquire()
23+
{
24+
hx::EnterGCFreeZone();
25+
26+
if (0 != dispatch_semaphore_wait(impl->semaphore, DISPATCH_TIME_FOREVER))
27+
{
28+
hx::ExitGCFreeZone();
29+
hx::Throw(HX_CSTRING("Failed to wait for semaphore"));
30+
}
31+
32+
hx::ExitGCFreeZone();
33+
}
34+
35+
void hx::thread::CountingSemaphore_obj::release()
36+
{
37+
dispatch_semaphore_signal(impl->semaphore);
38+
}
39+
40+
bool hx::thread::CountingSemaphore_obj::tryAcquire(Null<double> timeout)
41+
{
42+
hx::AutoGCFreeZone zone;
43+
44+
return
45+
(0 == dispatch_semaphore_wait(
46+
impl->semaphore,
47+
dispatch_time(DISPATCH_TIME_NOW, static_cast<int64_t>(timeout.Default(0)) * 1000 * 1000 * 1000)));
48+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#include <hxcpp.h>
2+
#include <semaphore.h>
3+
#include <sys/time.h>
4+
#include <memory>
5+
#include <hx/thread/CountingSemaphore.hpp>
6+
7+
struct hx::thread::CountingSemaphore_obj::Impl
8+
{
9+
sem_t semaphore;
10+
11+
static void finalise(hx::Object* obj)
12+
{
13+
auto impl = std::unique_ptr<Impl>(reinterpret_cast<hx::thread::CountingSemaphore_obj*>(obj)->impl);
14+
15+
sem_destroy(&impl->semaphore);
16+
}
17+
};
18+
19+
hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(new Impl())
20+
{
21+
if (0 != (sem_init(&impl->semaphore, false, 3)))
22+
{
23+
hx::Throw(HX_CSTRING("Failed to create semaphore"));
24+
}
25+
26+
hx::GCSetFinalizer(this, Impl::finalise);
27+
}
28+
29+
void hx::thread::CountingSemaphore_obj::acquire()
30+
{
31+
hx::EnterGCFreeZone();
32+
33+
if (0 != sem_wait(&impl->semaphore))
34+
{
35+
hx::ExitGCFreeZone();
36+
hx::Throw(HX_CSTRING("Failed to wait on semaphore"));
37+
}
38+
39+
hx::ExitGCFreeZone();
40+
}
41+
42+
void hx::thread::CountingSemaphore_obj::release()
43+
{
44+
if (0 != sem_post(&impl->semaphore))
45+
{
46+
hx::Throw(HX_CSTRING("Failed to release semaphore"));
47+
}
48+
}
49+
50+
bool hx::thread::CountingSemaphore_obj::tryAcquire(Null<double> timeout)
51+
{
52+
if (0 == timeout.Default(0))
53+
{
54+
return 0 == sem_trywait(&impl->semaphore);
55+
}
56+
else
57+
{
58+
hx::EnterGCFreeZone();
59+
60+
struct timeval tv;
61+
struct timespec t;
62+
auto delta = timeout.value;
63+
int idelta = (int)delta, idelta2;
64+
delta -= idelta;
65+
delta *= 1.0e9;
66+
gettimeofday(&tv, NULL);
67+
delta += tv.tv_usec * 1000.0;
68+
idelta2 = (int)(delta / 1e9);
69+
delta -= idelta2 * 1e9;
70+
t.tv_sec = tv.tv_sec + idelta + idelta2;
71+
t.tv_nsec = (long)delta;
72+
73+
switch (sem_timedwait(&impl->semaphore, &t))
74+
{
75+
case 0:
76+
hx::ExitGCFreeZone();
77+
return true;
78+
case ETIMEDOUT:
79+
hx::ExitGCFreeZone();
80+
return false;
81+
default:
82+
hx::ExitGCFreeZone();
83+
return hx::Throw(HX_CSTRING("Failed to wait for semaphore"));
84+
}
85+
}
86+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#include <hxcpp.h>
2+
#include <hx/thread/CountingSemaphore.hpp>
3+
4+
struct hx::thread::CountingSemaphore_obj::Impl {};
5+
6+
hx::thread::CountingSemaphore_obj::CountingSemaphore_obj(int value) : impl(nullptr) {}
7+
8+
void hx::thread::CountingSemaphore_obj::acquire()
9+
{
10+
hx::Throw(HX_CSTRING("Unsupported platform"));
11+
}
12+
13+
void hx::thread::CountingSemaphore_obj::release()
14+
{
15+
hx::Throw(HX_CSTRING("Unsupported platform"));
16+
}
17+
18+
bool hx::thread::CountingSemaphore_obj::tryAcquire(Null<double> timeout)
19+
{
20+
hx::Throw(HX_CSTRING("Unsupported platform"));
21+
22+
return false;
23+
}

0 commit comments

Comments
 (0)