Commit 3cfff8db authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

Write generic semaphore back-end and merge generic thread code

parent 4b95124b
......@@ -158,8 +158,8 @@ typedef struct
} vlc_cond_t;
#define VLC_STATIC_COND { 0, 0 }
typedef HANDLE vlc_sem_t;
typedef struct vlc_rwlock vlc_rwlock_t;
typedef HANDLE vlc_sem_t;
#define LIBVLC_NEED_RWLOCK
typedef struct vlc_threadvar *vlc_threadvar_t;
typedef struct vlc_timer *vlc_timer_t;
......@@ -188,27 +188,29 @@ typedef struct
} vlc_cond_t;
#define VLC_STATIC_COND { 0, 0 }
typedef struct
{
HEV hev;
HMTX wait_mutex;
HMTX count_mutex;
int count;
} vlc_sem_t;
typedef struct vlc_rwlock vlc_rwlock_t;
#define LIBVLC_NEED_SEMAPHORE
#define LIBVLC_NEED_RWLOCK
typedef struct vlc_threadvar *vlc_threadvar_t;
typedef struct vlc_timer *vlc_timer_t;
#endif
#ifndef VLC_STATIC_RWLOCK
struct vlc_rwlock
#ifdef LIBVLC_NEED_SEMAPHORE
typedef struct vlc_sem
{
vlc_mutex_t lock;
vlc_cond_t wait;
unsigned value;
} vlc_sem_t;
#endif
#ifdef LIBVLC_NEED_RWLOCK
typedef struct vlc_rwlock
{
vlc_mutex_t mutex;
vlc_cond_t wait;
long state;
};
} vlc_rwlock_t;
# define VLC_STATIC_RWLOCK { VLC_STATIC_MUTEX, VLC_STATIC_COND, 0 }
#endif
......
......@@ -269,7 +269,6 @@ SOURCES_libvlc_win32 = \
win32/dirs.c \
win32/filesystem.c \
win32/plugin.c \
misc/rwlock.c \
win32/thread.c \
win32/specific.c \
win32/winsock.c \
......@@ -288,7 +287,6 @@ SOURCES_libvlc_os2 = \
os2/dirs.c \
os2/filesystem.c \
os2/plugin.c \
misc/rwlock.c \
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);
mutex_cleanup_push (&lock->mutex);
vlc_cond_wait (&lock->wait, &lock->mutex);
vlc_cleanup_pop ();
}
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)
{
mutex_cleanup_push (&lock->mutex);
vlc_cond_wait (&lock->wait, &lock->mutex);
vlc_cleanup_pop ();
}
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);
}
/*****************************************************************************
* threads.c : threads implementation for the VideoLAN client
* threads.c: LibVLC generic thread support
*****************************************************************************
* Copyright (C) 1999-2008 VLC authors and VideoLAN
* $Id$
*
* Authors: Jean-Marc Dressler <polux@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
* Gildas Bazin <gbazin@netcourrier.com>
* Clément Sténac
* Rémi Denis-Courmont
* 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
......@@ -29,9 +22,10 @@
# include "config.h"
#endif
#include <vlc_common.h>
#include <assert.h>
#include <vlc_common.h>
/*** Global locks ***/
void vlc_global_mutex (unsigned n, bool acquire)
......@@ -54,3 +48,127 @@ void vlc_global_mutex (unsigned n, bool acquire)
else
vlc_mutex_unlock (lock);
}
#ifdef LIBVLC_NEED_RWLOCK
/*** Generic read/write locks ***/
#include <stdlib.h>
#include <limits.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);
mutex_cleanup_push (&lock->mutex);
vlc_cond_wait (&lock->wait, &lock->mutex);
vlc_cleanup_pop ();
}
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)
{
mutex_cleanup_push (&lock->mutex);
vlc_cond_wait (&lock->wait, &lock->mutex);
vlc_cleanup_pop ();
}
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);
}
#endif /* LIBVLC_NEED_RWLOCK */
#ifdef LIBVLC_NEED_SEMAPHORE
/*** Generic semaphores ***/
#include <limits.h>
#include <errno.h>
void vlc_sem_init (vlc_sem_t *sem, unsigned value)
{
vlc_mutex_init (&sem->lock);
vlc_cond_init (&sem->wait);
sem->value = value;
}
void vlc_sem_destroy (vlc_sem_t *sem)
{
vlc_cond_destroy (&sem->wait);
vlc_mutex_destroy (&sem->lock);
}
int vlc_sem_post (vlc_sem_t *sem)
{
int ret = 0;
vlc_mutex_lock (&sem->lock);
if (likely(sem->value != UINT_MAX))
sem->value++;
else
ret = EOVERFLOW;
vlc_mutex_unlock (&sem->lock);
vlc_cond_signal (&sem->wait);
return ret;
}
void vlc_sem_wait (vlc_sem_t *sem)
{
vlc_mutex_lock (&sem->lock);
while (!sem->value)
vlc_cond_wait (&sem->wait, &sem->lock);
sem->value--;
vlc_mutex_unlock (&sem->lock);
}
#endif /* LIBVLC_NEED_SEMAPHORE */
......@@ -360,74 +360,6 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
return rc ? ETIMEDOUT : 0;
}
/*** Semaphore ***/
void vlc_sem_init (vlc_sem_t *sem, unsigned value)
{
if (DosCreateEventSem(NULL, &sem->hev, 0, value > 0 ? TRUE : FALSE))
abort ();
if (DosCreateMutexSem(NULL, &sem->wait_mutex, 0, FALSE))
abort ();
if (DosCreateMutexSem(NULL, &sem->count_mutex, 0, FALSE))
abort ();
sem->count = value;
}
void vlc_sem_destroy (vlc_sem_t *sem)
{
DosCloseEventSem (sem->hev);
DosCloseMutexSem (sem->wait_mutex);
DosCloseMutexSem (sem->count_mutex);
}
int vlc_sem_post (vlc_sem_t *sem)
{
DosRequestMutexSem(sem->count_mutex, SEM_INDEFINITE_WAIT);
if (sem->count < 0x7FFFFFFF)
{
sem->count++;
DosPostEventSem(sem->hev);
}
DosReleaseMutexSem(sem->count_mutex);
return 0; /* FIXME */
}
void vlc_sem_wait (vlc_sem_t *sem)
{
ULONG rc;
do
{
vlc_testcancel ();
DosRequestMutexSem(sem->wait_mutex, SEM_INDEFINITE_WAIT);
rc = vlc_WaitForSingleObject (sem->hev, SEM_INDEFINITE_WAIT );
if (!rc)
{
DosRequestMutexSem(sem->count_mutex, SEM_INDEFINITE_WAIT);
sem->count--;
if (sem->count == 0)
{
ULONG ulPost;
DosResetEventSem(sem->hev, &ulPost);
}
DosReleaseMutexSem(sem->count_mutex);
}
DosReleaseMutexSem(sem->wait_mutex);
} while (rc == ERROR_INTERRUPT);
}
/*** 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