[vlc-commits] win32: fix vlc_cond_broadcast()

Rémi Denis-Courmont git at videolan.org
Sun May 17 16:23:59 CEST 2015


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun May 17 16:00:10 2015 +0300| [52894f2fe97db80e0f6b4fed7ca440c0e590204d] | committer: Rémi Denis-Courmont

win32: fix vlc_cond_broadcast()

Signaling an event ensures that at least one thread wakes up, but it
does not warrant that all of them do.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=52894f2fe97db80e0f6b4fed7ca440c0e590204d
---

 include/vlc_threads.h |    5 ++-
 src/win32/thread.c    |  104 +++++++++++++++++++++++--------------------------
 2 files changed, 52 insertions(+), 57 deletions(-)

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index dfe61ed..38bc3a7 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -61,10 +61,11 @@ typedef struct
 #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
 typedef struct
 {
-    HANDLE   handle;
+    HANDLE   semaphore;
+    LONG     waiters;
     unsigned clock;
 } vlc_cond_t;
-#define VLC_STATIC_COND { 0, 0 }
+#define VLC_STATIC_COND { NULL, 0, 0 }
 typedef HANDLE vlc_sem_t;
 #define LIBVLC_NEED_RWLOCK
 typedef struct vlc_threadvar *vlc_threadvar_t;
diff --git a/src/win32/thread.c b/src/win32/thread.c
index 2f94fab..46fa357 100644
--- a/src/win32/thread.c
+++ b/src/win32/thread.c
@@ -201,13 +201,13 @@ enum
     VLC_CLOCK_REALTIME,
 };
 
-static void vlc_cond_init_common (vlc_cond_t *p_condvar, unsigned clock)
+static void vlc_cond_init_common(vlc_cond_t *wait, unsigned clock)
 {
-    /* Create a manual-reset event (manual reset is needed for broadcast). */
-    p_condvar->handle = CreateEvent (NULL, TRUE, FALSE, NULL);
-    if (!p_condvar->handle)
+    wait->semaphore = CreateSemaphore(NULL, 0, 0x7FFFFFFF, NULL);
+    if (unlikely(wait->semaphore == NULL))
         abort();
-    p_condvar->clock = clock;
+    wait->waiters = 0;
+    wait->clock = clock;
 }
 
 void vlc_cond_init (vlc_cond_t *p_condvar)
@@ -220,9 +220,9 @@ void vlc_cond_init_daytime (vlc_cond_t *p_condvar)
     vlc_cond_init_common (p_condvar, VLC_CLOCK_REALTIME);
 }
 
-void vlc_cond_destroy (vlc_cond_t *p_condvar)
+void vlc_cond_destroy(vlc_cond_t *wait)
 {
-    CloseHandle (p_condvar->handle);
+    CloseHandle(wait->semaphore);
 }
 
 void vlc_cond_signal (vlc_cond_t *p_condvar)
@@ -231,75 +231,69 @@ void vlc_cond_signal (vlc_cond_t *p_condvar)
     vlc_cond_broadcast (p_condvar);
 }
 
-void vlc_cond_broadcast (vlc_cond_t *p_condvar)
+void vlc_cond_broadcast(vlc_cond_t *wait)
 {
-    if (!p_condvar->clock)
+    if (!wait->clock)
         return;
 
-    /* Wake all threads up (as the event HANDLE has manual reset) */
-    SetEvent (p_condvar->handle);
+    LONG waiters = InterlockedExchange(&wait->waiters, 0);
+    if (waiters > 0)
+        ReleaseSemaphore(wait->semaphore, waiters, NULL);
 }
 
-void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
+void vlc_cond_wait(vlc_cond_t *wait, vlc_mutex_t *lock)
 {
-    DWORD result;
+    vlc_testcancel();
 
-    if (!p_condvar->clock)
+    if (!wait->clock)
     {   /* FIXME FIXME FIXME */
         msleep (50000);
         return;
     }
 
-    do
-    {
-        vlc_testcancel ();
-        vlc_mutex_unlock (p_mutex);
-        result = vlc_WaitForSingleObject (p_condvar->handle, INFINITE);
-        vlc_mutex_lock (p_mutex);
-    }
-    while (result == WAIT_IO_COMPLETION);
-
-    ResetEvent (p_condvar->handle);
+    InterlockedIncrement(&wait->waiters);
+    vlc_mutex_unlock(lock);
+    vlc_WaitForSingleObject(wait->semaphore, INFINITE);
+    vlc_mutex_lock(lock);
 }
 
-int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
-                        mtime_t deadline)
+int vlc_cond_timedwait(vlc_cond_t *wait, vlc_mutex_t *lock, mtime_t deadline)
 {
+    mtime_t total;
     DWORD result;
 
-    do
-    {
-        vlc_testcancel ();
+    vlc_testcancel();
 
-        mtime_t total;
-        switch (p_condvar->clock)
-        {
-            case VLC_CLOCK_MONOTONIC:
-                total = mdate();
-                break;
-            case VLC_CLOCK_REALTIME: /* FIXME? sub-second precision */
-                total = CLOCK_FREQ * time (NULL);
-                break;
-            default:
-                assert (!p_condvar->clock);
-                /* FIXME FIXME FIXME */
-                msleep (50000);
-                return 0;
-        }
-        total = (deadline - total) / 1000;
-        if( total < 0 )
-            total = 0;
-
-        DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total;
-        vlc_mutex_unlock (p_mutex);
-        result = vlc_WaitForSingleObject (p_condvar->handle, delay);
-        vlc_mutex_lock (p_mutex);
+    switch (wait->clock)
+    {
+        case VLC_CLOCK_MONOTONIC:
+            total = mdate();
+            break;
+        case VLC_CLOCK_REALTIME: /* FIXME? sub-second precision */
+            total = CLOCK_FREQ * time(NULL);
+            break;
+        default:
+            assert(!wait->clock);
+            /* FIXME FIXME FIXME */
+            msleep(50000);
+            return 0;
     }
-    while (result == WAIT_IO_COMPLETION);
 
-    ResetEvent (p_condvar->handle);
+    total = (deadline - total) / 1000;
+    if (total < 0)
+        total = 0;
+
+    DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total;
+
+    InterlockedIncrement(&wait->waiters);
+    vlc_mutex_unlock(lock);
+    result = vlc_WaitForSingleObject(wait->semaphore, delay);
+    vlc_mutex_lock(lock);
+
+    if (result == WAIT_IO_COMPLETION)
+        vlc_testcancel();
 
-    return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT;
+    return (result == WAIT_TIMEOUT) ? ETIMEDOUT : 0;
 }
 
 /*** Semaphore ***/



More information about the vlc-commits mailing list