Home | History | Annotate | Line # | Download | only in util
      1 /**************************************************************************
      2  *
      3  * Copyright 2020 Lag Free Games, LLC
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #ifndef CND_MONOTONIC_H
     29 #define CND_MONOTONIC_H
     30 
     31 #include "c11/threads.h"
     32 #include "util/os_time.h"
     33 
     34 #ifdef __cplusplus
     35 extern "C" {
     36 #endif
     37 
     38 struct u_cnd_monotonic
     39 {
     40 #ifdef _WIN32
     41    CONDITION_VARIABLE condvar;
     42 #else
     43    pthread_cond_t cond;
     44 #endif
     45 };
     46 
     47 static inline int
     48 u_cnd_monotonic_init(struct u_cnd_monotonic *cond)
     49 {
     50    assert(cond != NULL);
     51 
     52 #ifdef _WIN32
     53    InitializeConditionVariable(&cond->condvar);
     54    return thrd_success;
     55 #else
     56    int ret = thrd_error;
     57    pthread_condattr_t condattr;
     58    if (pthread_condattr_init(&condattr) == 0) {
     59       if ((pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC) == 0) &&
     60          (pthread_cond_init(&cond->cond, &condattr) == 0)) {
     61          ret = thrd_success;
     62       }
     63 
     64       pthread_condattr_destroy(&condattr);
     65    }
     66 
     67    return ret;
     68 #endif
     69 }
     70 
     71 static inline void
     72 u_cnd_monotonic_destroy(struct u_cnd_monotonic *cond)
     73 {
     74    assert(cond != NULL);
     75 
     76 #ifdef _WIN32
     77    // Do nothing
     78 #else
     79    pthread_cond_destroy(&cond->cond);
     80 #endif
     81 }
     82 
     83 static inline int
     84 u_cnd_monotonic_broadcast(struct u_cnd_monotonic *cond)
     85 {
     86    assert(cond != NULL);
     87 
     88 #ifdef _WIN32
     89    WakeAllConditionVariable(&cond->condvar);
     90    return thrd_success;
     91 #else
     92    return (pthread_cond_broadcast(&cond->cond) == 0) ? thrd_success : thrd_error;
     93 #endif
     94 }
     95 
     96 static inline int
     97 u_cnd_monotonic_signal(struct u_cnd_monotonic *cond)
     98 {
     99    assert(cond != NULL);
    100 
    101 #ifdef _WIN32
    102    WakeConditionVariable(&cond->condvar);
    103    return thrd_success;
    104 #else
    105    return (pthread_cond_signal(&cond->cond) == 0) ? thrd_success : thrd_error;
    106 #endif
    107 }
    108 
    109 static inline int
    110 u_cnd_monotonic_timedwait(struct u_cnd_monotonic *cond, mtx_t *mtx, const struct timespec *abs_time)
    111 {
    112    assert(cond != NULL);
    113    assert(mtx != NULL);
    114    assert(abs_time != NULL);
    115 
    116 #ifdef _WIN32
    117    const uint64_t future = (abs_time->tv_sec * 1000) + (abs_time->tv_nsec / 1000000);
    118    const uint64_t now = os_time_get_nano() / 1000000;
    119    const DWORD timeout = (future > now) ? (DWORD)(future - now) : 0;
    120    if (SleepConditionVariableCS(&cond->condvar, mtx, timeout))
    121       return thrd_success;
    122    return (GetLastError() == ERROR_TIMEOUT) ? thrd_busy : thrd_error;
    123 #else
    124    int rt = pthread_cond_timedwait(&cond->cond, mtx, abs_time);
    125    if (rt == ETIMEDOUT)
    126       return thrd_busy;
    127    return (rt == 0) ? thrd_success : thrd_error;
    128 #endif
    129 }
    130 
    131 static inline int
    132 u_cnd_monotonic_wait(struct u_cnd_monotonic *cond, mtx_t *mtx)
    133 {
    134    assert(cond != NULL);
    135    assert(mtx != NULL);
    136 
    137 #ifdef _WIN32
    138    SleepConditionVariableCS(&cond->condvar, mtx, INFINITE);
    139    return thrd_success;
    140 #else
    141    return (pthread_cond_wait(&cond->cond, mtx) == 0) ? thrd_success : thrd_error;
    142 #endif
    143 }
    144 
    145 #ifdef __cplusplus
    146 }
    147 #endif
    148 
    149 #endif
    150