/** * Copyright (c) 2013-2021 UChicago Argonne, LLC and The HDF Group. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MERCURY_THREAD_CONDITION_H #define MERCURY_THREAD_CONDITION_H #include "mercury_thread_mutex.h" #ifdef _WIN32 typedef CONDITION_VARIABLE hg_thread_cond_t; #else #if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE) #include #elif defined(HG_UTIL_HAS_SYSTIME_H) #include #endif #include typedef pthread_cond_t hg_thread_cond_t; #endif #ifdef __cplusplus extern "C" { #endif /** * Initialize the condition. * * \param cond [IN/OUT] pointer to condition object * * \return Non-negative on success or negative on failure */ HG_UTIL_PUBLIC int hg_thread_cond_init(hg_thread_cond_t *cond); /** * Destroy the condition. * * \param cond [IN/OUT] pointer to condition object * * \return Non-negative on success or negative on failure */ HG_UTIL_PUBLIC int hg_thread_cond_destroy(hg_thread_cond_t *cond); /** * Wake one thread waiting for the condition to change. * * \param cond [IN/OUT] pointer to condition object * * \return Non-negative on success or negative on failure */ static HG_UTIL_INLINE int hg_thread_cond_signal(hg_thread_cond_t *cond); /** * Wake all the threads waiting for the condition to change. * * \param cond [IN/OUT] pointer to condition object * * \return Non-negative on success or negative on failure */ static HG_UTIL_INLINE int hg_thread_cond_broadcast(hg_thread_cond_t *cond); /** * Wait for the condition to change. * * \param cond [IN/OUT] pointer to condition object * \param mutex [IN/OUT] pointer to mutex object * * \return Non-negative on success or negative on failure */ static HG_UTIL_INLINE int hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex); /** * Wait timeout ms for the condition to change. * * \param cond [IN/OUT] pointer to condition object * \param mutex [IN/OUT] pointer to mutex object * \param timeout [IN] timeout (in milliseconds) * * \return Non-negative on success or negative on failure */ static HG_UTIL_INLINE int hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex, unsigned int timeout); /*---------------------------------------------------------------------------*/ static HG_UTIL_INLINE int hg_thread_cond_signal(hg_thread_cond_t *cond) { #ifdef _WIN32 WakeConditionVariable(cond); #else if (pthread_cond_signal(cond)) return HG_UTIL_FAIL; #endif return HG_UTIL_SUCCESS; } /*---------------------------------------------------------------------------*/ static HG_UTIL_INLINE int hg_thread_cond_broadcast(hg_thread_cond_t *cond) { #ifdef _WIN32 WakeAllConditionVariable(cond); #else if (pthread_cond_broadcast(cond)) return HG_UTIL_FAIL; #endif return HG_UTIL_SUCCESS; } /*---------------------------------------------------------------------------*/ static HG_UTIL_INLINE int hg_thread_cond_wait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex) { #ifdef _WIN32 if (!SleepConditionVariableCS(cond, mutex, INFINITE)) return HG_UTIL_FAIL; #else if (pthread_cond_wait(cond, mutex)) return HG_UTIL_FAIL; #endif return HG_UTIL_SUCCESS; } /*---------------------------------------------------------------------------*/ static HG_UTIL_INLINE int hg_thread_cond_timedwait(hg_thread_cond_t *cond, hg_thread_mutex_t *mutex, unsigned int timeout) { #ifdef _WIN32 if (!SleepConditionVariableCS(cond, mutex, timeout)) return HG_UTIL_FAIL; #else #if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE) struct timespec now; #else struct timeval now; #endif struct timespec abs_timeout; ldiv_t ld; /* Need to convert timeout (ms) to absolute time */ #if defined(HG_UTIL_HAS_PTHREAD_CONDATTR_SETCLOCK) && defined(HG_UTIL_HAS_CLOCK_MONOTONIC_COARSE) clock_gettime(CLOCK_MONOTONIC_COARSE, &now); /* Get sec / nsec */ ld = ldiv(now.tv_nsec + timeout * 1000000L, 1000000000L); abs_timeout.tv_nsec = ld.rem; #elif defined(HG_UTIL_HAS_SYSTIME_H) gettimeofday(&now, NULL); /* Get sec / usec */ ld = ldiv(now.tv_usec + timeout * 1000L, 1000000L); abs_timeout.tv_nsec = ld.rem * 1000L; #endif abs_timeout.tv_sec = now.tv_sec + ld.quot; if (pthread_cond_timedwait(cond, mutex, &abs_timeout)) return HG_UTIL_FAIL; #endif return HG_UTIL_SUCCESS; } #ifdef __cplusplus } #endif #endif /* MERCURY_THREAD_CONDITION_H */