/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * Copyright by The HDF Group.                                               *
 * All rights reserved.                                                      *
 *                                                                           *
 * This file is part of HDF5.  The full HDF5 copyright notice, including     *
 * terms governing use, modification, and redistribution, is contained in    *
 * the LICENSE file, which can be found at the root of the source code       *
 * distribution tree, or in https://www.hdfgroup.org/licenses.               *
 * If you do not have access to either file, you may request a copy from     *
 * help@hdfgroup.org.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#ifdef H5_HAVE_C11_THREADS

static inline herr_t
H5TS_rwlock_rdlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(mtx_lock(&lock->mutex) != thrd_success))
        return FAIL;

    
    if (lock->writers || lock->write_waiters) {
        
        lock->read_waiters++;

        
        do {
            if (H5_UNLIKELY(thrd_success != cnd_wait(&lock->read_cv, &lock->mutex))) {
                mtx_unlock(&lock->mutex);
                return FAIL;
            }
        } while (lock->writers || lock->write_waiters);

        
        lock->read_waiters--;
    }

    
    lock->readers++;

    
    if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_rdunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(mtx_lock(&lock->mutex) != thrd_success))
        return FAIL;

    
    lock->readers--;

    
    if (lock->write_waiters && 0 == lock->readers)
        if (H5_UNLIKELY(cnd_signal(&lock->write_cv) != thrd_success)) {
            mtx_unlock(&lock->mutex);
            return FAIL;
        }

    
    if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(mtx_lock(&lock->mutex) != thrd_success))
        return FAIL;

    
    if (lock->readers || lock->writers) {
        
        lock->write_waiters++;

        
        do {
            if (H5_UNLIKELY(thrd_success != cnd_wait(&lock->write_cv, &lock->mutex))) {
                mtx_unlock(&lock->mutex);
                return FAIL;
            }
        } while (lock->readers || lock->writers);

        
        lock->write_waiters--;
    }

    
    lock->writers++;

    
    if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired)
{
    int ret;

    
    if (H5_UNLIKELY(NULL == lock || NULL == acquired))
        return FAIL;

    
    if (H5_UNLIKELY(thrd_error == (ret = mtx_lock(&lock->mutex))))
        return FAIL;
    if (thrd_busy == ret) {
        
        *acquired = false;
        return SUCCEED;
    }

    
    if (lock->readers || lock->writers)
        
        *acquired = false;
    else {
        
        lock->writers++;

        
        *acquired = true;
    }

    
    if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(mtx_lock(&lock->mutex) != thrd_success))
        return FAIL;

    
    lock->writers--;

    
    if (lock->write_waiters) {
        if (H5_UNLIKELY(cnd_signal(&lock->write_cv) != thrd_success)) {
            mtx_unlock(&lock->mutex);
            return FAIL;
        }
    }
    else if (lock->read_waiters)
        if (H5_UNLIKELY(cnd_broadcast(&lock->read_cv) != thrd_success)) {
            mtx_unlock(&lock->mutex);
            return FAIL;
        }

    
    if (H5_UNLIKELY(mtx_unlock(&lock->mutex) != thrd_success))
        return FAIL;

    return SUCCEED;
} 

#else
#ifdef H5_HAVE_WIN_THREADS

static inline herr_t
H5TS_rwlock_rdlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    AcquireSRWLockShared(lock);

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_rdunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    ReleaseSRWLockShared(lock);

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    AcquireSRWLockExclusive(lock);

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired)
{
    
    if (H5_UNLIKELY(NULL == lock || NULL == acquired))
        return FAIL;

    if (TryAcquireSRWLockExclusive(lock))
        *acquired = true;
    else
        *acquired = false;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    ReleaseSRWLockExclusive(lock);

    return SUCCEED;
} 

#elif defined(__MACH__)

static inline herr_t
H5TS_rwlock_rdlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex)))
        return FAIL;

    
    if (lock->writers || lock->write_waiters) {
        
        lock->read_waiters++;

        
        do {
            if (H5_UNLIKELY(pthread_cond_wait(&lock->read_cv, &lock->mutex))) {
                pthread_mutex_unlock(&lock->mutex);
                return FAIL;
            }
        } while (lock->writers || lock->write_waiters);

        
        lock->read_waiters--;
    }

    
    lock->readers++;

    
    if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex)))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_rdunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex)))
        return FAIL;

    
    lock->readers--;

    
    if (lock->write_waiters && 0 == lock->readers)
        if (H5_UNLIKELY(pthread_cond_signal(&lock->write_cv))) {
            pthread_mutex_unlock(&lock->mutex);
            return FAIL;
        }

    
    if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex)))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex)))
        return FAIL;

    
    if (lock->readers || lock->writers) {
        
        lock->write_waiters++;

        
        do {
            if (H5_UNLIKELY(pthread_cond_wait(&lock->write_cv, &lock->mutex))) {
                pthread_mutex_unlock(&lock->mutex);
                return FAIL;
            }
        } while (lock->readers || lock->writers);

        
        lock->write_waiters--;
    }

    
    lock->writers++;

    
    if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex)))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired)
{
    int rc;

    
    if (H5_UNLIKELY(NULL == lock || NULL == acquired))
        return FAIL;

    
    rc = pthread_mutex_trylock(&lock->mutex);
    if (EBUSY == rc) {
        
        *acquired = false;
        return SUCCEED;
    }
    else if (0 != rc)
        return FAIL;

    
    if (lock->readers || lock->writers)
        
        *acquired = false;
    else {
        
        lock->writers++;

        
        *acquired = true;
    }

    
    if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex)))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    
    if (H5_UNLIKELY(pthread_mutex_lock(&lock->mutex)))
        return FAIL;

    
    lock->writers--;

    
    if (lock->write_waiters) {
        if (H5_UNLIKELY(pthread_cond_signal(&lock->write_cv))) {
            pthread_mutex_unlock(&lock->mutex);
            return FAIL;
        }
    }
    else if (lock->read_waiters)
        if (H5_UNLIKELY(pthread_cond_broadcast(&lock->read_cv))) {
            pthread_mutex_unlock(&lock->mutex);
            return FAIL;
        }

    
    if (H5_UNLIKELY(pthread_mutex_unlock(&lock->mutex)))
        return FAIL;

    return SUCCEED;
} 

#else

static inline herr_t
H5TS_rwlock_rdlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    if (H5_UNLIKELY(pthread_rwlock_rdlock(lock)))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_rdunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    if (H5_UNLIKELY(pthread_rwlock_unlock(lock)))
        return FAIL;

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    if (H5_UNLIKELY(pthread_rwlock_wrlock(lock)))
        return FAIL;

    return SUCCEED;
} 

herr_t
H5TS_rwlock_trywrlock(H5TS_rwlock_t *lock, bool *acquired)
{
    int ret;

    
    if (H5_UNLIKELY(NULL == lock || NULL == acquired))
        return FAIL;

    ret = pthread_rwlock_trywrlock(lock);
    if (EBUSY == ret)
        *acquired = false; 
    else if (H5_UNLIKELY(0 != ret))
        return FAIL;
    else
        *acquired = true; 

    return SUCCEED;
} 

static inline herr_t
H5TS_rwlock_wrunlock(H5TS_rwlock_t *lock)
{
    
    if (H5_UNLIKELY(NULL == lock))
        return FAIL;

    if (H5_UNLIKELY(pthread_rwlock_unlock(lock)))
        return FAIL;

    return SUCCEED;
} 
#endif
#endif
