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_
24 typedef CRITICAL_SECTION Eina_Lock;
25 typedef struct _Eina_Condition Eina_Condition;
27 #if _WIN32_WINNT >= 0x0600
28 struct _Eina_Condition
30 CRITICAL_SECTION *mutex;
31 CONDITION_VARIABLE condition;
34 struct _Eina_Condition
37 CRITICAL_SECTION waiters_count_lock;
38 CRITICAL_SECTION *mutex;
41 Eina_Bool was_broadcast;
45 typedef struct _Eina_Win32_RWLock Eina_RWLock;
47 struct _Eina_Win32_RWLock
55 Eina_Condition cond_read;
56 Eina_Condition cond_write;
59 typedef DWORD Eina_TLS;
61 typedef HANDLE Eina_Semaphore;
63 EAPI extern Eina_Bool _eina_threads_activated;
65 static inline Eina_Bool
66 eina_lock_new(Eina_Lock *mutex)
68 InitializeCriticalSection(mutex);
74 eina_lock_free(Eina_Lock *mutex)
76 DeleteCriticalSection(mutex);
79 static inline Eina_Lock_Result
80 eina_lock_take(Eina_Lock *mutex)
82 #ifdef EINA_HAVE_ON_OFF_THREADS
83 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
86 EnterCriticalSection(mutex);
88 return EINA_LOCK_SUCCEED;
91 static inline Eina_Lock_Result
92 eina_lock_take_try(Eina_Lock *mutex)
94 #ifdef EINA_HAVE_ON_OFF_THREADS
95 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
98 return TryEnterCriticalSection(mutex) == 0 ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED;
101 static inline Eina_Lock_Result
102 eina_lock_release(Eina_Lock *mutex)
104 #ifdef EINA_HAVE_ON_OFF_THREADS
105 if (!_eina_threads_activated) return EINA_LOCK_SUCCEED;
108 LeaveCriticalSection(mutex);
110 return EINA_LOCK_SUCCEED;
114 eina_lock_debug(const Eina_Lock *mutex)
119 static inline Eina_Bool
120 eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex)
123 #if _WIN32_WINNT >= 0x0600
124 InitializeConditionVariable(&cond->condition);
126 cond->waiters_count = 0;
127 cond->was_broadcast = EINA_FALSE;
128 cond->semaphore = CreateSemaphore(NULL, // no security
130 0x7fffffff, // max count
132 if (!cond->semaphore)
135 InitializeCriticalSection(&cond->waiters_count_lock);
137 cond->waiters_done = CreateEvent(NULL, // no security
139 FALSE, // non-signaled initially
141 if (!cond->waiters_done)
143 CloseHandle(cond->semaphore);
152 eina_condition_free(Eina_Condition *cond)
154 #if _WIN32_WINNT >= 0x0600
157 CloseHandle(cond->waiters_done);
158 DeleteCriticalSection(&cond->waiters_count_lock);
159 CloseHandle(cond->semaphore);
163 static inline Eina_Bool
164 _eina_condition_internal_timedwait(Eina_Condition *cond, DWORD t)
166 #if _WIN32_WINNT >= 0x0600
167 SleepConditionVariableCS(&cond->condition, cond->mutex, t);
170 Eina_Bool last_waiter;
172 /* Avoid race conditions. */
173 EnterCriticalSection(&cond->waiters_count_lock);
174 cond->waiters_count++;
175 LeaveCriticalSection(&cond->waiters_count_lock);
178 * This call atomically releases the mutex and waits on the
179 * semaphore until <pthread_cond_signal> or <pthread_cond_broadcast>
180 * are called by another thread.
182 ret = SignalObjectAndWait(cond->mutex, cond->semaphore, t, FALSE);
183 if (ret == WAIT_FAILED)
186 /* Reacquire lock to avoid race conditions. */
187 EnterCriticalSection(&cond->waiters_count_lock);
189 /* We're no longer waiting... */
190 cond->waiters_count--;
192 /* Check to see if we're the last waiter after <pthread_cond_broadcast>. */
193 last_waiter = (cond->was_broadcast) && (cond->waiters_count == 0);
195 LeaveCriticalSection(&cond->waiters_count_lock);
198 * If we're the last waiter thread during this particular broadcast
199 * then let all the other threads proceed.
204 * This call atomically signals the <waiters_done_> event and waits until
205 * it can acquire the <external_mutex>. This is required to ensure fairness.
207 ret = SignalObjectAndWait(cond->waiters_done, cond->mutex, t, FALSE);
208 if (ret == WAIT_FAILED)
214 * Always regain the external mutex since that's the guarantee we
215 * give to our callers.
217 ret = WaitForSingleObject(cond->mutex, t);
218 if (ret == WAIT_FAILED)
226 static inline Eina_Bool
227 eina_condition_timedwait(Eina_Condition *cond, double val)
229 return _eina_condition_internal_timedwait(cond, (DWORD)(val * 1000));
232 static inline Eina_Bool
233 eina_condition_wait(Eina_Condition *cond)
235 return _eina_condition_internal_timedwait(cond, INFINITE);
238 static inline Eina_Bool
239 eina_condition_broadcast(Eina_Condition *cond)
241 #if _WIN32_WINNT >= 0x0600
242 WakeAllConditionVariable(&cond->condition);
245 Eina_Bool have_waiters;
248 * This is needed to ensure that <waiters_count_> and <was_broadcast_> are
249 * consistent relative to each other.
251 EnterCriticalSection(&cond->waiters_count_lock);
252 have_waiters = EINA_FALSE;
254 if (cond->waiters_count > 0)
257 * We are broadcasting, even if there is just one waiter...
258 * Record that we are broadcasting, which helps optimize
259 * <pthread_cond_wait> for the non-broadcast case.
261 cond->was_broadcast = EINA_TRUE;
262 have_waiters = EINA_TRUE;
269 /* Wake up all the waiters atomically. */
270 ret = ReleaseSemaphore(cond->semaphore, cond->waiters_count, 0);
271 LeaveCriticalSection(&cond->waiters_count_lock);
272 if (!ret) return EINA_FALSE;
275 * Wait for all the awakened threads to acquire the counting
278 ret = WaitForSingleObject(cond->waiters_done, INFINITE);
279 if (ret == WAIT_FAILED)
282 * This assignment is okay, even without the <waiters_count_lock_> held
283 * because no other waiter threads can wake up to access it.
285 cond->was_broadcast = EINA_FALSE;
288 LeaveCriticalSection(&cond->waiters_count_lock);
294 static inline Eina_Bool
295 eina_condition_signal(Eina_Condition *cond)
297 #if _WIN32_WINNT >= 0x0600
298 WakeConditionVariable(&cond->condition);
300 Eina_Bool have_waiters;
302 EnterCriticalSection(&cond->waiters_count_lock);
303 have_waiters = (cond->waiters_count > 0);
304 LeaveCriticalSection(&cond->waiters_count_lock);
306 /* If there aren't any waiters, then this is a no-op. */
309 if (!ReleaseSemaphore(cond->semaphore, 1, 0))
317 static inline Eina_Bool
318 eina_rwlock_new(Eina_RWLock *mutex)
320 if (!eina_lock_new(&(mutex->mutex))) return EINA_FALSE;
321 if (!eina_condition_new(&(mutex->cond_read), &(mutex->mutex)))
323 if (!eina_condition_new(&(mutex->cond_write), &(mutex->mutex)))
329 eina_condition_free(&(mutex->cond_read));
331 eina_lock_free(&(mutex->mutex));
336 eina_rwlock_free(Eina_RWLock *mutex)
338 eina_condition_free(&(mutex->cond_read));
339 eina_condition_free(&(mutex->cond_write));
340 eina_lock_free(&(mutex->mutex));
343 static inline Eina_Lock_Result
344 eina_rwlock_take_read(Eina_RWLock *mutex)
348 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
349 return EINA_LOCK_FAIL;
353 mutex->readers_count++;
354 while (mutex->writers)
356 EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
357 mutex->cond_read.waiters_count++;
358 LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
359 res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
360 if (res != WAIT_OBJECT_0) break;
362 mutex->readers_count--;
366 eina_lock_release(&(mutex->mutex));
368 return EINA_LOCK_SUCCEED;
371 static inline Eina_Lock_Result
372 eina_rwlock_take_write(Eina_RWLock *mutex)
376 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
377 return EINA_LOCK_FAIL;
379 if (mutex->writers || mutex->readers > 0)
381 mutex->writers_count++;
382 while (mutex->writers || mutex->readers > 0)
384 EnterCriticalSection(&mutex->cond_write.waiters_count_lock);
385 mutex->cond_read.waiters_count++;
386 LeaveCriticalSection(&mutex->cond_write.waiters_count_lock);
387 res = WaitForSingleObject(mutex->cond_write.semaphore, INFINITE);
388 if (res != WAIT_OBJECT_0) break;
390 mutex->writers_count--;
392 if (res == 0) mutex->writers_count = 1;
393 eina_lock_release(&(mutex->mutex));
395 return EINA_LOCK_SUCCEED;
398 static inline Eina_Lock_Result
399 eina_rwlock_release(Eina_RWLock *mutex)
401 if (eina_lock_take(&(mutex->mutex)) == EINA_LOCK_FAIL)
402 return EINA_LOCK_FAIL;
407 if (mutex->readers_count == 1)
409 EnterCriticalSection(&mutex->cond_read.waiters_count_lock);
410 if (mutex->cond_read.waiters_count > 0)
411 ReleaseSemaphore(mutex->cond_read.semaphore, 1, 0);
412 LeaveCriticalSection(&mutex->cond_read.waiters_count_lock);
414 else if (mutex->readers_count > 0)
415 eina_condition_broadcast(&(mutex->cond_read));
416 else if (mutex->writers_count > 0)
418 EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
419 if (mutex->cond_write.waiters_count > 0)
420 ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
421 LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
424 else if (mutex->readers > 0)
427 if (mutex->readers == 0 && mutex->writers_count > 0)
429 EnterCriticalSection (&mutex->cond_write.waiters_count_lock);
430 if (mutex->cond_write.waiters_count > 0)
431 ReleaseSemaphore(mutex->cond_write.semaphore, 1, 0);
432 LeaveCriticalSection (&mutex->cond_write.waiters_count_lock);
435 eina_lock_release(&(mutex->mutex));
437 return EINA_LOCK_SUCCEED;
440 static inline Eina_Bool
441 eina_tls_new(Eina_TLS *key)
443 if ((*key = TlsAlloc()) == TLS_OUT_OF_INDEXES)
449 eina_tls_free(Eina_TLS key)
455 eina_tls_get(Eina_TLS key)
457 return (void*)TlsGetValue(key);
460 static inline Eina_Bool
461 eina_tls_set(Eina_TLS key, const void *data)
463 if (TlsSetValue(key, (LPVOID)data) == 0)
468 static inline Eina_Bool
469 eina_semaphore_new(Eina_Semaphore *sem, int count_init)
471 if (!sem || (count_init <= 0))
474 *sem = CreateSemaphore(NULL, count_init, 32767, NULL);
479 static inline Eina_Bool
480 eina_semaphore_free(Eina_Semaphore *sem)
488 static inline Eina_Bool
489 eina_semaphore_lock(Eina_Semaphore *sem)
496 res = WaitForSingleObject(*sem, 0L);
497 if (res == WAIT_OBJECT_0)
503 static inline Eina_Bool
504 eina_semaphore_release(Eina_Semaphore *sem, int count_release)
509 return ReleaseSemaphore(*sem, count_release, NULL) ? EINA_TRUE : EINA_FALSE;