feature: add linux condition variable, mutex, and read-write lock implementations
This commit is contained in:
parent
3211bb45b3
commit
9bd6be2c2c
4 changed files with 290 additions and 0 deletions
111
Source/DrangPlatform/Source/linux/sync/cond_var.c
Normal file
111
Source/DrangPlatform/Source/linux/sync/cond_var.c
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#include "drang/alloc.h"
|
||||
#include "errno_convert.h"
|
||||
#include "internal.h"
|
||||
#include <drang/error.h>
|
||||
#include <drang/sync.h>
|
||||
#include <errno.h>
|
||||
|
||||
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();
|
||||
}
|
||||
22
Source/DrangPlatform/Source/linux/sync/internal.h
Normal file
22
Source/DrangPlatform/Source/linux/sync/internal.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
#include <drang/sync.h>
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
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;
|
||||
};
|
||||
68
Source/DrangPlatform/Source/linux/sync/mutex.c
Normal file
68
Source/DrangPlatform/Source/linux/sync/mutex.c
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
#include "drang/alloc.h"
|
||||
#include "errno_convert.h"
|
||||
#include "internal.h"
|
||||
#include <drang/error.h>
|
||||
#include <drang/sync.h>
|
||||
|
||||
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();
|
||||
}
|
||||
89
Source/DrangPlatform/Source/linux/sync/rwlock.c
Normal file
89
Source/DrangPlatform/Source/linux/sync/rwlock.c
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
#include "errno_convert.h"
|
||||
#include "internal.h"
|
||||
#include <drang/error.h>
|
||||
#include <drang/sync.h>
|
||||
#include <stdalign.h>
|
||||
|
||||
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();
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue