aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/include/eina_inline_lock_win32.x
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/include/eina_inline_lock_win32.x')
-rw-r--r--libraries/eina/src/include/eina_inline_lock_win32.x466
1 files changed, 466 insertions, 0 deletions
diff --git a/libraries/eina/src/include/eina_inline_lock_win32.x b/libraries/eina/src/include/eina_inline_lock_win32.x
new file mode 100644
index 0000000..072095c
--- /dev/null
+++ b/libraries/eina/src/include/eina_inline_lock_win32.x
@@ -0,0 +1,466 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2011 Vincent Torri
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef EINA_INLINE_LOCK_WIN32_X_
20#define EINA_INLINE_LOCK_WIN32_X_
21
22#include <windows.h>
23
24typedef CRITICAL_SECTION Eina_Lock;
25typedef struct _Eina_Condition Eina_Condition;
26
27#if _WIN32_WINNT >= 0x0600
28struct _Eina_Condition
29{
30 CRITICAL_SECTION *mutex;
31 CONDITION_VARIABLE condition;
32};
33#else
34struct _Eina_Condition
35{
36 int waiters_count;
37 CRITICAL_SECTION waiters_count_lock;
38 CRITICAL_SECTION *mutex;
39 HANDLE semaphore;
40 HANDLE waiters_done;
41 Eina_Bool was_broadcast;
42};
43#endif
44
45typedef struct _Eina_Win32_RWLock Eina_RWLock;
46
47struct _Eina_Win32_RWLock
48{
49 LONG readers_count;
50 LONG writers_count;
51 int readers;
52 int writers;
53
54 Eina_Lock mutex;
55 Eina_Condition cond_read;
56 Eina_Condition cond_write;
57};
58
59typedef DWORD Eina_TLS;
60
61EAPI extern Eina_Bool _eina_threads_activated;
62
63static inline Eina_Bool
64eina_lock_new(Eina_Lock *mutex)
65{
66 InitializeCriticalSection(mutex);
67
68 return EINA_TRUE;
69}
70
71static inline void
72eina_lock_free(Eina_Lock *mutex)
73{
74 DeleteCriticalSection(mutex);
75}
76
77static inline Eina_Lock_Result
78eina_lock_take(Eina_Lock *mutex)
79{
80#ifdef EINA_HAVE_ON_OFF_THREADS
81 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
82#endif
83
84 EnterCriticalSection(mutex);
85
86 return EINA_LOCK_SUCCEED;
87}
88
89static inline Eina_Lock_Result
90eina_lock_take_try(Eina_Lock *mutex)
91{
92#ifdef EINA_HAVE_ON_OFF_THREADS
93 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
94#endif
95
96 return TryEnterCriticalSection(mutex) == 0 ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED;
97}
98
99static inline Eina_Lock_Result
100eina_lock_release(Eina_Lock *mutex)
101{
102#ifdef EINA_HAVE_ON_OFF_THREADS
103 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
104#endif
105
106 LeaveCriticalSection(mutex);
107
108 return EINA_LOCK_SUCCEED;
109}
110
111static inline void
112eina_lock_debug(const Eina_Lock *mutex)
113{
114 (void)mutex;
115}
116
117static inline Eina_Bool
118eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
119{
120 cond->mutex = mutex;
121#if _WIN32_WINNT >= 0x0600
122 InitializeConditionVariable(&cond->condition);
123#else
124 cond->waiters_count = 0;
125 cond->was_broadcast = EINA_FALSE;
126 cond->semaphore = CreateSemaphore(NULL, // no security
127 0, // initially 0
128 0x7fffffff, // max count
129 NULL); // unnamed
130 if (!cond->semaphore)
131 return EINA_FALSE;
132
133 InitializeCriticalSection(&cond->waiters_count_lock);
134
135 cond->waiters_done = CreateEvent(NULL, // no security
136 FALSE, // auto-reset
137 FALSE, // non-signaled initially
138 NULL); // unnamed
139 if (!cond->waiters_done)
140 {
141 CloseHandle(cond->semaphore);
142 return EINA_FALSE;
143 }
144
145 return EINA_TRUE;
146#endif
147}
148
149static inline void
150eina_condition_free(Eina_Condition *cond)
151{
152#if _WIN32_WINNT >= 0x0600
153 /* Nothing to do */
154#else
155 CloseHandle(cond->waiters_done);
156 DeleteCriticalSection(&cond->waiters_count_lock);
157 CloseHandle(cond->semaphore);
158#endif
159}
160
161static inline Eina_Bool
162_eina_condition_internal_timedwait(Eina_Condition *cond, DWORD t)
163{
164#if _WIN32_WINNT >= 0x0600
165 SleepConditionVariableCS(&cond->condition, cond->mutex, t);
166#else
167 DWORD ret;
168 Eina_Bool last_waiter;
169
170 /* Avoid race conditions. */
171 EnterCriticalSection(&cond->waiters_count_lock);
172 cond->waiters_count++;
173 LeaveCriticalSection(&cond->waiters_count_lock);
174
175 /*
176 * This call atomically releases the mutex and waits on the
177 * semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
178 * are called by another thread.
179 */
180 ret = SignalObjectAndWait(cond->mutex, cond->semaphore, t, FALSE);
181 if (ret == WAIT_FAILED)
182 return EINA_FALSE;
183
184 /* Reacquire lock to avoid race conditions. */
185 EnterCriticalSection(&cond->waiters_count_lock);
186
187 /* We're no longer waiting... */
188 cond->waiters_count--;
189
190 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
191 last_waiter = (cond->was_broadcast) && (cond->waiters_count == 0);
192
193 LeaveCriticalSection(&cond->waiters_count_lock);
194
195 /*
196 * If we're the last waiter thread during this particular broadcast
197 * then let all the other threads proceed.
198 */
199 if (last_waiter)
200 {
201 /*
202 * This call atomically signals the <waiters_done_> event and waits until
203 * it can acquire the <external_mutex>. This is required to ensure fairness.
204 */
205 ret = SignalObjectAndWait(cond->waiters_done, cond->mutex, t, FALSE);
206 if (ret == WAIT_FAILED)
207 return EINA_FALSE;
208 }
209 else
210 {
211 /*
212 * Always regain the external mutex since that's the guarantee we
213 * give to our callers.
214 */
215 ret = WaitForSingleObject(cond->mutex, t);
216 if (ret == WAIT_FAILED)
217 return EINA_FALSE;
218 }
219#endif
220
221 return EINA_TRUE;
222}
223
224static inline Eina_Bool
225eina_condition_timedwait(Eina_Condition *cond, double val)
226{
227 return _eina_condition_internal_timedwait(cond, (DWORD)(val * 1000));
228}
229
230static inline Eina_Bool
231eina_condition_wait(Eina_Condition *cond)
232{
233 return _eina_condition_internal_timedwait(cond, INFINITE);
234}
235
236static inline Eina_Bool
237eina_condition_broadcast(Eina_Condition *cond)
238{
239#if _WIN32_WINNT >= 0x0600
240 WakeAllConditionVariable(&cond->condition);
241 return EINA_TRUE;
242#else
243 Eina_Bool have_waiters;
244
245 /*
246 * This is needed to ensure that <waiters_count_> and <was_broadcast_> are
247 * consistent relative to each other.
248 */
249 EnterCriticalSection(&cond->waiters_count_lock);
250 have_waiters = EINA_FALSE;
251
252 if (cond->waiters_count > 0)
253 {
254 /*
255 * We are broadcasting, even if there is just one waiter...
256 * Record that we are broadcasting, which helps optimize
257 * <pthread_cond_wait> for the non-broadcast case.
258 */
259 cond->was_broadcast = EINA_TRUE;
260 have_waiters = EINA_TRUE;
261 }
262
263 if (have_waiters)
264 {
265 DWORD ret;
266
267 /* Wake up all the waiters atomically. */
268 ret = ReleaseSemaphore(cond->semaphore, cond->waiters_count, 0);
269 LeaveCriticalSection(&cond->waiters_count_lock);
270 if (!ret) return EINA_FALSE;
271
272 /*
273 * Wait for all the awakened threads to acquire the counting
274 * semaphore.
275 */
276 ret = WaitForSingleObject(cond->waiters_done, INFINITE);
277 if (ret == WAIT_FAILED)
278 return EINA_FALSE;
279 /*
280 * This assignment is okay, even without the <waiters_count_lock_> held
281 * because no other waiter threads can wake up to access it.
282 */
283 cond->was_broadcast = EINA_FALSE;
284 }
285 else
286 LeaveCriticalSection(&cond->waiters_count_lock);
287
288 return EINA_TRUE;
289#endif
290}
291
292static inline Eina_Bool
293eina_condition_signal(Eina_Condition *cond)
294{
295#if _WIN32_WINNT >= 0x0600
296 WakeConditionVariable(&cond->condition);
297#else
298 Eina_Bool have_waiters;
299
300 EnterCriticalSection(&cond->waiters_count_lock);
301 have_waiters = (cond->waiters_count > 0);
302 LeaveCriticalSection(&cond->waiters_count_lock);
303
304 /* If there aren't any waiters, then this is a no-op. */
305 if (have_waiters)
306 {
307 if (!ReleaseSemaphore(cond->semaphore, 1, 0))
308 return EINA_FALSE;
309 }
310
311 return EINA_TRUE;
312#endif
313}
314
315static inline Eina_Bool
316eina_rwlock_new(Eina_RWLock *mutex)
317{
318 if (!eina_lock_new(&(mutex->mutex))) return EINA_FALSE;
319 if (!eina_condition_new(&(mutex->cond_read), &(mutex->mutex)))
320 goto on_error1;
321 if (!eina_condition_new(&(mutex->cond_write), &(mutex->mutex)))
322 goto on_error2;
323
324 return EINA_TRUE;
325
326 on_error2:
327 eina_condition_free(&(mutex->cond_read));
328 on_error1:
329 eina_lock_free(&(mutex->mutex));
330 return EINA_FALSE;
331}
332
333static inline void
334eina_rwlock_free(Eina_RWLock *mutex)
335{
336 eina_condition_free(&(mutex->cond_read));
337 eina_condition_free(&(mutex->cond_write));
338 eina_lock_free(&(mutex->mutex));
339}
340
341static inline Eina_Lock_Result
342eina_rwlock_take_read(Eina_RWLock *mutex)
343{
344 DWORD res;
345
346 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
347 return EINA_LOCK_FAIL;
348
349 if (mutex->writers)
350 {
351 mutex->readers_count++;
352 while (mutex->writers)
353 {
354 EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
355 mutex->cond_read.waiters_count++;
356 LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
357 res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
358 if (res != WAIT_OBJECT_0) break;
359 }
360 mutex->readers_count--;
361 }
362 if (res == 0)
363 mutex->readers++;
364 eina_lock_release(&(mutex->mutex));
365
366 return EINA_LOCK_SUCCEED;
367}
368
369static inline Eina_Lock_Result
370eina_rwlock_take_write(Eina_RWLock *mutex)
371{
372 DWORD res;
373
374 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
375 return EINA_LOCK_FAIL;
376
377 if (mutex->writers || mutex->readers > 0)
378 {
379 mutex->writers_count++;
380 while (mutex->writers || mutex->readers > 0)
381 {
382 EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
383 mutex->cond_read.waiters_count++;
384 LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
385 res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
386 if (res != WAIT_OBJECT_0) break;
387 }
388 mutex->writers_count--;
389 }
390 if (res == 0) mutex->writers_count = 1;
391 eina_lock_release(&(mutex->mutex));
392
393 return EINA_LOCK_SUCCEED;
394}
395
396static inline Eina_Lock_Result
397eina_rwlock_release(Eina_RWLock *mutex)
398{
399 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
400 return EINA_LOCK_FAIL;
401
402 if (mutex->writers)
403 {
404 mutex->writers = 0;
405 if (mutex->readers_count == 1)
406 {
407 EnterCriticalSection(&mutex->cond_read.waiters_count_lock);
408 if (mutex->cond_read.waiters_count > 0)
409 ReleaseSemaphore(mutex->cond_read.semaphore, 1, 0);
410 LeaveCriticalSection(&mutex->cond_read.waiters_count_lock);
411 }
412 else if (mutex->readers_count > 0)
413 eina_condition_broadcast(&(mutex->cond_read));
414 else if (mutex->writers_count > 0)
415 {
416 EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
417 if (mutex->cond_write.waiters_count > 0)
418 ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
419 LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
420 }
421 }
422 else if (mutex->readers > 0)
423 {
424 mutex->readers--;
425 if (mutex->readers == 0 && mutex->writers_count > 0)
426 {
427 EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
428 if (mutex->cond_write.waiters_count > 0)
429 ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
430 LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
431 }
432 }
433 eina_lock_release(&(mutex->mutex));
434
435 return EINA_LOCK_SUCCEED;
436}
437
438static inline Eina_Bool
439eina_tls_new(Eina_TLS *key)
440{
441 if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
442 return EINA_FALSE;
443 return EINA_TRUE;
444}
445
446static inline void
447eina_tls_free(Eina_TLS key)
448{
449 TlsFree(key);
450}
451
452static inline void *
453eina_tls_get(Eina_TLS key)
454{
455 return (void*)TlsGetValue(key);
456}
457
458static inline Eina_Bool
459eina_tls_set(Eina_TLS key, const void *data)
460{
461 if (TlsSetValue(key, (LPVOID)data) == 0)
462 return EINA_FALSE;
463 return EINA_TRUE;
464}
465
466#endif