]> git.sesse.net Git - vlc/commitdiff
rwlock: reduce footprint and factor Win32 and OS/2 back-ends
authorRémi Denis-Courmont <remi@remlab.net>
Mon, 10 Sep 2012 15:21:38 +0000 (18:21 +0300)
committerRémi Denis-Courmont <remi@remlab.net>
Mon, 10 Sep 2012 15:24:29 +0000 (18:24 +0300)
include/vlc_threads.h
src/Makefile.am
src/misc/rwlock.h [new file with mode: 0644]
src/os2/thread.c
src/win32/thread.c

index 7fcbf25064be9be76ab2b7bf4b6a8c400db9a4db..4dd63352b150ea32c39777054eb6e71e9f16c8fa 100644 (file)
@@ -159,17 +159,7 @@ typedef struct
 #define VLC_STATIC_COND { 0, 0 }
 
 typedef HANDLE  vlc_sem_t;
-
-typedef struct
-{
-    vlc_mutex_t   mutex;
-    vlc_cond_t    wait;
-    unsigned long readers;
-    DWORD         writer;
-} vlc_rwlock_t;
-#define VLC_STATIC_RWLOCK \
-    { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0, 0 }
-
+typedef struct vlc_rwlock vlc_rwlock_t;
 typedef struct vlc_threadvar *vlc_threadvar_t;
 typedef struct vlc_timer *vlc_timer_t;
 
@@ -189,7 +179,6 @@ typedef struct
         HMTX hmtx;
     };
 } vlc_mutex_t;
-
 #define VLC_STATIC_MUTEX { false, { { false, 0 } } }
 
 typedef struct
@@ -197,7 +186,6 @@ typedef struct
     HEV      hev;
     unsigned clock;
 } vlc_cond_t;
-
 #define VLC_STATIC_COND { 0, 0 }
 
 typedef struct
@@ -208,21 +196,22 @@ typedef struct
     int  count;
 } vlc_sem_t;
 
-typedef struct
-{
-    vlc_mutex_t   mutex;
-    vlc_cond_t    wait;
-    unsigned long readers;
-    int           writer;
-} vlc_rwlock_t;
-#define VLC_STATIC_RWLOCK \
-    { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0, 0 }
-
+typedef struct vlc_rwlock vlc_rwlock_t;
 typedef struct vlc_threadvar *vlc_threadvar_t;
 typedef struct vlc_timer *vlc_timer_t;
 
 #endif
 
+#ifndef VLC_STATIC_RWLOCK
+struct vlc_rwlock
+{
+    vlc_mutex_t   mutex;
+    vlc_cond_t    wait;
+    long          state;
+};
+# define VLC_STATIC_RWLOCK { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0 }
+#endif
+
 #if defined( WIN32 ) && !defined ETIMEDOUT
 #  define ETIMEDOUT 10060 /* This is the value in winsock.h. */
 #endif
index 9ac25d35fb8cb1cdfc10d826e809ad1994cf459d..733dec6a4be522240488b5304b51b88496b2ce7d 100644 (file)
@@ -269,6 +269,7 @@ SOURCES_libvlc_win32 = \
        win32/dirs.c \
        win32/filesystem.c \
        win32/plugin.c \
+       misc/rwlock.h \
        win32/thread.c \
        win32/specific.c \
        win32/winsock.c \
@@ -287,6 +288,7 @@ SOURCES_libvlc_os2 = \
        os2/dirs.c \
        os2/filesystem.c \
        os2/plugin.c \
+       misc/rwlock.h \
        os2/thread.c \
        os2/specific.c \
        os2/rand.c \
diff --git a/src/misc/rwlock.h b/src/misc/rwlock.h
new file mode 100644 (file)
index 0000000..d4857ad
--- /dev/null
@@ -0,0 +1,99 @@
+/*****************************************************************************
+ * rwlock.h : generic back-end for LibVLC read/write locks
+ *****************************************************************************
+ * Copyright (C) 2009-2012 Rémi Denis-Courmont
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * 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
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <vlc_common.h>
+
+/* NOTE:
+ * lock->state is a signed long integer:
+ *  - The sign bit is set when the lock is held for writing.
+ *  - The other bits code the number of times the lock is held for reading.
+ * Consequently:
+ *  - The value is negative if and only if the lock is held for writing.
+ *  - The value is zero if and only if the lock is not held at all.
+ */
+#define READER_MASK LONG_MAX
+#define WRITER_BIT  LONG_MIN
+
+void vlc_rwlock_init (vlc_rwlock_t *lock)
+{
+    vlc_mutex_init (&lock->mutex);
+    vlc_cond_init (&lock->wait);
+    lock->state = 0;
+}
+
+void vlc_rwlock_destroy (vlc_rwlock_t *lock)
+{
+    vlc_cond_destroy (&lock->wait);
+    vlc_mutex_destroy (&lock->mutex);
+}
+
+void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
+{
+    vlc_mutex_lock (&lock->mutex);
+    /* Recursive read-locking is allowed.
+     * Ensure that there is no active writer. */
+    while (lock->state < 0)
+    {
+        assert (lock->state == WRITER_BIT);
+        vlc_cond_wait (&lock->wait, &lock->mutex);
+    }
+    if (unlikely(lock->state >= READER_MASK))
+        abort (); /* An overflow is certainly a recursion bug. */
+    lock->state++;
+    vlc_mutex_unlock (&lock->mutex);
+}
+
+void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
+{
+    vlc_mutex_lock (&lock->mutex);
+    /* Wait until nobody owns the lock in any way. */
+    while (lock->state != 0)
+        vlc_cond_wait (&lock->wait, &lock->mutex);
+    lock->state = WRITER_BIT;
+    vlc_mutex_unlock (&lock->mutex);
+}
+
+void vlc_rwlock_unlock (vlc_rwlock_t *lock)
+{
+    vlc_mutex_lock (&lock->mutex);
+    if (lock->state < 0)
+    {   /* Write unlock */
+        assert (lock->state == WRITER_BIT);
+        /* Let reader and writer compete. OS scheduler decides who wins. */
+        lock->state = 0;
+        vlc_cond_broadcast (&lock->wait);
+    }
+    else
+    {   /* Read unlock */
+        assert (lock->state > 0);
+        /* If there are no readers left, wake up one pending writer. */
+        if (--lock->state == 0)
+            vlc_cond_signal (&lock->wait);
+    }
+    vlc_mutex_unlock (&lock->mutex);
+}
index e51b086f38706e675e3cc684b0c1ed831d7bd0d4..0be1e2a2297b3540861c4c1008dd5fad0871c3a8 100644 (file)
@@ -428,80 +428,7 @@ void vlc_sem_wait (vlc_sem_t *sem)
     } while (rc == ERROR_INTERRUPT);
 }
 
-/*** Read/write locks */
-void vlc_rwlock_init (vlc_rwlock_t *lock)
-{
-    vlc_mutex_init (&lock->mutex);
-    vlc_cond_init (&lock->wait);
-    lock->readers = 0; /* active readers */
-    lock->writer = 0; /* ID of active writer */
-}
-
-void vlc_rwlock_destroy (vlc_rwlock_t *lock)
-{
-    vlc_cond_destroy (&lock->wait);
-    vlc_mutex_destroy (&lock->mutex);
-}
-
-void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
-{
-    vlc_mutex_lock (&lock->mutex);
-    /* Recursive read-locking is allowed. */
-    while (lock->writer != 0)
-    {
-        assert (lock->readers == 0);
-        vlc_cond_wait (&lock->wait, &lock->mutex);
-    }
-    if (unlikely(lock->readers == ULONG_MAX))
-        abort ();
-    lock->readers++;
-    vlc_mutex_unlock (&lock->mutex);
-}
-
-static void vlc_rwlock_rdunlock (vlc_rwlock_t *lock)
-{
-    vlc_mutex_lock (&lock->mutex);
-    assert (lock->readers > 0);
-
-    /* If there are no readers left, wake up a writer. */
-    if (--lock->readers == 0)
-        vlc_cond_signal (&lock->wait);
-    vlc_mutex_unlock (&lock->mutex);
-}
-
-void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
-{
-    vlc_mutex_lock (&lock->mutex);
-    /* Wait until nobody owns the lock in either way. */
-    while ((lock->readers > 0) || (lock->writer != 0))
-        vlc_cond_wait (&lock->wait, &lock->mutex);
-    assert (lock->writer == 0);
-    lock->writer = _gettid ();
-    vlc_mutex_unlock (&lock->mutex);
-}
-
-static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
-{
-    vlc_mutex_lock (&lock->mutex);
-    assert (lock->writer == _gettid ());
-    assert (lock->readers == 0);
-    lock->writer = 0; /* Write unlock */
-
-    /* Let reader and writer compete. Scheduler decides who wins. */
-    vlc_cond_broadcast (&lock->wait);
-    vlc_mutex_unlock (&lock->mutex);
-}
-
-void vlc_rwlock_unlock (vlc_rwlock_t *lock)
-{
-    /* Note: If the lock is held for reading, lock->writer is nul.
-     * If the lock is held for writing, only this thread can store a value to
-     * lock->writer. Either way, lock->writer is safe to fetch here. */
-    if (lock->writer != 0)
-        vlc_rwlock_wrunlock (lock);
-    else
-        vlc_rwlock_rdunlock (lock);
-}
+#include "misc/rwlock.h"
 
 /*** Thread-specific variables (TLS) ***/
 struct vlc_threadvar
index 5b12c45ea3d323efd4a5cb3dfc8b5425b5be5386..848c5a3c68c0ee31d22998748e5737594c126fae 100644 (file)
@@ -303,81 +303,30 @@ void vlc_sem_wait (vlc_sem_t *sem)
 }
 
 /*** Read/write locks */
+#if 0
 /* SRW (Slim Read Write) locks are available in Vista+ only */
 void vlc_rwlock_init (vlc_rwlock_t *lock)
 {
-    vlc_mutex_init (&lock->mutex);
-    vlc_cond_init (&lock->wait);
-    lock->readers = 0; /* active readers */
-    lock->writer = 0; /* ID of active writer */
 }
 
 void vlc_rwlock_destroy (vlc_rwlock_t *lock)
 {
-    vlc_cond_destroy (&lock->wait);
-    vlc_mutex_destroy (&lock->mutex);
 }
 
 void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
 {
-    vlc_mutex_lock (&lock->mutex);
-    /* Recursive read-locking is allowed. We only need to ensure that there is
-     * no active writer. */
-    while (lock->writer != 0)
-    {
-        assert (lock->readers == 0);
-        vlc_cond_wait (&lock->wait, &lock->mutex);
-    }
-    if (unlikely(lock->readers == ULONG_MAX))
-        abort ();
-    lock->readers++;
-    vlc_mutex_unlock (&lock->mutex);
-}
-
-static void vlc_rwlock_rdunlock (vlc_rwlock_t *lock)
-{
-    vlc_mutex_lock (&lock->mutex);
-    assert (lock->readers > 0);
-
-    /* If there are no readers left, wake up a writer. */
-    if (--lock->readers == 0)
-        vlc_cond_signal (&lock->wait);
-    vlc_mutex_unlock (&lock->mutex);
 }
 
 void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
 {
-    vlc_mutex_lock (&lock->mutex);
-    /* Wait until nobody owns the lock in either way. */
-    while ((lock->readers > 0) || (lock->writer != 0))
-        vlc_cond_wait (&lock->wait, &lock->mutex);
-    assert (lock->writer == 0);
-    lock->writer = GetCurrentThreadId ();
-    vlc_mutex_unlock (&lock->mutex);
-}
-
-static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
-{
-    vlc_mutex_lock (&lock->mutex);
-    assert (lock->writer == GetCurrentThreadId ());
-    assert (lock->readers == 0);
-    lock->writer = 0; /* Write unlock */
-
-    /* Let reader and writer compete. Scheduler decides who wins. */
-    vlc_cond_broadcast (&lock->wait);
-    vlc_mutex_unlock (&lock->mutex);
 }
 
 void vlc_rwlock_unlock (vlc_rwlock_t *lock)
 {
-    /* Note: If the lock is held for reading, lock->writer is nul.
-     * If the lock is held for writing, only this thread can store a value to
-     * lock->writer. Either way, lock->writer is safe to fetch here. */
-    if (lock->writer != 0)
-        vlc_rwlock_wrunlock (lock);
-    else
-        vlc_rwlock_rdunlock (lock);
 }
+#else
+# include "misc/rwlock.h"
+#endif
 
 /*** Thread-specific variables (TLS) ***/
 struct vlc_threadvar