diff options
Diffstat (limited to 'libraries/eina/src/include/eina_inline_lock_win32.x')
-rw-r--r-- | libraries/eina/src/include/eina_inline_lock_win32.x | 466 |
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 | |||
24 | typedef CRITICAL_SECTION Eina_Lock; | ||
25 | typedef struct _Eina_Condition Eina_Condition; | ||
26 | |||
27 | #if _WIN32_WINNT >= 0x0600 | ||
28 | struct _Eina_Condition | ||
29 | { | ||
30 | CRITICAL_SECTION *mutex; | ||
31 | CONDITION_VARIABLE condition; | ||
32 | }; | ||
33 | #else | ||
34 | struct _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 | |||
45 | typedef struct _Eina_Win32_RWLock Eina_RWLock; | ||
46 | |||
47 | struct _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 | |||
59 | typedef DWORD Eina_TLS; | ||
60 | |||
61 | EAPI extern Eina_Bool _eina_threads_activated; | ||
62 | |||
63 | static inline Eina_Bool | ||
64 | eina_lock_new(Eina_Lock *mutex) | ||
65 | { | ||
66 | InitializeCriticalSection(mutex); | ||
67 | |||
68 | return EINA_TRUE; | ||
69 | } | ||
70 | |||
71 | static inline void | ||
72 | eina_lock_free(Eina_Lock *mutex) | ||
73 | { | ||
74 | DeleteCriticalSection(mutex); | ||
75 | } | ||
76 | |||
77 | static inline Eina_Lock_Result | ||
78 | eina_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 | |||
89 | static inline Eina_Lock_Result | ||
90 | eina_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 | |||
99 | static inline Eina_Lock_Result | ||
100 | eina_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 | |||
111 | static inline void | ||
112 | eina_lock_debug(const Eina_Lock *mutex) | ||
113 | { | ||
114 | (void)mutex; | ||
115 | } | ||
116 | |||
117 | static inline Eina_Bool | ||
118 | eina_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 | |||
149 | static inline void | ||
150 | eina_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 | |||
161 | static 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 | |||
224 | static inline Eina_Bool | ||
225 | eina_condition_timedwait(Eina_Condition *cond, double val) | ||
226 | { | ||
227 | return _eina_condition_internal_timedwait(cond, (DWORD)(val * 1000)); | ||
228 | } | ||
229 | |||
230 | static inline Eina_Bool | ||
231 | eina_condition_wait(Eina_Condition *cond) | ||
232 | { | ||
233 | return _eina_condition_internal_timedwait(cond, INFINITE); | ||
234 | } | ||
235 | |||
236 | static inline Eina_Bool | ||
237 | eina_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 | |||
292 | static inline Eina_Bool | ||
293 | eina_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 | |||
315 | static inline Eina_Bool | ||
316 | eina_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 | |||
333 | static inline void | ||
334 | eina_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 | |||
341 | static inline Eina_Lock_Result | ||
342 | eina_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 | |||
369 | static inline Eina_Lock_Result | ||
370 | eina_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 | |||
396 | static inline Eina_Lock_Result | ||
397 | eina_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 | |||
438 | static inline Eina_Bool | ||
439 | eina_tls_new(Eina_TLS *key) | ||
440 | { | ||
441 | if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES) | ||
442 | return EINA_FALSE; | ||
443 | return EINA_TRUE; | ||
444 | } | ||
445 | |||
446 | static inline void | ||
447 | eina_tls_free(Eina_TLS key) | ||
448 | { | ||
449 | TlsFree(key); | ||
450 | } | ||
451 | |||
452 | static inline void * | ||
453 | eina_tls_get(Eina_TLS key) | ||
454 | { | ||
455 | return (void*)TlsGetValue(key); | ||
456 | } | ||
457 | |||
458 | static inline Eina_Bool | ||
459 | eina_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 | ||