From c1ab49e1a7005e4a408a3938476555101382becc Mon Sep 17 00:00:00 2001 From: caro Date: Sat, 14 May 2011 21:19:36 +0000 Subject: [PATCH] Eina : eina_lock : make it compile on Windows git-svn-id: http://svn.enlightenment.org/svn/e/trunk/eina@59391 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33 --- ChangeLog | 4 + src/include/eina_inline_lock_void.x | 44 ++++++- src/include/eina_inline_lock_win32.x | 232 +++++++++++++++++++++++++++++++++-- src/include/eina_inline_lock_wince.x | 50 ++++++-- 4 files changed, 308 insertions(+), 22 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5097a8c..35b5273 100644 --- a/ChangeLog +++ b/ChangeLog @@ -72,3 +72,7 @@ 2011-04-29 Cedric Bail * Add Eina_Refcount macro helper. You should really use them when running with thread ! + +2011-05-14 Cedric Bail + + * Add Eina_Condition API on Windows. diff --git a/src/include/eina_inline_lock_void.x b/src/include/eina_inline_lock_void.x index 2d605a4..5ec6ace 100644 --- a/src/include/eina_inline_lock_void.x +++ b/src/include/eina_inline_lock_void.x @@ -80,10 +80,10 @@ eina_lock_free(Eina_Lock mutex) * #EINA_FALSE otherwise. For performance reasons, no check is done on * @p mutex. */ -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_take(Eina_Lock mutex) { - return EINA_FALSE; + return EINA_LOCK_FAIL; } /** @@ -101,10 +101,10 @@ eina_lock_take(Eina_Lock mutex) * * @note On Windows CE, this function is actually eina_lock_take(). */ -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_take_try(Eina_Lock mutex) { - return EINA_FALSE; + return EINA_LOCK_FAIL; } /** @@ -118,9 +118,43 @@ eina_lock_take_try(Eina_Lock mutex) * #EINA_FALSE otherwise. For performance reasons, no check is done on * @p mutex. */ -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_release(Eina_Lock mutex) { + return EINA_LOCK_FAIL; +} + +static inline void +eina_lock_debug(const Eina_Lock *mutex) +{ +} + +static inline Eina_Bool +eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex) +{ + return EINA_FALSE; +} + +static inline void +eina_condition_free(Eina_Condition *cond) +{ +} + +static inline Eina_Bool +eina_condition_wait(Eina_Condition *cond) +{ + return EINA_FALSE; +} + +static inline Eina_Bool +eina_condition_broadcast(Eina_Condition *cond) +{ + return EINA_FALSE; +} + +static inline Eina_Bool +eina_condition_signal(Eina_Condition *cond) +{ return EINA_FALSE; } diff --git a/src/include/eina_inline_lock_win32.x b/src/include/eina_inline_lock_win32.x index 750dd3a..67d0164 100644 --- a/src/include/eina_inline_lock_win32.x +++ b/src/include/eina_inline_lock_win32.x @@ -21,7 +21,27 @@ #include -typedef CRITICAL_SECTION Eina_Lock; +typedef CRITICAL_SECTION Eina_Lock; +typedef struct _Eina_Condition Eina_Condition; + +#if _WIN32_WINNT >= 0x0600 +struct _Eina_Condition +{ + CRITICAL_SECTION mutex; + CONDITION_VARIABLE condition; +}; +#else +struct _Eina_Condition +{ + int waiters_count; + CRITICAL_SECTION waiters_count_lock; + CRITICAL_SECTION mutex; + HANDLE semaphore; + HANDLE waiters_done; + Eina_Bool was_broadcast; +}; +#endif + EAPI extern Eina_Bool _eina_threads_activated; @@ -39,38 +59,232 @@ eina_lock_free(Eina_Lock *mutex) DeleteCriticalSection(mutex); } -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_take(Eina_Lock *mutex) { #ifdef EINA_HAVE_ON_OFF_THREADS - if (!_eina_threads_activated) return EINA_FALSE; + if (!_eina_threads_activated) return EINA_LOCK_FAIL; #endif EnterCriticalSection(mutex); - return EINA_TRUE; + return EINA_LOCK_SUCCEED; } -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex) { #ifdef EINA_HAVE_ON_OFF_THREADS - if (!_eina_threads_activated) return EINA_FALSE; + if (!_eina_threads_activated) return EINA_LOCK_FAIL; #endif - return TryEnterCriticalSection(mutex) == 0 ? EINA_FALSE : EINA_TRUE; + return TryEnterCriticalSection(mutex) == 0 ? EINA_LOCK_FAIL : EINA_LOCK_SUCCEED; } -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_release(Eina_Lock *mutex) { #ifdef EINA_HAVE_ON_OFF_THREADS - if (!_eina_threads_activated) return EINA_FALSE; + if (!_eina_threads_activated) return EINA_LOCK_FAIL; #endif LeaveCriticalSection(mutex); + return EINA_LOCK_SUCCEED; +} + +static inline void +eina_lock_debug(const Eina_Lock *mutex) +{ + (void)mutex; +} + +static inline Eina_Bool +eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex) +{ +#if _WIN32_WINNT >= 0x0600 + InitializeCriticalSection(&cond->mutex); + InitializeConditionVariable(&cond->condition); +#else + cond->waiters_count = 0; + cond->was_broadcast = EINA_FALSE; + cond->mutex = *mutex; + cond->semaphore = CreateSemaphore(NULL, // no security + 0, // initially 0 + 0x7fffffff, // max count + NULL); // unnamed + if (!cond->semaphore) + return EINA_FALSE; + + InitializeCriticalSection(&cond->waiters_count_lock); + InitializeCriticalSection(&cond->mutex); + + cond->waiters_done = CreateEvent(NULL, // no security + FALSE, // auto-reset + FALSE, // non-signaled initially + NULL); // unnamed + if (!cond->waiters_done) + { + CloseHandle(cond->semaphore); + return EINA_FALSE; + } + return EINA_TRUE; +#endif +} + +static inline void +eina_condition_free(Eina_Condition *cond) +{ +#if _WIN32_WINNT >= 0x0600 + DeleteCriticalSection(&cond->mutex); +#else + CloseHandle(cond->waiters_done); + DeleteCriticalSection(&cond->mutex); + DeleteCriticalSection(&cond->waiters_count_lock); + CloseHandle(cond->semaphore); +#endif +} + +static inline Eina_Bool +eina_condition_wait(Eina_Condition *cond) +{ +#if _WIN32_WINNT >= 0x0600 + SleepConditionVariableCS(&cond->condition, &cond->mutex, INFINITE); +#else + DWORD ret; + Eina_Bool last_waiter; + + /* Avoid race conditions. */ + EnterCriticalSection(&cond->waiters_count_lock); + cond->waiters_count++; + LeaveCriticalSection(&cond->waiters_count_lock); + + /* + * This call atomically releases the mutex and waits on the + * semaphore until or + * are called by another thread. + */ + ret = SignalObjectAndWait(&cond->mutex, cond->semaphore, INFINITE, FALSE); + if (ret == WAIT_FAILED) + return EINA_FALSE; + + /* Reacquire lock to avoid race conditions. */ + EnterCriticalSection(&cond->waiters_count_lock); + + /* We're no longer waiting... */ + cond->waiters_count--; + + /* Check to see if we're the last waiter after . */ + last_waiter = (cond->was_broadcast) && (cond->waiters_count == 0); + + LeaveCriticalSection(&cond->waiters_count_lock); + + /* + * If we're the last waiter thread during this particular broadcast + * then let all the other threads proceed. + */ + if (last_waiter) + { + /* + * This call atomically signals the event and waits until + * it can acquire the . This is required to ensure fairness. + */ + ret = SignalObjectAndWait(cond->waiters_done, &cond->mutex, INFINITE, FALSE); + if (ret == WAIT_FAILED) + return EINA_FALSE; + } + else + { + /* + * Always regain the external mutex since that's the guarantee we + * give to our callers. + */ + ret = WaitForSingleObject(&cond->mutex, INFINITE); + if (ret == WAIT_FAILED) + return EINA_FALSE; + } + + return EINA_TRUE; +#endif +} + +static inline Eina_Bool +eina_condition_broadcast(Eina_Condition *cond) +{ +#if _WIN32_WINNT >= 0x0600 + WakeAllConditionVariable(&cond->condition); +#else + Eina_Bool have_waiters; + + /* + * This is needed to ensure that and are + * consistent relative to each other. + */ + EnterCriticalSection(&cond->waiters_count_lock); + have_waiters = EINA_FALSE; + + if (cond->waiters_count > 0) + { + /* + * We are broadcasting, even if there is just one waiter... + * Record that we are broadcasting, which helps optimize + * for the non-broadcast case. + */ + cond->was_broadcast = EINA_TRUE; + have_waiters = EINA_TRUE; + } + + if (have_waiters) + { + DWORD ret; + + /* Wake up all the waiters atomically. */ + ret = ReleaseSemaphore(cond->semaphore, cond->waiters_count, 0); + LeaveCriticalSection(&cond->waiters_count_lock); + if (!ret) return EINA_FALSE; + + /* + * Wait for all the awakened threads to acquire the counting + * semaphore. + */ + ret = WaitForSingleObject(cond->waiters_done, INFINITE); + if (ret == WAIT_FAILED) + return EINA_FALSE; + /* + * This assignment is okay, even without the held + * because no other waiter threads can wake up to access it. + */ + cond->was_broadcast = EINA_FALSE; + } + else + LeaveCriticalSection(&cond->waiters_count_lock); + + return EINA_TRUE; +#endif +} + +static inline Eina_Bool +eina_condition_signal(Eina_Condition *cond) +{ +#if _WIN32_WINNT >= 0x0600 + WakeConditionVariable(&cond->condition); +#else + Eina_Bool have_waiters; + + EnterCriticalSection(&cond->waiters_count_lock); + have_waiters = (cond->waiters_count > 0); + LeaveCriticalSection(&cond->waiters_count_lock); + + /* If there aren't any waiters, then this is a no-op. */ + if (have_waiters) + { + if (!ReleaseSemaphore(cond->semaphore, 1, 0)) + return EINA_FALSE; + } + + return EINA_TRUE; +#endif } #endif diff --git a/src/include/eina_inline_lock_wince.x b/src/include/eina_inline_lock_wince.x index 53267af..475c4d6 100644 --- a/src/include/eina_inline_lock_wince.x +++ b/src/include/eina_inline_lock_wince.x @@ -41,36 +41,70 @@ eina_lock_free(Eina_Lock *mutex) CloseHandle(*mutex); } -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_take(Eina_Lock *mutex) { DWORD res; #ifdef EINA_HAVE_ON_OFF_THREADS - if (!_eina_threads_activated) return EINA_FALSE; + if (!_eina_threads_activated) return EINA_LOCK_FAIL; #endif res = WaitForSingleObject(*mutex, INFINITE); if ((res == WAIT_ABANDONED) || (res == WAIT_FAILED)) - return EINA_FALSE; + return EINA_LOCK_FAIL; - return EINA_TRUE; + return EINA_LOCK_SUCCEED; } -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_take_try(Eina_Lock *mutex) { return eina_lock_take(*mutex); } -static inline Eina_Bool +static inline Eina_Lock_Result eina_lock_release(Eina_Lock *mutex) { #ifdef EINA_HAVE_ON_OFF_THREADS - if (!_eina_threads_activated) return EINA_FALSE; + if (!_eina_threads_activated) return ; #endif - return ReleaseMutex(*mutex); + return ReleaseMutex(*mutex) ? EINA_LOCK_SUCCEED : EINA_LOCK_FAIL; +} + +static inline void +eina_lock_debug(const Eina_Lock *mutex) +{ +} + +static inline Eina_Bool +eina_condition_new(Eina_Condition *cond, Eina_Lock *mutex) +{ + return EINA_FALSE; +} + +static inline void +eina_condition_free(Eina_Condition *cond) +{ +} + +static inline Eina_Bool +eina_condition_wait(Eina_Condition *cond) +{ + return EINA_FALSE; +} + +static inline Eina_Bool +eina_condition_broadcast(Eina_Condition *cond) +{ + return EINA_FALSE; +} + +static inline Eina_Bool +eina_condition_signal(Eina_Condition *cond) +{ + return EINA_FALSE; } -- 2.7.4