]> git.sesse.net Git - vlc/blobdiff - src/misc/w32thread.c
Don't use a static mutex for libvlc_wait on Win32 (fixes: #3219)
[vlc] / src / misc / w32thread.c
index 0edba5ecfe3a8fb67a23cb8326d9db0037aa5c27..c712ca845b5c2c5a7354bb3738a5b2984da44951 100644 (file)
@@ -140,7 +140,8 @@ DWORD WaitForMultipleObjectsEx (DWORD nCount, const HANDLE *lpHandles,
 }
 #endif
 
-static vlc_mutex_t super_mutex;
+vlc_mutex_t super_mutex;
+vlc_cond_t  super_variable;
 
 BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
 {
@@ -151,11 +152,13 @@ BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
     {
         case DLL_PROCESS_ATTACH:
             vlc_mutex_init (&super_mutex);
+            vlc_cond_init (&super_variable);
             vlc_threadvar_create (&cancel_key, free);
             break;
 
         case DLL_PROCESS_DETACH:
             vlc_threadvar_delete( &cancel_key );
+            vlc_cond_destroy (&super_variable);
             vlc_mutex_destroy (&super_mutex);
             break;
     }
@@ -168,57 +171,78 @@ void vlc_mutex_init( vlc_mutex_t *p_mutex )
     /* This creates a recursive mutex. This is OK as fast mutexes have
      * no defined behavior in case of recursive locking. */
     InitializeCriticalSection (&p_mutex->mutex);
-    p_mutex->initialized = 1;
+    p_mutex->dynamic = true;
 }
 
 void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
 {
     InitializeCriticalSection( &p_mutex->mutex );
-    p_mutex->initialized = 1;
+    p_mutex->dynamic = true;
 }
 
 
 void vlc_mutex_destroy (vlc_mutex_t *p_mutex)
 {
-    assert (InterlockedExchange (&p_mutex->initialized, -1) == 1);
+    assert (p_mutex->dynamic);
     DeleteCriticalSection (&p_mutex->mutex);
 }
 
 void vlc_mutex_lock (vlc_mutex_t *p_mutex)
 {
-    if (InterlockedCompareExchange (&p_mutex->initialized, 0, 0) == 0)
-    { /* ^^ We could also lock super_mutex all the time... sluggish */
+    if (!p_mutex->dynamic)
+    {   /* static mutexes */
         assert (p_mutex != &super_mutex); /* this one cannot be static */
 
         vlc_mutex_lock (&super_mutex);
-        if (InterlockedCompareExchange (&p_mutex->initialized, 0, 0) == 0)
-            vlc_mutex_init (p_mutex);
-        /* FIXME: destroy the mutex some time... */
+        while (p_mutex->locked)
+        {
+            p_mutex->contention++;
+            vlc_cond_wait (&super_variable, &super_mutex);
+            p_mutex->contention--;
+        }
+        p_mutex->locked = true;
         vlc_mutex_unlock (&super_mutex);
+        return;
     }
-    assert (InterlockedExchange (&p_mutex->initialized, 1) == 1);
+
     EnterCriticalSection (&p_mutex->mutex);
 }
 
 int vlc_mutex_trylock (vlc_mutex_t *p_mutex)
 {
-    if (InterlockedCompareExchange (&p_mutex->initialized, 0, 0) == 0)
-    { /* ^^ We could also lock super_mutex all the time... sluggish */
-        assert (p_mutex != &super_mutex); /* this one cannot be static */
+    if (!p_mutex->dynamic)
+    {   /* static mutexes */
+        int ret = EBUSY;
 
+        assert (p_mutex != &super_mutex); /* this one cannot be static */
         vlc_mutex_lock (&super_mutex);
-        if (InterlockedCompareExchange (&p_mutex->initialized, 0, 0) == 0)
-            vlc_mutex_init (p_mutex);
-        /* FIXME: destroy the mutex some time... */
+        if (!p_mutex->locked)
+        {
+            p_mutex->locked = true;
+            ret = 0;
+        }
         vlc_mutex_unlock (&super_mutex);
+        return ret;
     }
-    assert (InterlockedExchange (&p_mutex->initialized, 1) == 1);
+
     return TryEnterCriticalSection (&p_mutex->mutex) ? 0 : EBUSY;
 }
 
 void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
 {
-    assert (InterlockedExchange (&p_mutex->initialized, 1) == 1);
+    if (!p_mutex->dynamic)
+    {   /* static mutexes */
+        assert (p_mutex != &super_mutex); /* this one cannot be static */
+
+        vlc_mutex_lock (&super_mutex);
+        assert (p_mutex->locked);
+        p_mutex->locked = false;
+        if (p_mutex->contention)
+            vlc_cond_broadcast (&super_variable);
+        vlc_mutex_unlock (&super_mutex);
+        return;
+    }
+
     LeaveCriticalSection (&p_mutex->mutex);
 }
 
@@ -255,6 +279,7 @@ void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
 {
     DWORD result;
 
+    assert (p_mutex->dynamic); /* TODO */
     do
     {
         vlc_testcancel ();
@@ -274,6 +299,7 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
 {
     DWORD result;
 
+    assert (p_mutex->dynamic); /* TODO */
     do
     {
         vlc_testcancel ();
@@ -296,6 +322,37 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
     return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT;
 }
 
+/*** Semaphore ***/
+void vlc_sem_init (vlc_sem_t *sem, unsigned value)
+{
+    *sem = CreateSemaphore (NULL, value, 0x7fffffff, NULL);
+    if (*sem == NULL)
+        abort ();
+}
+
+void vlc_sem_destroy (vlc_sem_t *sem)
+{
+    CloseHandle (*sem);
+}
+
+int vlc_sem_post (vlc_sem_t *sem)
+{
+    ReleaseSemaphore (*sem, 1, NULL);
+    return 0; /* FIXME */
+}
+
+void vlc_sem_wait (vlc_sem_t *sem)
+{
+    DWORD result;
+
+    do
+    {
+        vlc_testcancel ();
+        result = WaitForSingleObjectEx (*sem, INFINITE, TRUE);
+    }
+    while (result == WAIT_IO_COMPLETION);
+}
+
 /*** Read/write locks */
 /* SRW (Slim Read Write) locks are available in Vista+ only */
 void vlc_rwlock_init (vlc_rwlock_t *lock)
@@ -373,6 +430,8 @@ void vlc_rwlock_unlock (vlc_rwlock_t *lock)
 int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *))
 {
 #warning FIXME: use destr() callback and stop leaking!
+    VLC_UNUSED( destr );
+
     *p_tls = TlsAlloc();
     return (*p_tls == TLS_OUT_OF_INDEXES) ? EAGAIN : 0;
 }