Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/sdl/thread/generic/SDL_syscond.c
10279 views
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
42
typedef 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
52
SDL_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
72
void 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
90
void 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
114
void 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
149
Typical use:
150
151
Thread A:
152
SDL_LockMutex(lock);
153
while ( ! condition ) {
154
SDL_WaitCondition(cond, lock);
155
}
156
SDL_UnlockMutex(lock);
157
158
Thread B:
159
SDL_LockMutex(lock);
160
...
161
condition = true;
162
...
163
SDL_SignalCondition(cond);
164
SDL_UnlockMutex(lock);
165
*/
166
bool 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
212
bool SDL_WaitConditionTimeoutNS(SDL_Condition *cond, SDL_Mutex *mutex, Sint64 timeoutNS)
213
{
214
return SDL_WaitConditionTimeoutNS_generic(cond, mutex, timeoutNS);
215
}
216
#endif
217
218