/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * 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.                                                        *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#if !(defined H5TS_FRIEND || defined H5TS_MODULE)
#error "Do not include this file outside the H5TS package!"
#endif

#ifndef H5TSpkg_H
#define H5TSpkg_H

#ifdef H5_HAVE_THREADS

#include "H5TSprivate.h"

#ifdef H5TS_DEBUG
#define H5TS_ENABLE_REC_RWLOCK_STATS 1
#else
#define H5TS_ENABLE_REC_RWLOCK_STATS 0
#endif

#ifdef H5_HAVE_THREADSAFE_API

typedef struct H5TS_api_info_t {
#ifdef H5_HAVE_THREADSAFE
    
    H5TS_mutex_t api_mutex;

    
    unsigned lock_count;
#else 
    
    H5TS_rwlock_t api_lock;
#endif

    
    H5TS_atomic_uint_t attempt_lock_count;
} H5TS_api_info_t;
#endif 

#if H5TS_ENABLE_REC_RWLOCK_STATS

typedef struct H5TS_rec_rwlock_stats_t {
    int64_t read_locks_granted;
    int64_t read_locks_released;
    int64_t real_read_locks_granted;
    int64_t real_read_locks_released;
    int64_t max_read_locks;
    int64_t max_read_lock_recursion_depth;
    int64_t read_locks_delayed;
    int64_t write_locks_granted;
    int64_t write_locks_released;
    int64_t real_write_locks_granted;
    int64_t real_write_locks_released;
    int64_t max_write_locks;
    int64_t max_write_lock_recursion_depth;
    int64_t write_locks_delayed;
    int64_t max_write_locks_pending;
} H5TS_rec_rwlock_stats_t;
#endif

typedef enum {
    H5TS_REC_RWLOCK_UNUSED = 0, 
    H5TS_REC_RWLOCK_WRITE,      
    H5TS_REC_RWLOCK_READ        
} H5TS_rec_rwlock_type_t;

typedef struct H5TS_rec_rwlock_t {
    
    H5TS_mutex_t           mutex;
    H5TS_rec_rwlock_type_t lock_type;

    
    H5TS_cond_t   writers_cv;
    H5TS_thread_t write_thread;
    int32_t       rec_write_lock_count;
    int32_t       waiting_writers_count;

    
    H5TS_cond_t readers_cv;
    int32_t     reader_thread_count;
    H5TS_key_t  rec_read_lock_count_key;
    bool        is_key_registered;

#if H5TS_ENABLE_REC_RWLOCK_STATS
    
    H5TS_rec_rwlock_stats_t stats;
#endif
} H5TS_rec_rwlock_t;

#ifdef H5_HAVE_THREADSAFE_API

extern H5TS_api_info_t H5TS_api_info_p;

extern H5TS_key_t H5TS_thrd_info_key_g;
#endif 

#ifdef H5_HAVE_THREADSAFE_API
H5_DLL herr_t H5TS__init_package(void);
H5_DLL herr_t H5TS__api_mutex_acquire(unsigned lock_count, bool *acquired);
H5_DLL herr_t H5TS__api_mutex_release(unsigned *lock_count);
H5_DLL herr_t H5TS__tinfo_init(void);
H5_DLL void   H5TS__tinfo_destroy(void *tinfo_node);
H5_DLL herr_t H5TS__tinfo_term(void);
#endif 

H5_DLL herr_t H5TS__rec_rwlock_init(H5TS_rec_rwlock_t *lock);
H5_DLL herr_t H5TS__rec_rwlock_rdlock(H5TS_rec_rwlock_t *lock);
H5_DLL herr_t H5TS__rec_rwlock_wrlock(H5TS_rec_rwlock_t *lock);
H5_DLL herr_t H5TS__rec_rwlock_rdunlock(H5TS_rec_rwlock_t *lock);
H5_DLL herr_t H5TS__rec_rwlock_wrunlock(H5TS_rec_rwlock_t *lock);
H5_DLL herr_t H5TS__rec_rwlock_destroy(H5TS_rec_rwlock_t *lock);

#ifdef H5_HAVE_THREADSAFE_API
#ifdef H5_HAVE_C11_THREADS
H5_DLL void H5TS__c11_first_thread_init(void);
#else
#ifdef H5_HAVE_WIN_THREADS
H5_DLL BOOL CALLBACK H5TS__win32_process_enter(PINIT_ONCE InitOnce, PVOID Parameter, PVOID *lpContex);
#else
H5_DLL void H5TS__pthread_first_thread_init(void);
#endif 
#endif
#endif 

#if H5TS_ENABLE_REC_RWLOCK_STATS
H5_DLL herr_t H5TS__rec_rwlock_get_stats(H5TS_rec_rwlock_t *lock, H5TS_rec_rwlock_stats_t *stats);
H5_DLL herr_t H5TS__rec_rwlock_reset_stats(H5TS_rec_rwlock_t *lock);
H5_DLL herr_t H5TS__rec_rwlock_print_stats(const char *header_str, H5TS_rec_rwlock_stats_t *stats);
#endif

#endif 

#endif 
