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 35extern "C" { 36#endif 37 38struct u_cnd_monotonic 39{ 40#ifdef _WIN32 41 CONDITION_VARIABLE condvar; 42#else 43 pthread_cond_t cond; 44#endif 45}; 46 47static inline int 48u_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 71static inline void 72u_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 83static inline int 84u_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 96static inline int 97u_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 109static inline int 110u_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_timedout : thrd_error; 123#else 124 int rt = pthread_cond_timedwait(&cond->cond, mtx, abs_time); 125 if (rt == ETIMEDOUT) 126 return thrd_timedout; 127 return (rt == 0) ? thrd_success : thrd_error; 128#endif 129} 130 131static inline int 132u_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