LGPL
[vlc.git] / src / win32 / thread.c
index d93cf28..90a80a3 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * thread.c : Win32 back-end for LibVLC
  *****************************************************************************
- * Copyright (C) 1999-2009 the VideoLAN team
+ * Copyright (C) 1999-2009 VLC authors and VideoLAN
  *
  * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
  *          Samuel Hocevar <sam@zoy.org>
  *          RĂ©mi Denis-Courmont
  *          Pierre Ynard
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -61,44 +61,9 @@ struct vlc_thread
     void          *data;
 };
 
-#ifdef UNDER_CE
-static void CALLBACK vlc_cancel_self (ULONG_PTR dummy);
-
-DWORD WaitForMultipleObjectsEx (DWORD nCount, const HANDLE *lpHandles,
-                                BOOL bWaitAll, DWORD dwMilliseconds,
-                                BOOL bAlertable)
-{
-    HANDLE handles[nCount + 1];
-    DWORD ret;
-
-    memcpy(handles, lpHandles, count * sizeof(HANDLE));
-    if (bAlertable)
-    {
-        struct vlc_thread *th = vlc_threadvar_get (thread_key);
-        if (th != NULL)
-        {
-            handles[nCount] = th->cancel_event;
-            /* bWaitAll not implemented and not used by VLC... */
-            assert (!bWaitAll);
-        }
-        else
-            bAltertable = FALSE;
-    }
-
-    ret = WaitForMultipleObjects (nCount + bAlertable, handles, bWaitAll,
-                                  dwMilliseconds);
-    if (ret == WAIT_OBJECT_0 + nCount)
-    {
-        assert (bAlertable);
-        vlc_cancel_self ((uintptr_t)th);
-        ret = WAIT_IO_COMPLETION;
-    }
-    return ret;
-}
-#endif
-
 static vlc_mutex_t super_mutex;
 static vlc_cond_t  super_variable;
+extern vlc_rwlock_t config_lock, msg_lock;
 
 BOOL WINAPI DllMain (HINSTANCE, DWORD, LPVOID);
 
@@ -113,9 +78,14 @@ BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
             vlc_mutex_init (&super_mutex);
             vlc_cond_init (&super_variable);
             vlc_threadvar_create (&thread_key, NULL);
+            vlc_rwlock_init (&config_lock);
+            vlc_rwlock_init (&msg_lock);
+            vlc_CPU_init ();
             break;
 
         case DLL_PROCESS_DETACH:
+            vlc_rwlock_destroy (&msg_lock);
+            vlc_rwlock_destroy (&config_lock);
             vlc_threadvar_delete (&thread_key);
             vlc_cond_destroy (&super_variable);
             vlc_mutex_destroy (&super_mutex);
@@ -124,18 +94,52 @@ BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
     return TRUE;
 }
 
+static void CALLBACK vlc_cancel_self (ULONG_PTR);
+
 static DWORD vlc_WaitForMultipleObjects (DWORD count, const HANDLE *handles,
                                          DWORD delay)
 {
-    DWORD ret = WaitForMultipleObjectsEx (count, handles, FALSE, delay, TRUE);
+    DWORD ret;
+#ifdef UNDER_CE
+    HANDLE buf[count + 1];
 
-   /* We do not abandon objects... this would be a bug */
-   assert (ret < WAIT_ABANDONED_0 || WAIT_ABANDONED_0 + count - 1 < ret);
+    struct vlc_thread *th = vlc_threadvar_get (thread_key);
+    if (th != NULL)
+    {
+        memcpy (buf, handles, count * sizeof(HANDLE));
+        buf[count++] = th->cancel_event;
+        handles = buf;
+    }
 
-   if (unlikely(ret == WAIT_FAILED))
-       abort (); /* We are screwed! */
+    if (count == 0)
+    {
+         Sleep (delay);
+         ret = WAIT_TIMEOUT;
+    }
+    else
+        ret = WaitForMultipleObjects (count, handles, FALSE, delay);
 
-   return ret;
+    if ((th != NULL) && (ret == WAIT_OBJECT_0 + count - 1))
+    {
+        vlc_cancel_self ((uintptr_t)th);
+        ret = WAIT_IO_COMPLETION;
+    }
+#else
+    if (count == 0)
+    {
+        ret = SleepEx (delay, TRUE);
+        if (ret == 0)
+            ret = WAIT_TIMEOUT;
+    }
+    else
+        ret = WaitForMultipleObjectsEx (count, handles, FALSE, delay, TRUE);
+#endif
+    /* We do not abandon objects... this would be a bug */
+    assert (ret < WAIT_ABANDONED_0 || WAIT_ABANDONED_0 + count - 1 < ret);
+
+    if (unlikely(ret == WAIT_FAILED))
+        abort (); /* We are screwed! */
+    return ret;
 }
 
 static DWORD vlc_WaitForSingleObject (HANDLE handle, DWORD delay)
@@ -143,15 +147,11 @@ static DWORD vlc_WaitForSingleObject (HANDLE handle, DWORD delay)
     return vlc_WaitForMultipleObjects (1, &handle, delay);
 }
 
-#if 0 // WaitForMultipleObjectsEx() cannot deal with zero handles
 static DWORD vlc_Sleep (DWORD delay)
 {
     DWORD ret = vlc_WaitForMultipleObjects (0, NULL, delay);
-    if (ret == WAIT_TIMEOUT)
-        ret = 0;
-    return ret;
+    return (ret != WAIT_TIMEOUT) ? ret : 0;
 }
-#endif
 
 
 /*** Mutexes ***/
@@ -240,8 +240,8 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
 /*** Condition variables ***/
 enum
 {
+    CLOCK_REALTIME=0, /* must be zero for VLC_STATIC_COND */
     CLOCK_MONOTONIC,
-    CLOCK_REALTIME,
 };
 
 static void vlc_cond_init_common (vlc_cond_t *p_condvar, unsigned clock)
@@ -270,16 +270,19 @@ void vlc_cond_destroy (vlc_cond_t *p_condvar)
 
 void vlc_cond_signal (vlc_cond_t *p_condvar)
 {
-    /* NOTE: This will cause a broadcast, that is wrong.
-     * This will also wake up the next waiting thread if no threads are yet
-     * waiting, which is also wrong. However both of these issues are allowed
-     * by the provision for spurious wakeups. Better have too many wakeups
-     * than too few (= deadlocks). */
-    SetEvent (p_condvar->handle);
+    if (!p_condvar->handle)
+        return;
+
+    /* This is suboptimal but works. */
+    vlc_cond_broadcast (p_condvar);
 }
 
 void vlc_cond_broadcast (vlc_cond_t *p_condvar)
 {
+    if (!p_condvar->handle)
+        return;
+
+    /* Wake all threads up (as the event HANDLE has manual reset) */
     SetEvent (p_condvar->handle);
 }
 
@@ -287,13 +290,18 @@ void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
 {
     DWORD result;
 
-    assert (p_mutex->dynamic); /* TODO */
+    if (!p_condvar->handle)
+    {   /* FIXME FIXME FIXME */
+        msleep (50000);
+        return;
+    }
+
     do
     {
         vlc_testcancel ();
-        LeaveCriticalSection (&p_mutex->mutex);
+        vlc_mutex_unlock (p_mutex);
         result = vlc_WaitForSingleObject (p_condvar->handle, INFINITE);
-        EnterCriticalSection (&p_mutex->mutex);
+        vlc_mutex_lock (p_mutex);
     }
     while (result == WAIT_IO_COMPLETION);
 
@@ -305,7 +313,12 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
 {
     DWORD result;
 
-    assert (p_mutex->dynamic); /* TODO */
+    if (!p_condvar->handle)
+    {   /* FIXME FIXME FIXME */
+        msleep (50000);
+        return 0;
+    }
+
     do
     {
         vlc_testcancel ();
@@ -326,9 +339,9 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
             total = 0;
 
         DWORD delay = (total > 0x7fffffff) ? 0x7fffffff : total;
-        LeaveCriticalSection (&p_mutex->mutex);
+        vlc_mutex_unlock (p_mutex);
         result = vlc_WaitForSingleObject (p_condvar->handle, delay);
-        EnterCriticalSection (&p_mutex->mutex);
+        vlc_mutex_lock (p_mutex);
     }
     while (result == WAIT_IO_COMPLETION);
 
@@ -373,8 +386,7 @@ void vlc_sem_wait (vlc_sem_t *sem)
 void vlc_rwlock_init (vlc_rwlock_t *lock)
 {
     vlc_mutex_init (&lock->mutex);
-    vlc_cond_init (&lock->read_wait);
-    vlc_cond_init (&lock->write_wait);
+    vlc_cond_init (&lock->wait);
     lock->readers = 0; /* active readers */
     lock->writers = 0; /* waiting writers */
     lock->writer = 0; /* ID of active writer */
@@ -382,8 +394,7 @@ void vlc_rwlock_init (vlc_rwlock_t *lock)
 
 void vlc_rwlock_destroy (vlc_rwlock_t *lock)
 {
-    vlc_cond_destroy (&lock->read_wait);
-    vlc_cond_destroy (&lock->write_wait);
+    vlc_cond_destroy (&lock->wait);
     vlc_mutex_destroy (&lock->mutex);
 }
 
@@ -400,7 +411,7 @@ void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
     while (lock->writer != 0)
     {
         assert (lock->readers == 0);
-        vlc_cond_wait (&lock->read_wait, &lock->mutex);
+        vlc_cond_wait (&lock->wait, &lock->mutex);
     }
     if (unlikely(lock->readers == ULONG_MAX))
         abort ();
@@ -415,7 +426,7 @@ static void vlc_rwlock_rdunlock (vlc_rwlock_t *lock)
 
     /* If there are no readers left, wake up a writer. */
     if (--lock->readers == 0 && lock->writers > 0)
-        vlc_cond_signal (&lock->write_wait);
+        vlc_cond_signal (&lock->wait);
     vlc_mutex_unlock (&lock->mutex);
 }
 
@@ -427,7 +438,7 @@ void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
     lock->writers++;
     /* Wait until nobody owns the lock in either way. */
     while ((lock->readers > 0) || (lock->writer != 0))
-        vlc_cond_wait (&lock->write_wait, &lock->mutex);
+        vlc_cond_wait (&lock->wait, &lock->mutex);
     lock->writers--;
     assert (lock->writer == 0);
     lock->writer = GetCurrentThreadId ();
@@ -442,9 +453,7 @@ static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
     lock->writer = 0; /* Write unlock */
 
     /* Let reader and writer compete. Scheduler decides who wins. */
-    if (lock->writers > 0)
-        vlc_cond_signal (&lock->write_wait);
-    vlc_cond_broadcast (&lock->read_wait);
+    vlc_cond_broadcast (&lock->wait);
     vlc_mutex_unlock (&lock->mutex);
 }
 
@@ -486,6 +495,9 @@ int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
 
     vlc_mutex_lock (&super_mutex);
     var->prev = vlc_threadvar_last;
+    if (var->prev)
+        var->prev->next = var;
+
     vlc_threadvar_last = var;
     vlc_mutex_unlock (&super_mutex);
     return 0;
@@ -498,10 +510,12 @@ void vlc_threadvar_delete (vlc_threadvar_t *p_tls)
     vlc_mutex_lock (&super_mutex);
     if (var->prev != NULL)
         var->prev->next = var->next;
-    else
-        vlc_threadvar_last = var->next;
+
     if (var->next != NULL)
         var->next->prev = var->prev;
+    else
+        vlc_threadvar_last = var->prev;
+
     vlc_mutex_unlock (&super_mutex);
 
     TlsFree (var->id);
@@ -638,7 +652,7 @@ void vlc_join (vlc_thread_t th, void **result)
 {
     do
         vlc_testcancel ();
-    while (WaitForSingleObjectEx (th->id, INFINITE, TRUE)
+    while (vlc_WaitForSingleObject (th->id, INFINITE)
                                                         == WAIT_IO_COMPLETION);
 
     if (result != NULL)
@@ -791,7 +805,7 @@ void mwait (mtime_t deadline)
         delay /= 1000;
         if (unlikely(delay > 0x7fffffff))
             delay = 0x7fffffff;
-        SleepEx (delay, TRUE);
+        vlc_Sleep (delay);
         vlc_testcancel();
     }
 }
@@ -937,8 +951,8 @@ unsigned vlc_timer_getoverrun (vlc_timer_t timer)
 unsigned vlc_GetCPUCount (void)
 {
 #ifndef UNDER_CE
-    DWORD process;
-    DWORD system;
+    DWORD_PTR process;
+    DWORD_PTR system;
 
     if (GetProcessAffinityMask (GetCurrentProcess(), &process, &system))
         return popcount (system);