Commit fba184a0 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont
Browse files

rwlock: reduce footprint and factor Win32 and OS/2 back-ends

parent 4cd019b1
......@@ -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
......
......@@ -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 \
......
/*****************************************************************************
* 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);
}
......@@ -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
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment