1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2016 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 semaphores using mutexes and condition variables */
24
25 #include "SDL_timer.h"
26 #include "SDL_thread.h"
27 #include "SDL_systhread_c.h"
28
29
30 #if SDL_THREADS_DISABLED
31
32 SDL_sem *
SDL_CreateSemaphore(Uint32 initial_value)33 SDL_CreateSemaphore(Uint32 initial_value)
34 {
35 SDL_SetError("SDL not built with thread support");
36 return (SDL_sem *) 0;
37 }
38
39 void
SDL_DestroySemaphore(SDL_sem * sem)40 SDL_DestroySemaphore(SDL_sem * sem)
41 {
42 }
43
44 int
SDL_SemTryWait(SDL_sem * sem)45 SDL_SemTryWait(SDL_sem * sem)
46 {
47 return SDL_SetError("SDL not built with thread support");
48 }
49
50 int
SDL_SemWaitTimeout(SDL_sem * sem,Uint32 timeout)51 SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
52 {
53 return SDL_SetError("SDL not built with thread support");
54 }
55
56 int
SDL_SemWait(SDL_sem * sem)57 SDL_SemWait(SDL_sem * sem)
58 {
59 return SDL_SetError("SDL not built with thread support");
60 }
61
62 Uint32
SDL_SemValue(SDL_sem * sem)63 SDL_SemValue(SDL_sem * sem)
64 {
65 return 0;
66 }
67
68 int
SDL_SemPost(SDL_sem * sem)69 SDL_SemPost(SDL_sem * sem)
70 {
71 return SDL_SetError("SDL not built with thread support");
72 }
73
74 #else
75
76 struct SDL_semaphore
77 {
78 Uint32 count;
79 Uint32 waiters_count;
80 SDL_mutex *count_lock;
81 SDL_cond *count_nonzero;
82 };
83
84 SDL_sem *
SDL_CreateSemaphore(Uint32 initial_value)85 SDL_CreateSemaphore(Uint32 initial_value)
86 {
87 SDL_sem *sem;
88
89 sem = (SDL_sem *) SDL_malloc(sizeof(*sem));
90 if (!sem) {
91 SDL_OutOfMemory();
92 return NULL;
93 }
94 sem->count = initial_value;
95 sem->waiters_count = 0;
96
97 sem->count_lock = SDL_CreateMutex();
98 sem->count_nonzero = SDL_CreateCond();
99 if (!sem->count_lock || !sem->count_nonzero) {
100 SDL_DestroySemaphore(sem);
101 return NULL;
102 }
103
104 return sem;
105 }
106
107 /* WARNING:
108 You cannot call this function when another thread is using the semaphore.
109 */
110 void
SDL_DestroySemaphore(SDL_sem * sem)111 SDL_DestroySemaphore(SDL_sem * sem)
112 {
113 if (sem) {
114 sem->count = 0xFFFFFFFF;
115 while (sem->waiters_count > 0) {
116 SDL_CondSignal(sem->count_nonzero);
117 SDL_Delay(10);
118 }
119 SDL_DestroyCond(sem->count_nonzero);
120 if (sem->count_lock) {
121 SDL_LockMutex(sem->count_lock);
122 SDL_UnlockMutex(sem->count_lock);
123 SDL_DestroyMutex(sem->count_lock);
124 }
125 SDL_free(sem);
126 }
127 }
128
129 int
SDL_SemTryWait(SDL_sem * sem)130 SDL_SemTryWait(SDL_sem * sem)
131 {
132 int retval;
133
134 if (!sem) {
135 return SDL_SetError("Passed a NULL semaphore");
136 }
137
138 retval = SDL_MUTEX_TIMEDOUT;
139 SDL_LockMutex(sem->count_lock);
140 if (sem->count > 0) {
141 --sem->count;
142 retval = 0;
143 }
144 SDL_UnlockMutex(sem->count_lock);
145
146 return retval;
147 }
148
149 int
SDL_SemWaitTimeout(SDL_sem * sem,Uint32 timeout)150 SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout)
151 {
152 int retval;
153
154 if (!sem) {
155 return SDL_SetError("Passed a NULL semaphore");
156 }
157
158 /* A timeout of 0 is an easy case */
159 if (timeout == 0) {
160 return SDL_SemTryWait(sem);
161 }
162
163 SDL_LockMutex(sem->count_lock);
164 ++sem->waiters_count;
165 retval = 0;
166 while ((sem->count == 0) && (retval != SDL_MUTEX_TIMEDOUT)) {
167 retval = SDL_CondWaitTimeout(sem->count_nonzero,
168 sem->count_lock, timeout);
169 }
170 --sem->waiters_count;
171 if (retval == 0) {
172 --sem->count;
173 }
174 SDL_UnlockMutex(sem->count_lock);
175
176 return retval;
177 }
178
179 int
SDL_SemWait(SDL_sem * sem)180 SDL_SemWait(SDL_sem * sem)
181 {
182 return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
183 }
184
185 Uint32
SDL_SemValue(SDL_sem * sem)186 SDL_SemValue(SDL_sem * sem)
187 {
188 Uint32 value;
189
190 value = 0;
191 if (sem) {
192 SDL_LockMutex(sem->count_lock);
193 value = sem->count;
194 SDL_UnlockMutex(sem->count_lock);
195 }
196 return value;
197 }
198
199 int
SDL_SemPost(SDL_sem * sem)200 SDL_SemPost(SDL_sem * sem)
201 {
202 if (!sem) {
203 return SDL_SetError("Passed a NULL semaphore");
204 }
205
206 SDL_LockMutex(sem->count_lock);
207 if (sem->waiters_count > 0) {
208 SDL_CondSignal(sem->count_nonzero);
209 }
210 ++sem->count;
211 SDL_UnlockMutex(sem->count_lock);
212
213 return 0;
214 }
215
216 #endif /* SDL_THREADS_DISABLED */
217 /* vi: set ts=4 sw=4 expandtab: */
218