1 /* EINA - EFL data type library
2 * Copyright (C) 2011 Vincent Torri
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.
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.
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/>.
19 #ifndef EINA_INLINE_LOCK_WIN32_X_
20 #define EINA_INLINE_LOCK_WIN32_X_
26 # define EINA_UNUSED __attribute__((unused))
33 typedef CRITICAL_SECTION Eina_Lock;
34 typedef struct _Eina_Condition Eina_Condition;
35 typedef struct _Eina_RWLock Eina_RWLock;
36 typedef DWORD Eina_TLS;
37 typedef HANDLE Eina_Semaphore;
39 #if _WIN32_WINNT >= 0x0600
40 struct _Eina_Condition
42 CRITICAL_SECTION *mutex;
43 CONDITION_VARIABLE condition;
50 Eina_Bool is_read_mode : 1;
53 struct _Eina_Condition
56 CRITICAL_SECTION waiters_count_lock;
57 CRITICAL_SECTION *mutex;
60 Eina_Bool was_broadcast;
71 Eina_Condition cond_read;
72 Eina_Condition cond_write;
77 EAPI extern Eina_Bool _eina_threads_activated;
80 static inline Eina_Bool
81 eina_lock_new(Eina_Lock *mutex)
83 InitializeCriticalSection(mutex);
89 eina_lock_free(Eina_Lock *mutex)
91 DeleteCriticalSection(mutex);
94 static inline Eina_Lock_Result
95 eina_lock_take(Eina_Lock *mutex)
97 #ifdef EINA_HAVE_ON_OFF_THREADS
98 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
101 EnterCriticalSection(mutex);
103 return EINA_LOCK_SUCCEED;
106 static inline Eina_Lock_Result
107 eina_lock_take_try(Eina_Lock *mutex)
109 #ifdef EINA_HAVE_ON_OFF_THREADS
110 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
113 return TryEnterCriticalSection(mutex) == 0 ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED;
116 static inline Eina_Lock_Result
117 eina_lock_release(Eina_Lock *mutex)
119 #ifdef EINA_HAVE_ON_OFF_THREADS
120 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
123 LeaveCriticalSection(mutex);
125 return EINA_LOCK_SUCCEED;
129 eina_lock_debug(const Eina_Lock *mutex)
134 static inline Eina_Bool
135 eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
138 #if _WIN32_WINNT >= 0x0600
139 InitializeConditionVariable(&cond->condition);
141 cond->waiters_count = 0;
142 cond->was_broadcast = EINA_FALSE;
143 cond->semaphore = CreateSemaphore(NULL, // no security
145 0x7fffffff, // max count
147 if (!cond->semaphore)
150 InitializeCriticalSection(&cond->waiters_count_lock);
152 cond->waiters_done = CreateEvent(NULL, // no security
154 FALSE, // non-signaled initially
156 if (!cond->waiters_done)
158 CloseHandle(cond->semaphore);
167 eina_condition_free(Eina_Condition *cond)
169 #if _WIN32_WINNT >= 0x0600
173 CloseHandle(cond->waiters_done);
174 DeleteCriticalSection(&cond->waiters_count_lock);
175 CloseHandle(cond->semaphore);
179 static inline Eina_Bool
180 _eina_condition_internal_timedwait(Eina_Condition *cond, DWORD t)
182 #if _WIN32_WINNT >= 0x0600
183 SleepConditionVariableCS(&cond->condition, cond->mutex, t);
186 Eina_Bool last_waiter;
188 /* Avoid race conditions. */
189 EnterCriticalSection(&cond->waiters_count_lock);
190 cond->waiters_count++;
191 LeaveCriticalSection(&cond->waiters_count_lock);
194 * This call atomically releases the mutex and waits on the
195 * semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
196 * are called by another thread.
198 ret = SignalObjectAndWait(cond->mutex, cond->semaphore, t, FALSE);
199 if (ret == WAIT_FAILED)
202 /* Reacquire lock to avoid race conditions. */
203 EnterCriticalSection(&cond->waiters_count_lock);
205 /* We're no longer waiting... */
206 cond->waiters_count--;
208 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
209 last_waiter = (cond->was_broadcast) && (cond->waiters_count == 0);
211 LeaveCriticalSection(&cond->waiters_count_lock);
214 * If we're the last waiter thread during this particular broadcast
215 * then let all the other threads proceed.
220 * This call atomically signals the <waiters_done_> event and waits until
221 * it can acquire the <external_mutex>. This is required to ensure fairness.
223 ret = SignalObjectAndWait(cond->waiters_done, cond->mutex, t, FALSE);
224 if (ret == WAIT_FAILED)
230 * Always regain the external mutex since that's the guarantee we
231 * give to our callers.
233 ret = WaitForSingleObject(cond->mutex, t);
234 if (ret == WAIT_FAILED)
242 static inline Eina_Bool
243 eina_condition_timedwait(Eina_Condition *cond, double val)
245 return _eina_condition_internal_timedwait(cond, (DWORD)(val * 1000));
248 static inline Eina_Bool
249 eina_condition_wait(Eina_Condition *cond)
251 return _eina_condition_internal_timedwait(cond, INFINITE);
254 static inline Eina_Bool
255 eina_condition_broadcast(Eina_Condition *cond)
257 #if _WIN32_WINNT >= 0x0600
258 WakeAllConditionVariable(&cond->condition);
261 Eina_Bool have_waiters;
264 * This is needed to ensure that <waiters_count_> and <was_broadcast_> are
265 * consistent relative to each other.
267 EnterCriticalSection(&cond->waiters_count_lock);
268 have_waiters = EINA_FALSE;
270 if (cond->waiters_count > 0)
273 * We are broadcasting, even if there is just one waiter...
274 * Record that we are broadcasting, which helps optimize
275 * <pthread_cond_wait> for the non-broadcast case.
277 cond->was_broadcast = EINA_TRUE;
278 have_waiters = EINA_TRUE;
285 /* Wake up all the waiters atomically. */
286 ret = ReleaseSemaphore(cond->semaphore, cond->waiters_count, 0);
287 LeaveCriticalSection(&cond->waiters_count_lock);
288 if (!ret) return EINA_FALSE;
291 * Wait for all the awakened threads to acquire the counting
294 ret = WaitForSingleObject(cond->waiters_done, INFINITE);
295 if (ret == WAIT_FAILED)
298 * This assignment is okay, even without the <waiters_count_lock_> held
299 * because no other waiter threads can wake up to access it.
301 cond->was_broadcast = EINA_FALSE;
304 LeaveCriticalSection(&cond->waiters_count_lock);
310 static inline Eina_Bool
311 eina_condition_signal(Eina_Condition *cond)
313 #if _WIN32_WINNT >= 0x0600
314 WakeConditionVariable(&cond->condition);
316 Eina_Bool have_waiters;
318 EnterCriticalSection(&cond->waiters_count_lock);
319 have_waiters = (cond->waiters_count > 0);
320 LeaveCriticalSection(&cond->waiters_count_lock);
322 /* If there aren't any waiters, then this is a no-op. */
325 if (!ReleaseSemaphore(cond->semaphore, 1, 0))
333 static inline Eina_Bool
334 eina_rwlock_new(Eina_RWLock *mutex)
336 #if _WIN32_WINNT >= 0x0600
337 InitializeSRWLock(&mutex->mutex);
340 if (!eina_lock_new(&(mutex->mutex))) return EINA_FALSE;
341 if (!eina_condition_new(&(mutex->cond_read), &(mutex->mutex)))
343 if (!eina_condition_new(&(mutex->cond_write), &(mutex->mutex)))
346 mutex->readers_count = 0;
347 mutex->writers_count = 0;
354 eina_condition_free(&(mutex->cond_read));
356 eina_lock_free(&(mutex->mutex));
362 eina_rwlock_free(Eina_RWLock *mutex)
364 #if _WIN32_WINNT >= 0x0600
367 eina_condition_free(&(mutex->cond_read));
368 eina_condition_free(&(mutex->cond_write));
369 eina_lock_free(&(mutex->mutex));
373 static inline Eina_Lock_Result
374 eina_rwlock_take_read(Eina_RWLock *mutex)
376 #if _WIN32_WINNT >= 0x0600
377 AcquireSRWLockShared(&mutex->mutex);
378 mutex->is_read_mode = EINA_TRUE;
382 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
383 return EINA_LOCK_FAIL;
387 mutex->readers_count++;
388 while (mutex->writers)
390 EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
391 mutex->cond_read.waiters_count++;
392 LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
393 res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
394 if (res != WAIT_OBJECT_0) break;
396 mutex->readers_count--;
400 eina_lock_release(&(mutex->mutex));
403 return EINA_LOCK_SUCCEED;
406 static inline Eina_Lock_Result
407 eina_rwlock_take_write(Eina_RWLock *mutex)
409 #if _WIN32_WINNT >= 0x0600
410 AcquireSRWLockExclusive(&mutex->mutex);
411 mutex->is_read_mode = EINA_FALSE;
415 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
416 return EINA_LOCK_FAIL;
418 if (mutex->writers || mutex->readers > 0)
420 mutex->writers_count++;
421 while (mutex->writers || mutex->readers > 0)
423 EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
424 mutex->cond_read.waiters_count++;
425 LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
426 res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
427 if (res != WAIT_OBJECT_0) break;
429 mutex->writers_count--;
431 if (res == 0) mutex->writers = 1;
432 eina_lock_release(&(mutex->mutex));
435 return EINA_LOCK_SUCCEED;
438 static inline Eina_Lock_Result
439 eina_rwlock_release(Eina_RWLock *mutex)
441 #if _WIN32_WINNT >= 0x0600
442 if (mutex->is_read_mode)
443 ReleaseSRWLockShared(&mutex->mutex);
445 ReleaseSRWLockExclusive(&mutex->mutex);
447 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
448 return EINA_LOCK_FAIL;
453 if (mutex->readers_count == 1)
455 EnterCriticalSection(&mutex->cond_read.waiters_count_lock);
456 if (mutex->cond_read.waiters_count > 0)
457 ReleaseSemaphore(mutex->cond_read.semaphore, 1, 0);
458 LeaveCriticalSection(&mutex->cond_read.waiters_count_lock);
460 else if (mutex->readers_count > 0)
461 eina_condition_broadcast(&(mutex->cond_read));
462 else if (mutex->writers_count > 0)
464 EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
465 if (mutex->cond_write.waiters_count > 0)
466 ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
467 LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
470 else if (mutex->readers > 0)
473 if (mutex->readers == 0 && mutex->writers_count > 0)
475 EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
476 if (mutex->cond_write.waiters_count > 0)
477 ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
478 LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
481 eina_lock_release(&(mutex->mutex));
484 return EINA_LOCK_SUCCEED;
487 static inline Eina_Bool
488 eina_tls_new(Eina_TLS *key)
490 if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
496 eina_tls_free(Eina_TLS key)
502 eina_tls_get(Eina_TLS key)
504 return (void*)TlsGetValue(key);
507 static inline Eina_Bool
508 eina_tls_set(Eina_TLS key, const void *data)
510 if (TlsSetValue(key, (LPVOID)data) == 0)
515 static inline Eina_Bool
516 eina_semaphore_new(Eina_Semaphore *sem, int count_init)
518 if (!sem || (count_init <= 0))
521 *sem = CreateSemaphore(NULL, count_init, 32767, NULL);
526 static inline Eina_Bool
527 eina_semaphore_free(Eina_Semaphore *sem)
535 static inline Eina_Bool
536 eina_semaphore_lock(Eina_Semaphore *sem)
543 res = WaitForSingleObject(*sem, 0L);
544 if (res == WAIT_OBJECT_0)
550 static inline Eina_Bool
551 eina_semaphore_release(Eina_Semaphore *sem, int count_release)
556 return ReleaseSemaphore(*sem, count_release, NULL) ? EINA_TRUE : EINA_FALSE;