[vlc-commits] Win32 R/W locks: fix/add comments, add asserts

Rémi Denis-Courmont git at videolan.org
Sat May 7 11:01:07 CEST 2011


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Fri May  6 16:12:33 2011 +0300| [53ffb22418d7d213e1c82c64f0c8efb1cea7c5c8] | committer: Rémi Denis-Courmont

Win32 R/W locks: fix/add comments, add asserts

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

 src/win32/thread.c |   70 ++++++++++++++++++++++++++++++++-------------------
 1 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/src/win32/thread.c b/src/win32/thread.c
index e040838..8902050 100644
--- a/src/win32/thread.c
+++ b/src/win32/thread.c
@@ -392,13 +392,10 @@ void vlc_rwlock_init (vlc_rwlock_t *lock)
     vlc_cond_init (&lock->read_wait);
     vlc_cond_init (&lock->write_wait);
     lock->readers = 0; /* active readers */
-    lock->writers = 0; /* waiting or active writers */
+    lock->writers = 0; /* waiting writers */
     lock->writer = 0; /* ID of active writer */
 }
 
-/**
- * Destroys an initialized unused read/write lock.
- */
 void vlc_rwlock_destroy (vlc_rwlock_t *lock)
 {
     vlc_cond_destroy (&lock->read_wait);
@@ -406,57 +403,78 @@ void vlc_rwlock_destroy (vlc_rwlock_t *lock)
     vlc_mutex_destroy (&lock->mutex);
 }
 
-/**
- * Acquires a read/write lock for reading. Recursion is allowed.
- */
 void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
 {
     vlc_mutex_lock (&lock->mutex);
+    /* Recursive read-locking is allowed. With the infos available:
+     *  - the loosest possible condition (no active writer) is:
+     *     (lock->writer != 0)
+     *  - the strictest possible condition is:
+     *     (lock->writer != 0 || (lock->readers == 0 && lock->writers > 0))
+     *  or (lock->readers == 0 && (lock->writer != 0 || lock->writers > 0))
+     */
     while (lock->writer != 0)
+    {
+        assert (lock->readers == 0);
         vlc_cond_wait (&lock->read_wait, &lock->mutex);
-    if (lock->readers == ULONG_MAX)
+    }
+    if (unlikely(lock->readers == ULONG_MAX))
         abort ();
     lock->readers++;
     vlc_mutex_unlock (&lock->mutex);
 }
 
-/**
- * Acquires a read/write lock for writing. Recursion is not allowed.
- */
+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 && lock->writers > 0)
+        vlc_cond_signal (&lock->write_wait);
+    vlc_mutex_unlock (&lock->mutex);
+}
+
 void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
 {
     vlc_mutex_lock (&lock->mutex);
-    if (lock->writers == ULONG_MAX)
+    if (unlikely(lock->writers == ULONG_MAX))
         abort ();
     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);
     lock->writers--;
+    assert (lock->writer == 0);
     lock->writer = GetCurrentThreadId ();
     vlc_mutex_unlock (&lock->mutex);
 }
 
-/**
- * Releases a read/write lock.
- */
-void vlc_rwlock_unlock (vlc_rwlock_t *lock)
+static void vlc_rwlock_wrunlock (vlc_rwlock_t *lock)
 {
     vlc_mutex_lock (&lock->mutex);
-    if (lock->readers > 0)
-        lock->readers--; /* Read unlock */
-    else
-        lock->writer = 0; /* Write unlock */
+    assert (lock->writer == GetCurrentThreadId ());
+    assert (lock->readers == 0);
+    lock->writer = 0; /* Write unlock */
 
+    /* Let reader and writer compete. Scheduler decides who wins. */
     if (lock->writers > 0)
-    {
-        if (lock->readers == 0)
-            vlc_cond_signal (&lock->write_wait);
-    }
-    else
-        vlc_cond_broadcast (&lock->read_wait);
+        vlc_cond_signal (&lock->write_wait);
+    vlc_cond_broadcast (&lock->read_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);
+}
+
 /*** Thread-specific variables (TLS) ***/
 struct vlc_threadvar
 {



More information about the vlc-commits mailing list