Atlas - SDL_syscond.c

Home / ext / SDL / src / thread / generic Lines: 1 | Size: 6905 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23// An implementation of condition variables using semaphores and mutexes 24/* 25 This implementation borrows heavily from the BeOS condition variable 26 implementation, written by Christopher Tate and Owen Smith. Thanks! 27 */ 28 29#include "../generic/SDL_syscond_c.h" 30 31/* If two implementations are to be compiled into SDL (the active one 32 * will be chosen at runtime), the function names need to be 33 * suffixed 34 */ 35#ifndef SDL_THREAD_GENERIC_COND_SUFFIX 36#define SDL_CreateCondition_generic SDL_CreateCondition 37#define SDL_DestroyCondition_generic SDL_DestroyCondition 38#define SDL_SignalCondition_generic SDL_SignalCondition 39#define SDL_BroadcastCondition_generic SDL_BroadcastCondition 40#endif 41 42typedef struct SDL_cond_generic 43{ 44 SDL_Semaphore *sem; 45 SDL_Semaphore *handshake_sem; 46 SDL_Semaphore *signal_sem; 47 int num_waiting; 48 int num_signals; 49} SDL_cond_generic; 50 51// Create a condition variable 52SDL_Condition *SDL_CreateCondition_generic(void) 53{ 54 SDL_cond_generic *cond = (SDL_cond_generic *)SDL_calloc(1, sizeof(*cond)); 55 56#ifndef SDL_THREADS_DISABLED 57 if (cond) { 58 cond->sem = SDL_CreateSemaphore(0); 59 cond->handshake_sem = SDL_CreateSemaphore(0); 60 cond->signal_sem = SDL_CreateSemaphore(1); 61 if (!cond->sem || !cond->handshake_sem || !cond->signal_sem) { 62 SDL_DestroyCondition_generic((SDL_Condition *)cond); 63 cond = NULL; 64 } 65 } 66#endif 67 68 return (SDL_Condition *)cond; 69} 70 71// Destroy a condition variable 72void SDL_DestroyCondition_generic(SDL_Condition *_cond) 73{ 74 SDL_cond_generic *cond = (SDL_cond_generic *)_cond; 75 if (cond) { 76 if (cond->sem) { 77 SDL_DestroySemaphore(cond->sem); 78 } 79 if (cond->handshake_sem) { 80 SDL_DestroySemaphore(cond->handshake_sem); 81 } 82 if (cond->signal_sem) { 83 SDL_DestroySemaphore(cond->signal_sem); 84 } 85 SDL_free(cond); 86 } 87} 88 89// Restart one of the threads that are waiting on the condition variable 90void SDL_SignalCondition_generic(SDL_Condition *_cond) 91{ 92 SDL_cond_generic *cond = (SDL_cond_generic *)_cond; 93 if (!cond) { 94 return; 95 } 96 97#ifndef SDL_THREADS_DISABLED 98 /* If there are waiting threads not already signalled, then 99 signal the condition and wait for the thread to respond. 100 */ 101 SDL_WaitSemaphore(cond->signal_sem); 102 if (cond->num_waiting > cond->num_signals) { 103 cond->num_signals++; 104 SDL_SignalSemaphore(cond->sem); 105 SDL_SignalSemaphore(cond->signal_sem); 106 SDL_WaitSemaphore(cond->handshake_sem); 107 } else { 108 SDL_SignalSemaphore(cond->signal_sem); 109 } 110#endif 111} 112 113// Restart all threads that are waiting on the condition variable 114void SDL_BroadcastCondition_generic(SDL_Condition *_cond) 115{ 116 SDL_cond_generic *cond = (SDL_cond_generic *)_cond; 117 if (!cond) { 118 return; 119 } 120 121#ifndef SDL_THREADS_DISABLED 122 /* If there are waiting threads not already signalled, then 123 signal the condition and wait for the thread to respond. 124 */ 125 SDL_WaitSemaphore(cond->signal_sem); 126 if (cond->num_waiting > cond->num_signals) { 127 const int num_waiting = (cond->num_waiting - cond->num_signals); 128 cond->num_signals = cond->num_waiting; 129 for (int i = 0; i < num_waiting; i++) { 130 SDL_SignalSemaphore(cond->sem); 131 } 132 /* Now all released threads are blocked here, waiting for us. 133 Collect them all (and win fabulous prizes!) :-) 134 */ 135 SDL_SignalSemaphore(cond->signal_sem); 136 for (int i = 0; i < num_waiting; i++) { 137 SDL_WaitSemaphore(cond->handshake_sem); 138 } 139 } else { 140 SDL_SignalSemaphore(cond->signal_sem); 141 } 142#endif 143} 144 145/* Wait on the condition variable for at most 'timeoutNS' nanoseconds. 146 The mutex must be locked before entering this function! 147 The mutex is unlocked during the wait, and locked again after the wait. 148 149Typical use: 150 151Thread A: 152 SDL_LockMutex(lock); 153 while ( ! condition ) { 154 SDL_WaitCondition(cond, lock); 155 } 156 SDL_UnlockMutex(lock); 157 158Thread B: 159 SDL_LockMutex(lock); 160 ... 161 condition = true; 162 ... 163 SDL_SignalCondition(cond); 164 SDL_UnlockMutex(lock); 165 */ 166bool SDL_WaitConditionTimeoutNS_generic(SDL_Condition *_cond, SDL_Mutex *mutex, Sint64 timeoutNS) 167{ 168 SDL_cond_generic *cond = (SDL_cond_generic *)_cond; 169 bool result = true; 170 171 if (!cond || !mutex) { 172 return true; 173 } 174 175#ifndef SDL_THREADS_DISABLED 176 /* Obtain the protection mutex, and increment the number of waiters. 177 This allows the signal mechanism to only perform a signal if there 178 are waiting threads. 179 */ 180 SDL_WaitSemaphore(cond->signal_sem); 181 cond->num_waiting++; 182 SDL_SignalSemaphore(cond->signal_sem); 183 184 // Unlock the mutex, as is required by condition variable semantics 185 SDL_UnlockMutex(mutex); 186 187 // Wait for a signal 188 result = SDL_WaitSemaphoreTimeoutNS(cond->sem, timeoutNS); 189 190 /* Let the signaler know we have completed the wait, otherwise 191 the signaler can race ahead and get the condition semaphore 192 if we are stopped between the mutex unlock and semaphore wait, 193 giving a deadlock. See the following URL for details: 194 http://web.archive.org/web/20010914175514/http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html#Workshop 195 */ 196 SDL_WaitSemaphore(cond->signal_sem); 197 if (cond->num_signals > 0) { 198 SDL_SignalSemaphore(cond->handshake_sem); 199 cond->num_signals--; 200 } 201 cond->num_waiting--; 202 SDL_SignalSemaphore(cond->signal_sem); 203 204 // Lock the mutex, as is required by condition variable semantics 205 SDL_LockMutex(mutex); 206#endif 207 208 return result; 209} 210 211#ifndef SDL_THREAD_GENERIC_COND_SUFFIX 212bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS) 213{ 214 return SDL_WaitConditionTimeoutNS_generic(cond, mutex, timeoutNS); 215} 216#endif 217
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.