From: RĂ©mi Denis-Courmont Date: Sun, 5 Jul 2009 17:21:43 +0000 (+0300) Subject: Read/write locks X-Git-Tag: 1.1.0-ff~5123 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=651698d171a71e20546045a7faa56e606d0ca9a3;p=vlc Read/write locks --- diff --git a/include/vlc_threads.h b/include/vlc_threads.h index 41426289b3..3b6c838396 100644 --- a/include/vlc_threads.h +++ b/include/vlc_threads.h @@ -107,6 +107,7 @@ typedef pthread_t vlc_thread_t; typedef pthread_mutex_t vlc_mutex_t; #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER typedef pthread_cond_t vlc_cond_t; +typedef pthread_rwlock_t vlc_rwlock_t; typedef pthread_key_t vlc_threadvar_t; typedef struct vlc_timer_t vlc_timer_t; @@ -143,6 +144,17 @@ typedef struct #define VLC_STATIC_MUTEX { 0, } typedef HANDLE vlc_cond_t; + +typedef struct +{ + vlc_mutex_t mutex; + vlc_cond_t read_wait; + vlc_cond_t write_wait; + unsigned long readers; + unsigned long writers; + DWORD writer; +} vlc_rwlock_t; + typedef DWORD vlc_threadvar_t; typedef struct vlc_timer_t vlc_timer_t; struct vlc_timer_t @@ -176,6 +188,11 @@ VLC_EXPORT( void, vlc_cond_signal, (vlc_cond_t *) ); VLC_EXPORT( void, vlc_cond_broadcast, (vlc_cond_t *) ); VLC_EXPORT( void, vlc_cond_wait, (vlc_cond_t *, vlc_mutex_t *) ); VLC_EXPORT( int, vlc_cond_timedwait, (vlc_cond_t *, vlc_mutex_t *, mtime_t) ); +VLC_EXPORT( void, vlc_rwlock_init, (vlc_rwlock_t *) ); +VLC_EXPORT( void, vlc_rwlock_destroy, (vlc_rwlock_t *) ); +VLC_EXPORT( void, vlc_rwlock_rdlock, (vlc_rwlock_t *) ); +VLC_EXPORT( void, vlc_rwlock_wrlock, (vlc_rwlock_t *) ); +VLC_EXPORT( void, vlc_rwlock_unlock, (vlc_rwlock_t *) ); VLC_EXPORT( int, vlc_threadvar_create, (vlc_threadvar_t * , void (*) (void *) ) ); VLC_EXPORT( void, vlc_threadvar_delete, (vlc_threadvar_t *) ); VLC_EXPORT( int, vlc_threadvar_set, (vlc_threadvar_t, void *) ); diff --git a/src/libvlccore.sym b/src/libvlccore.sym index aeaa2e95fe..3d1a407bd0 100644 --- a/src/libvlccore.sym +++ b/src/libvlccore.sym @@ -519,6 +519,11 @@ vlc_poll vlc_rand_bytes vlc_release vlc_restorecancel +vlc_rwlock_destroy +vlc_rwlock_init +vlc_rwlock_rdlock +vlc_rwlock_unlock +vlc_rwlock_wrlock vlc_savecancel vlc_sd_Create vlc_sd_GetNames diff --git a/src/misc/pthread.c b/src/misc/pthread.c index 9264598250..14a48ad21b 100644 --- a/src/misc/pthread.c +++ b/src/misc/pthread.c @@ -375,6 +375,51 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, return val; } +/** + * Initializes a read/write lock. + */ +void vlc_rwlock_init (vlc_rwlock_t *lock) +{ + if (pthread_rwlock_init (lock, NULL)) + abort (); +} + +/** + * Destroys an initialized unused read/write lock. + */ +void vlc_rwlock_destroy (vlc_rwlock_t *lock) +{ + int val = pthread_rwlock_destroy (lock); + VLC_THREAD_ASSERT ("destroying R/W lock"); +} + +/** + * Acquires a read/write lock for reading. Recursion is allowed. + */ +void vlc_rwlock_rdlock (vlc_rwlock_t *lock) +{ + int val = pthread_rwlock_rdlock (lock); + VLC_THREAD_ASSERT ("acquiring R/W lock for reading"); +} + +/** + * Acquires a read/write lock for writing. Recursion is not allowed. + */ +void vlc_rwlock_wrlock (vlc_rwlock_t *lock) +{ + int val = pthread_rwlock_wrlock (lock); + VLC_THREAD_ASSERT ("acquiring R/W lock for writing"); +} + +/** + * Releases a read/write lock. + */ +void vlc_rwlock_unlock (vlc_rwlock_t *lock) +{ + int val = pthread_rwlock_unlock (lock); + VLC_THREAD_ASSERT ("releasing R/W lock"); +} + /** * Allocates a thread-specific variable. * @param key where to store the thread-specific variable handle diff --git a/src/misc/w32thread.c b/src/misc/w32thread.c index 24f991e04d..7c722c74ff 100644 --- a/src/misc/w32thread.c +++ b/src/misc/w32thread.c @@ -34,6 +34,7 @@ #include "libvlc.h" #include #include +#include static vlc_threadvar_t cancel_key; @@ -291,6 +292,82 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex, return (result == WAIT_OBJECT_0) ? 0 : ETIMEDOUT; } +/*** Read/write locks */ +/* 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->read_wait); + vlc_cond_init (&lock->write_wait); + lock->readers = 0; /* active readers */ + lock->writers = 0; /* waiting or active 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); + vlc_cond_destroy (&lock->write_wait); + 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); + while (lock->writers > 0) /* Favor writers to avoid starving */ + vlc_cond_wait (&lock->read_wait, &lock->mutex); + if (lock->readers == ULONG_MAX) + abort (); + lock->readers++; + vlc_mutex_unlock (&lock->mutex); +} + +/** + * Acquires a read/write lock for writing. Recursion is not allowed. + */ +void vlc_rwlock_wrlock (vlc_rwlock_t *lock) +{ + vlc_mutex_lock (&lock->mutex); + if (lock->writers == ULONG_MAX) + abort (); + lock->writers++; + while ((lock->readers > 0) || (lock->writer != 0)) + vlc_cond_wait (&lock->write_wait, &lock->mutex); + lock->writer = GetCurrentThreadId (); + vlc_mutex_unlock (&lock->mutex); +} + +/** + * Releases a read/write lock. + */ +void vlc_rwlock_unlock (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->writers > 0); + lock->writers--; + } + + if (lock->writers > 0) + { + if (lock->readers == 0) + vlc_cond_signal (&lock->write_wait); + } + else + vlc_cond_broadcast (&lock->read_wait); + vlc_mutex_unlock (&lock->mutex); +} + /*** Thread-specific variables (TLS) ***/ int vlc_threadvar_create (vlc_threadvar_t *p_tls, void (*destr) (void *)) {