summaryrefslogtreecommitdiff
path: root/contrib/SDL-3.2.8/src/thread/generic/SDL_syscond.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
committer3gg <3gg@shellblade.net>2025-12-27 12:03:39 -0800
commit5a079a2d114f96d4847d1ee305d5b7c16eeec50e (patch)
tree8926ab44f168acf787d8e19608857b3af0f82758 /contrib/SDL-3.2.8/src/thread/generic/SDL_syscond.c
Initial commit
Diffstat (limited to 'contrib/SDL-3.2.8/src/thread/generic/SDL_syscond.c')
-rw-r--r--contrib/SDL-3.2.8/src/thread/generic/SDL_syscond.c216
1 files changed, 216 insertions, 0 deletions
diff --git a/contrib/SDL-3.2.8/src/thread/generic/SDL_syscond.c b/contrib/SDL-3.2.8/src/thread/generic/SDL_syscond.c
new file mode 100644
index 0000000..5fdfe84
--- /dev/null
+++ b/contrib/SDL-3.2.8/src/thread/generic/SDL_syscond.c
@@ -0,0 +1,216 @@
1/*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
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