Eina : eina_lock : make it compile on Windows
authorcaro <caro@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sat, 14 May 2011 21:19:36 +0000 (21:19 +0000)
committercaro <caro@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sat, 14 May 2011 21:19:36 +0000 (21:19 +0000)
git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@59391 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

ChangeLog
src/include/eina_inline_lock_void.x
src/include/eina_inline_lock_win32.x
src/include/eina_inline_lock_wince.x

index 5097a8c..35b5273 100644 (file)
--- 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.
index 2d605a4..5ec6ace 100644 (file)
@@ -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;
 }
 
index 750dd3a..67d0164 100644 (file)
 
 #include <windows.h>
 
-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 <pthread_cond_signal> or <pthread_cond_broadcast>
+    * 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 <pthread_cond_broadcast>. */
+   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 <waiters_done_> event and waits until
+        * it can acquire the <external_mutex>.  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 <waiters_count_> and <was_broadcast_> 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
+         * <pthread_cond_wait> 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 <waiters_count_lock_> 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
index 53267af..475c4d6 100644 (file)
@@ -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;
 }