diff --git a/Source/DrangPlatform/Source/linux/sync/cond_var.c b/Source/DrangPlatform/Source/linux/sync/cond_var.c new file mode 100644 index 0000000..a768c41 --- /dev/null +++ b/Source/DrangPlatform/Source/linux/sync/cond_var.c @@ -0,0 +1,111 @@ +#include "drang/alloc.h" +#include "errno_convert.h" +#include "internal.h" +#include +#include +#include + +size_t drang_cond_size(void) +{ + return sizeof(struct drang_cond); +} + +size_t drang_cond_alignment(void) +{ + return alignof(struct drang_cond); +} + +int drang_cond_init(struct drang_cond *cond) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(cond != NULL, DRANG_EINVAL); + DRANG_CHECK(!cond->initialized, DRANG_EBUSY); + const int res = pthread_cond_init(&cond->inner, NULL); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + cond->initialized = true; + DRANG_END_TRY_IGNORE(); +} + +void drang_cond_fini(struct drang_cond *cond) +{ + if (cond == NULL) { + return; + } + + pthread_cond_destroy(&cond->inner); + cond->initialized = false; +} + +int drang_cond_signal(struct drang_cond *cond) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(cond != NULL, DRANG_EINVAL); + DRANG_CHECK(cond->initialized, DRANG_EINVAL); + const int res = pthread_cond_signal(&cond->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +} + +int drang_cond_broadcast(struct drang_cond *cond) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(cond != NULL, DRANG_EINVAL); + DRANG_CHECK(cond->initialized, DRANG_EINVAL); + const int res = pthread_cond_broadcast(&cond->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +} + +int drang_cond_wait(struct drang_cond *cond, struct drang_mutex *mutex) +{ + return drang_cond_timedwait(cond, mutex, 0); +} + +int drang_cond_timedwait(struct drang_cond *cond, struct drang_mutex *mutex, uint64_t timeout_ms) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(cond != NULL, DRANG_EINVAL); + DRANG_CHECK(cond->initialized, DRANG_EINVAL); + DRANG_CHECK(mutex != NULL, DRANG_EINVAL); + DRANG_CHECK(mutex->initialized, DRANG_EINVAL); + + int res; + if (timeout_ms == 0) { + // Infinite wait + res = pthread_cond_wait(&cond->inner, &mutex->inner); + } else { + // Timed wait - calculate absolute timeout + struct timespec abs_timeout; + if (clock_gettime(CLOCK_REALTIME, &abs_timeout) != 0) { + DRANG_FAIL(drang_errno_to_error(errno)); + } + + // Add timeout milliseconds to current time + + abs_timeout.tv_sec += (time_t)(timeout_ms / 1000); + abs_timeout.tv_nsec += (time_t)((timeout_ms % 1000) * 1000000); + + // Handle nanosecond overflow + if (abs_timeout.tv_nsec >= 1000000000) { + abs_timeout.tv_sec += 1; + abs_timeout.tv_nsec -= 1000000000; + } + + res = pthread_cond_timedwait(&cond->inner, &mutex->inner, &abs_timeout); + } + + if (res != 0) { + if (res == ETIMEDOUT) { + DRANG_FAIL(DRANG_ETIMEDOUT); + } + DRANG_FAIL(drang_errno_to_error(res)); + } + + DRANG_END_TRY_IGNORE(); +} diff --git a/Source/DrangPlatform/Source/linux/sync/internal.h b/Source/DrangPlatform/Source/linux/sync/internal.h new file mode 100644 index 0000000..e41e1d5 --- /dev/null +++ b/Source/DrangPlatform/Source/linux/sync/internal.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include + +struct drang_mutex +{ + pthread_mutex_t inner; + bool initialized; +}; + +struct drang_cond +{ + pthread_cond_t inner; + bool initialized; +}; + +struct drang_rwlock +{ + pthread_rwlock_t inner; + bool initialized; +}; diff --git a/Source/DrangPlatform/Source/linux/sync/mutex.c b/Source/DrangPlatform/Source/linux/sync/mutex.c new file mode 100644 index 0000000..54291fb --- /dev/null +++ b/Source/DrangPlatform/Source/linux/sync/mutex.c @@ -0,0 +1,68 @@ +#include "drang/alloc.h" +#include "errno_convert.h" +#include "internal.h" +#include +#include + +size_t drang_mutex_size(void) +{ + return sizeof(struct drang_mutex); +} + + +size_t drang_mutex_alignment(void) +{ + return alignof(struct drang_mutex); +} + +int drang_mutex_init(struct drang_mutex *mutex) +{ + DRANG_BEGIN_TRY(); + + DRANG_CHECK(mutex != NULL, DRANG_EINVAL); + DRANG_CHECK(!mutex->initialized, DRANG_EBUSY); + + const int res = pthread_mutex_init(&mutex->inner, NULL); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + mutex->initialized = true; + + + DRANG_END_TRY_IGNORE(); +} + +void drang_mutex_fini(struct drang_mutex *mutex) +{ + if (mutex == NULL) { + return; + } + + if (mutex->initialized) { + pthread_mutex_destroy(&mutex->inner); + mutex->initialized = false; + } +} + +int drang_mutex_lock(struct drang_mutex *mutex) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(mutex != NULL, DRANG_EINVAL); + DRANG_CHECK(mutex->initialized, DRANG_EINVAL); + const int res = pthread_mutex_lock(&mutex->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +} +int drang_mutex_unlock(struct drang_mutex *mutex) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(mutex != NULL, DRANG_EINVAL); + DRANG_CHECK(mutex->initialized, DRANG_EINVAL); + const int res = pthread_mutex_unlock(&mutex->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +} diff --git a/Source/DrangPlatform/Source/linux/sync/rwlock.c b/Source/DrangPlatform/Source/linux/sync/rwlock.c new file mode 100644 index 0000000..007315e --- /dev/null +++ b/Source/DrangPlatform/Source/linux/sync/rwlock.c @@ -0,0 +1,89 @@ +#include "errno_convert.h" +#include "internal.h" +#include +#include +#include + +size_t drang_rwlock_size(void) +{ + return sizeof(struct drang_rwlock); +} + +size_t drang_rwlock_alignment(void) +{ + return alignof(struct drang_rwlock); +} + + +int drang_rwlock_init(struct drang_rwlock *rwlock) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(rwlock != NULL, DRANG_EINVAL); + DRANG_CHECK(!rwlock->initialized, DRANG_EBUSY); + const int res = pthread_rwlock_init(&rwlock->inner, NULL); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + rwlock->initialized = true; + DRANG_END_TRY_IGNORE(); + +} + +void drang_rwlock_fini(struct drang_rwlock *rwlock) +{ + if (rwlock == NULL) { + return; + } + if (rwlock->initialized) { + pthread_rwlock_destroy(&rwlock->inner); + rwlock->initialized = false; + } +} + +int drang_rwlock_rdlock(struct drang_rwlock *rwlock) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(rwlock != NULL, DRANG_EINVAL); + DRANG_CHECK(rwlock->initialized, DRANG_EINVAL); + const int res = pthread_rwlock_rdlock(&rwlock->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +} + +int drang_rwlock_wrlock(struct drang_rwlock *rwlock) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(rwlock != NULL, DRANG_EINVAL); + DRANG_CHECK(rwlock->initialized, DRANG_EINVAL); + const int res = pthread_rwlock_wrlock(&rwlock->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +} + +int drang_rwlock_rdunlock(struct drang_rwlock *rwlock) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(rwlock != NULL, DRANG_EINVAL); + DRANG_CHECK(rwlock->initialized, DRANG_EINVAL); + const int res = pthread_rwlock_unlock(&rwlock->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +} + +int drang_rwlock_wrunlock(struct drang_rwlock *rwlock) +{ + DRANG_BEGIN_TRY() + DRANG_CHECK(rwlock != NULL, DRANG_EINVAL); + DRANG_CHECK(rwlock->initialized, DRANG_EINVAL); + const int res = pthread_rwlock_unlock(&rwlock->inner); + if (res != 0) { + DRANG_FAIL(drang_errno_to_error(res)); + } + DRANG_END_TRY_IGNORE(); +}