#include "threading.h"

/* Based on: https://eli.thegreenplace.net/2019/implementing-reader-writer-locks/ */

RT_DLLEXPORT rt_create_rwlock_result rtCreateRWLock(void) {
    rt_create_rwlock_result res;
    res.lock.reader_count = 0;
    res.lock.cond         = rtCreateConditionVar();
    res.ok                = res.lock.cond != NULL;
    return res;
}

RT_DLLEXPORT void rtDestroyRWLock(rt_rwlock *lock) {
    rtDestroyConditionVar(lock->cond);
    lock->cond         = NULL;
    lock->reader_count = 0;
}

RT_DLLEXPORT void rtLockRead(rt_rwlock *lock) {
    rtLockConditionVar(lock->cond);
    ++lock->reader_count;
    rtUnlockConditionVar(lock->cond, false);
}

RT_DLLEXPORT void rtUnlockRead(rt_rwlock *lock) {
    rtLockConditionVar(lock->cond);
    RT_ASSERT(lock->reader_count > 0, "Tried to unlock a read-write lock that is not held.");
    --lock->reader_count;
    bool signal = lock->reader_count == 0;
    rtUnlockConditionVar(lock->cond, signal);
}

RT_DLLEXPORT void rtLockWrite(rt_rwlock *lock) {
    rtLockConditionVar(lock->cond);
    while (lock->reader_count > 0)
        rtWaitOnConditionVar(lock->cond);
}

RT_DLLEXPORT void rtUnlockWrite(rt_rwlock *lock) {
    rtUnlockConditionVar(lock->cond, true);
}
