|
@@ -28,6 +28,14 @@ struct _hl_mutex {
|
|
void *_unused;
|
|
void *_unused;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct _hl_semaphore {
|
|
|
|
+ void (*free)(hl_semaphore *);
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct _hl_condition {
|
|
|
|
+ void (*free)(hl_condition *);
|
|
|
|
+};
|
|
|
|
+
|
|
struct _hl_tls {
|
|
struct _hl_tls {
|
|
void (*free)( hl_tls * );
|
|
void (*free)( hl_tls * );
|
|
void *value;
|
|
void *value;
|
|
@@ -41,6 +49,17 @@ struct _hl_mutex {
|
|
bool is_gc;
|
|
bool is_gc;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct _hl_semaphore {
|
|
|
|
+ void (*free)(hl_semaphore *);
|
|
|
|
+ HANDLE sem;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct _hl_condition {
|
|
|
|
+ void (*free)(hl_condition *);
|
|
|
|
+ CRITICAL_SECTION cs;
|
|
|
|
+ CONDITION_VARIABLE cond;
|
|
|
|
+};
|
|
|
|
+
|
|
struct _hl_tls {
|
|
struct _hl_tls {
|
|
void (*free)( hl_tls * );
|
|
void (*free)( hl_tls * );
|
|
DWORD tid;
|
|
DWORD tid;
|
|
@@ -53,6 +72,11 @@ struct _hl_tls {
|
|
# include <sys/syscall.h>
|
|
# include <sys/syscall.h>
|
|
# include <sys/time.h>
|
|
# include <sys/time.h>
|
|
|
|
|
|
|
|
+#ifdef __APPLE__
|
|
|
|
+#include <dispatch/dispatch.h>
|
|
|
|
+#else
|
|
|
|
+#include <semaphore.h>
|
|
|
|
+#endif
|
|
|
|
|
|
struct _hl_mutex {
|
|
struct _hl_mutex {
|
|
void (*free)( hl_mutex * );
|
|
void (*free)( hl_mutex * );
|
|
@@ -60,6 +84,21 @@ struct _hl_mutex {
|
|
bool is_gc;
|
|
bool is_gc;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+struct _hl_semaphore {
|
|
|
|
+ void (*free)(hl_semaphore *);
|
|
|
|
+# ifdef __APPLE__
|
|
|
|
+ dispatch_semaphore_t sem;
|
|
|
|
+# else
|
|
|
|
+ sem_t sem;
|
|
|
|
+#endif
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+struct _hl_condition {
|
|
|
|
+ void (*free)(hl_condition *);
|
|
|
|
+ pthread_mutex_t mutex;
|
|
|
|
+ pthread_cond_t cond;
|
|
|
|
+};
|
|
|
|
+
|
|
struct _hl_tls {
|
|
struct _hl_tls {
|
|
void (*free)( hl_tls * );
|
|
void (*free)( hl_tls * );
|
|
pthread_key_t key;
|
|
pthread_key_t key;
|
|
@@ -146,6 +185,241 @@ DEFINE_PRIM(_BOOL, mutex_try_acquire, _MUTEX);
|
|
DEFINE_PRIM(_VOID, mutex_release, _MUTEX);
|
|
DEFINE_PRIM(_VOID, mutex_release, _MUTEX);
|
|
DEFINE_PRIM(_VOID, mutex_free, _MUTEX);
|
|
DEFINE_PRIM(_VOID, mutex_free, _MUTEX);
|
|
|
|
|
|
|
|
+// ------------------ SEMAPHORE
|
|
|
|
+
|
|
|
|
+HL_API hl_semaphore *hl_semaphore_alloc(int value) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+ static struct _hl_semaphore null_semaphore = {0};
|
|
|
|
+ return (hl_condition *)&null_semaphore;
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ hl_semaphore *sem =
|
|
|
|
+ (hl_semaphore *)hl_gc_alloc_finalizer(sizeof(hl_semaphore));
|
|
|
|
+ sem->free = hl_semaphore_free;
|
|
|
|
+ sem->sem = CreateSemaphoreW(NULL, value, 0x7FFFFFFF, NULL);
|
|
|
|
+ return sem;
|
|
|
|
+# else
|
|
|
|
+ hl_semaphore *sem =
|
|
|
|
+ (hl_semaphore *)hl_gc_alloc_finalizer(sizeof(hl_semaphore));
|
|
|
|
+ sem->free = hl_semaphore_free;
|
|
|
|
+# ifdef __APPLE__
|
|
|
|
+ sem->sem = dispatch_semaphore_create(value);
|
|
|
|
+# else
|
|
|
|
+ sem_init(&sem->sem, false, value);
|
|
|
|
+# endif
|
|
|
|
+ return sem;
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API void hl_semaphore_acquire(hl_semaphore *sem) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ WaitForSingleObject(sem->sem, INFINITE);
|
|
|
|
+# else
|
|
|
|
+# ifdef __APPLE__
|
|
|
|
+ dispatch_semaphore_wait(sem->sem, DISPATCH_TIME_FOREVER);
|
|
|
|
+# else
|
|
|
|
+ sem_wait(&sem->sem);
|
|
|
|
+# endif
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API bool hl_semaphore_try_acquire(hl_semaphore *sem, vdynamic *timeout) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ return WaitForSingleObject(sem->sem,
|
|
|
|
+ timeout ? (DWORD)((FLOAT)timeout->v.d * 1000.0)
|
|
|
|
+ : 0) == WAIT_OBJECT_0;
|
|
|
|
+# else
|
|
|
|
+# ifdef __APPLE__
|
|
|
|
+ return dispatch_semaphore_wait(
|
|
|
|
+ sem, dispatch_time(DISPATCH_TIME_NOW,
|
|
|
|
+ (int64_t)((timeout ? timeout->v.d : 0) *
|
|
|
|
+ 1000 * 1000 * 1000))) == 0;
|
|
|
|
+# else
|
|
|
|
+ if (timeout) {
|
|
|
|
+ struct timeval tv;
|
|
|
|
+ struct timespec t;
|
|
|
|
+ double delta = timeout->v.d;
|
|
|
|
+ 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->sem, &t) == 0;
|
|
|
|
+ } else {
|
|
|
|
+
|
|
|
|
+ return sem_trywait(&sem->sem) == 0;
|
|
|
|
+ }
|
|
|
|
+# endif
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API void hl_semaphore_release(hl_semaphore *sem) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ ReleaseSemaphore(sem->sem, 1, NULL);
|
|
|
|
+# else
|
|
|
|
+# ifdef __APPLE__
|
|
|
|
+ dispatch_semaphore_signal(&sem->sem);
|
|
|
|
+# else
|
|
|
|
+ sem_post(&sem->sem);
|
|
|
|
+# endif
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API void hl_semaphore_free(hl_semaphore *sem) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ if (sem->free) {
|
|
|
|
+ CloseHandle(sem->sem);
|
|
|
|
+ sem->free = NULL;
|
|
|
|
+ }
|
|
|
|
+# else
|
|
|
|
+ if (sem->free) {
|
|
|
|
+ sem_destroy(&sem->sem);
|
|
|
|
+ sem->free = NULL;
|
|
|
|
+ }
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define _SEMAPHORE _ABSTRACT(hl_semaphore)
|
|
|
|
+DEFINE_PRIM(_SEMAPHORE, semaphore_alloc, _I32);
|
|
|
|
+DEFINE_PRIM(_VOID, semaphore_acquire, _SEMAPHORE);
|
|
|
|
+DEFINE_PRIM(_BOOL, semaphore_try_acquire, _SEMAPHORE _NULL(_F64));
|
|
|
|
+DEFINE_PRIM(_VOID, semaphore_release, _SEMAPHORE);
|
|
|
|
+DEFINE_PRIM(_VOID, semaphore_free, _SEMAPHORE);
|
|
|
|
+// ------------------ CONDITION
|
|
|
|
+
|
|
|
|
+HL_API hl_condition *hl_condition_alloc() {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+ static struct _hl_condition null_condition = {0};
|
|
|
|
+ return (hl_condition *)&null_condition;
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ hl_condition *cond =
|
|
|
|
+ (hl_condition *)hl_gc_alloc_finalizer(sizeof(hl_condition));
|
|
|
|
+ cond->free = hl_condition_free;
|
|
|
|
+ InitializeCriticalSection(&cond->cs);
|
|
|
|
+ InitializeConditionVariable(&cond->cond);
|
|
|
|
+ return cond;
|
|
|
|
+# else
|
|
|
|
+ hl_condition *cond =
|
|
|
|
+ (hl_condition *)hl_gc_alloc_finalizer(sizeof(hl_condition));
|
|
|
|
+ cond->free = hl_condition_free;
|
|
|
|
+ pthread_condattr_t attr;
|
|
|
|
+ pthread_condattr_init(&attr);
|
|
|
|
+ pthread_cond_init(&cond->cond, &attr);
|
|
|
|
+ pthread_condattr_destroy(&attr);
|
|
|
|
+ pthread_mutexattr_t mutexattr;
|
|
|
|
+ pthread_mutexattr_init(&mutexattr);
|
|
|
|
+ pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
+ pthread_mutex_init(&cond->mutex, &mutexattr);
|
|
|
|
+ pthread_mutexattr_destroy(&mutexattr);
|
|
|
|
+ return cond;
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+HL_API void hl_condition_acquire(hl_condition *cond) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ EnterCriticalSection(&cond->cs);
|
|
|
|
+# else
|
|
|
|
+ pthread_mutex_lock(&cond->mutex);
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API bool hl_condition_try_acquire(hl_condition *cond) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ return (bool)TryEnterCriticalSection(&cond->cs);
|
|
|
|
+# else
|
|
|
|
+ return pthread_mutex_trylock(&cond->mutex) == 0;
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API void hl_condition_release(hl_condition *cond) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ LeaveCriticalSection(&cond->cs);
|
|
|
|
+# else
|
|
|
|
+ pthread_mutex_unlock(&cond->mutex);
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+HL_API void hl_condition_wait(hl_condition *cond) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ SleepConditionVariableCS(&cond->cond, &cond->cs, INFINITE);
|
|
|
|
+# else
|
|
|
|
+ pthread_cond_wait(&cond->cond, &cond->mutex);
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API bool hl_condition_timed_wait(hl_condition *cond, double timeout) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ SleepConditionVariableCS(&cond->cond, &cond->cs,
|
|
|
|
+ (DWORD)((FLOAT)timeout * 1000.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 pthread_cond_timedwait(&cond->cond, &cond->mutex, &t) == 0;
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+HL_API void hl_condition_signal(hl_condition *cond) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ WakeConditionVariable(&cond->cond);
|
|
|
|
+# else
|
|
|
|
+ pthread_cond_signal(&cond->cond);
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+HL_API void hl_condition_broadcast(hl_condition *cond) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ WakeAllConditionVariable(&cond->cond);
|
|
|
|
+# else
|
|
|
|
+ pthread_cond_broadcast(&cond->cond);
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+HL_API void hl_condition_free(hl_condition *cond) {
|
|
|
|
+# if !defined(HL_THREADS)
|
|
|
|
+# elif defined(HL_WIN)
|
|
|
|
+ if (cond->free) {
|
|
|
|
+ DeleteCriticalSection(&cond->cs);
|
|
|
|
+ cond->free = NULL;
|
|
|
|
+ }
|
|
|
|
+# else
|
|
|
|
+ if (cond->free) {
|
|
|
|
+ pthread_cond_destroy(&cond->cond);
|
|
|
|
+ pthread_mutex_destroy(&cond->mutex);
|
|
|
|
+ cond->free = NULL;
|
|
|
|
+ }
|
|
|
|
+# endif
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#define _CONDITION _ABSTRACT(hl_condition)
|
|
|
|
+DEFINE_PRIM(_CONDITION, condition_alloc, _NO_ARG)
|
|
|
|
+DEFINE_PRIM(_VOID, condition_acquire, _CONDITION)
|
|
|
|
+DEFINE_PRIM(_BOOL, condition_try_acquire, _CONDITION)
|
|
|
|
+DEFINE_PRIM(_VOID, condition_release, _CONDITION)
|
|
|
|
+DEFINE_PRIM(_VOID, condition_wait, _CONDITION)
|
|
|
|
+DEFINE_PRIM(_BOOL, condition_timed_wait, _CONDITION _F64)
|
|
|
|
+DEFINE_PRIM(_VOID, condition_signal, _CONDITION)
|
|
|
|
+DEFINE_PRIM(_VOID, condition_broadcast, _CONDITION)
|
|
|
|
+
|
|
// ----------------- THREAD LOCAL
|
|
// ----------------- THREAD LOCAL
|
|
|
|
|
|
HL_PRIM hl_tls *hl_tls_alloc( bool gc_value ) {
|
|
HL_PRIM hl_tls *hl_tls_alloc( bool gc_value ) {
|