#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;
HMTX hmtx;
};
} vlc_mutex_t;
-
#define VLC_STATIC_MUTEX { false, { { false, 0 } } }
typedef struct
HEV hev;
unsigned clock;
} vlc_cond_t;
-
#define VLC_STATIC_COND { 0, 0 }
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
win32/dirs.c \
win32/filesystem.c \
win32/plugin.c \
+ misc/rwlock.h \
win32/thread.c \
win32/specific.c \
win32/winsock.c \
os2/dirs.c \
os2/filesystem.c \
os2/plugin.c \
+ misc/rwlock.h \
os2/thread.c \
os2/specific.c \
os2/rand.c \
--- /dev/null
+/*****************************************************************************
+ * 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);
+}
} 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
}
/*** 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