[vlc-commits] android: use generic condition variable and wait (fix #14586)
Rémi Denis-Courmont
git at videolan.org
Sat May 28 15:08:29 CEST 2016
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Fri May 27 01:13:57 2016 +0300| [6f3e18d534e4fcfeeba6e9b8051ec0db1ea1b3c8] | committer: Rémi Denis-Courmont
android: use generic condition variable and wait (fix #14586)
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=6f3e18d534e4fcfeeba6e9b8051ec0db1ea1b3c8
---
include/vlc_threads.h | 4 +-
src/android/thread.c | 245 ++++++++++++-------------------------------------
2 files changed, 60 insertions(+), 189 deletions(-)
diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 4792cc1..c06c69b 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -161,6 +161,8 @@ static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
# include <pthread.h>
# include <poll.h>
# define LIBVLC_USE_PTHREAD_CLEANUP 1
+# define LIBVLC_NEED_SLEEP
+# define LIBVLC_NEED_CONDVAR
# define LIBVLC_NEED_SEMAPHORE
# define LIBVLC_NEED_RWLOCK
@@ -168,8 +170,6 @@ typedef struct vlc_thread *vlc_thread_t;
#define VLC_THREAD_CANCELED NULL
typedef pthread_mutex_t vlc_mutex_t;
#define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
-typedef pthread_cond_t vlc_cond_t;
-#define VLC_STATIC_COND PTHREAD_COND_INITIALIZER
typedef pthread_key_t vlc_threadvar_t;
typedef struct vlc_timer *vlc_timer_t;
diff --git a/src/android/thread.c b/src/android/thread.c
index 6c8397d..3dfe3e6 100644
--- a/src/android/thread.c
+++ b/src/android/thread.c
@@ -1,7 +1,7 @@
/*****************************************************************************
* thread.c : android pthread back-end for LibVLC
*****************************************************************************
- * Copyright (C) 1999-2012 VLC authors and VideoLAN
+ * Copyright (C) 1999-2016 VLC authors and VideoLAN
*
* Authors: Jean-Marc Dressler <polux at via.ecp.fr>
* Samuel Hocevar <sam at zoy.org>
@@ -48,15 +48,6 @@
#error no pthread monotonic clock support
#endif
-/* helper */
-static struct timespec mtime_to_ts (mtime_t date)
-{
- lldiv_t d = lldiv (date, CLOCK_FREQ);
- struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
-
- return ts;
-}
-
/* debug */
#define vlc_assert(x) do { \
if (unlikely(!(x))) { \
@@ -166,13 +157,17 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
struct vlc_thread
{
pthread_t thread;
- pthread_cond_t *cond; /// Non-null if thread waiting on cond
- vlc_mutex_t lock ; /// Protects cond
vlc_sem_t finished;
void *(*entry)(void*);
void *data;
+ struct
+ {
+ void *addr; /// Non-null if waiting on futex
+ vlc_mutex_t lock ; /// Protects futex address
+ } wait;
+
atomic_bool killed;
bool killable;
};
@@ -189,149 +184,13 @@ void vlc_threads_setup (libvlc_int_t *p_libvlc)
(void)p_libvlc;
}
-/* cond */
-
-void vlc_cond_init (vlc_cond_t *condvar)
-{
-#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
- if (unlikely(pthread_cond_init (condvar, NULL)))
- abort ();
-#else
- pthread_condattr_t attr;
-
- pthread_condattr_init (&attr);
- pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
-
- if (unlikely(pthread_cond_init (condvar, &attr)))
- abort ();
-#endif
-}
-
-void vlc_cond_init_daytime (vlc_cond_t *condvar)
-{
- if (unlikely(pthread_cond_init (condvar, NULL)))
- abort ();
-}
-
-void vlc_cond_destroy (vlc_cond_t *condvar)
-{
- int val = pthread_cond_destroy (condvar);
- VLC_THREAD_ASSERT ("destroying condition");
-}
-
-void vlc_cond_signal (vlc_cond_t *condvar)
-{
- int val = pthread_cond_signal (condvar);
- VLC_THREAD_ASSERT ("signaling condition variable");
-}
-
-void vlc_cond_broadcast (vlc_cond_t *condvar)
-{
- pthread_cond_broadcast (condvar);
-}
-
-void vlc_cond_wait (vlc_cond_t *condvar, vlc_mutex_t *p_mutex)
-{
- vlc_thread_t th = thread;
-
- if (th != NULL)
- {
- vlc_testcancel ();
- if (vlc_mutex_trylock (&th->lock) == 0)
- {
- th->cond = condvar;
- vlc_mutex_unlock (&th->lock);
- }
- else
- { /* The lock is already held by another thread.
- * => That other thread has just cancelled this one. */
- vlc_testcancel ();
- /* Cancellation did not occur even though this thread is cancelled.
- * => Cancellation is disabled. */
- th = NULL;
- }
- }
-
- int val = pthread_cond_wait (condvar, p_mutex);
- VLC_THREAD_ASSERT ("waiting on condition");
-
- if (th != NULL)
- {
- vlc_mutex_lock(&th->lock);
- th->cond = NULL;
- vlc_mutex_unlock(&th->lock);
- vlc_testcancel();
- }
-}
-
-typedef int (*vlc_cond_wait_cb)(pthread_cond_t *, pthread_mutex_t *,
- const struct timespec *);
-
-static int vlc_cond_timedwait_common(vlc_cond_t *condvar, vlc_mutex_t *mutex,
- const struct timespec *ts,
- vlc_cond_wait_cb cb)
-{
- vlc_thread_t th = thread;
-
- if (th != NULL)
- {
- vlc_testcancel ();
- if (vlc_mutex_trylock (&th->lock) == 0)
- {
- th->cond = condvar;
- vlc_mutex_unlock (&th->lock);
- }
- else
- { /* The lock is already held by another thread.
- * => That other thread has just cancelled this one. */
- vlc_testcancel ();
- /* Cancellation did not occur even though this thread is cancelled.
- * => Cancellation is disabled. */
- th = NULL;
- }
- }
-
- int val = cb(condvar, mutex, ts);
- if (val != ETIMEDOUT)
- VLC_THREAD_ASSERT ("timed-waiting on condition");
-
- if (th != NULL)
- {
- vlc_mutex_lock(&th->lock);
- th->cond = NULL;
- vlc_mutex_unlock(&th->lock);
- vlc_testcancel();
- }
- return val;
-}
-
-int vlc_cond_timedwait(vlc_cond_t *cond, vlc_mutex_t *mutex, mtime_t deadline)
-{
- struct timespec ts = mtime_to_ts(deadline);
-
-#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP
- return vlc_cond_timedwait_common(cond, mutex, &ts,
- pthread_cond_timedwait_monotonic_np);
-#else
- return vlc_cond_timedwait_common(cond, mutex, &ts, pthread_cond_timedwait);
-#endif
-}
-
-int vlc_cond_timedwait_daytime(vlc_cond_t *cond, vlc_mutex_t *mutex,
- time_t deadline)
-{
- struct timespec ts = { deadline, 0 };
-
- return vlc_cond_timedwait_common(cond, mutex, &ts, pthread_cond_timedwait);
-}
-
/* pthread */
static void clean_detached_thread(void *data)
{
struct vlc_thread *th = data;
/* release thread handle */
- vlc_mutex_destroy(&th->lock);
+ vlc_mutex_destroy(&th->wait.lock);
free(th);
}
@@ -344,9 +203,7 @@ static void *detached_thread(void *data)
vlc_cleanup_push(clean_detached_thread, th);
th->entry(th->data);
vlc_cleanup_pop();
- vlc_mutex_destroy(&th->lock);
- free(th);
-
+ clean_detached_thread(th);
return NULL;
}
@@ -397,10 +254,10 @@ static int vlc_clone_attr (vlc_thread_t *th, void *(*entry) (void *),
vlc_sem_init(&thread->finished, 0);
atomic_store(&thread->killed, false);
thread->killable = true;
- thread->cond = NULL;
thread->entry = entry;
thread->data = data;
- vlc_mutex_init(&thread->lock);
+ thread->wait.addr = NULL;
+ vlc_mutex_init(&thread->wait.lock);
pthread_attr_t attr;
pthread_attr_init (&attr);
@@ -430,8 +287,7 @@ void vlc_join (vlc_thread_t handle, void **result)
int val = pthread_join (handle->thread, result);
VLC_THREAD_ASSERT ("joining thread");
- vlc_mutex_destroy(&handle->lock);
- free(handle);
+ clean_detached_thread(handle);
}
int vlc_clone_detach (vlc_thread_t *th, void *(*entry) (void *), void *data,
@@ -453,15 +309,18 @@ int vlc_set_priority (vlc_thread_t th, int priority)
void vlc_cancel (vlc_thread_t thread_id)
{
- pthread_cond_t *cond;
+ atomic_int *addr;
atomic_store(&thread_id->killed, true);
- vlc_mutex_lock(&thread_id->lock);
- cond = thread_id->cond;
- if (cond)
- pthread_cond_broadcast(cond);
- vlc_mutex_unlock(&thread_id->lock);
+ vlc_mutex_lock(&thread_id->wait.lock);
+ addr = thread_id->wait.addr;
+ if (addr != NULL)
+ {
+ atomic_fetch_and_explicit(addr, -2, memory_order_relaxed);
+ vlc_addr_broadcast(addr);
+ }
+ vlc_mutex_unlock(&thread_id->wait.lock);
}
int vlc_savecancel (void)
@@ -494,6 +353,43 @@ void vlc_testcancel (void)
pthread_exit(NULL);
}
+void vlc_control_cancel(int cmd, ...)
+{
+ vlc_thread_t th = vlc_thread_self();
+ va_list ap;
+
+ va_start(ap, cmd);
+ switch (cmd)
+ {
+ case VLC_CANCEL_ADDR_SET:
+ {
+ void *addr = va_arg(ap, void *);
+
+ vlc_mutex_lock(&th->wait.lock);
+ assert(th->wait.addr == NULL);
+ th->wait.addr = addr;
+ vlc_mutex_unlock(&th->wait.lock);
+ break;
+ }
+
+ case VLC_CANCEL_ADDR_CLEAR:
+ {
+ void *addr = va_arg(ap, void *);
+
+ vlc_mutex_lock(&th->wait.lock);
+ assert(th->wait.addr == addr);
+ th->wait.addr = NULL;
+ (void) addr;
+ vlc_mutex_unlock(&th->wait.lock);
+ break;
+ }
+
+ default:
+ vlc_assert_unreachable ();
+ }
+ va_end(ap);
+}
+
/* threadvar */
int vlc_threadvar_create (vlc_threadvar_t *key, void (*destr) (void *))
@@ -527,31 +423,6 @@ mtime_t mdate (void)
return (INT64_C(1000000) * ts.tv_sec) + (ts.tv_nsec / 1000);
}
-#undef mwait
-void mwait (mtime_t deadline)
-{
- vlc_mutex_t lock;
- vlc_cond_t wait;
-
- vlc_mutex_init (&lock);
- vlc_cond_init (&wait);
-
- vlc_mutex_lock (&lock);
- mutex_cleanup_push (&lock);
- while (!vlc_cond_timedwait (&wait, &lock, deadline));
- vlc_cleanup_pop ();
- vlc_mutex_unlock (&lock);
-
- vlc_cond_destroy (&wait);
- vlc_mutex_destroy (&lock);
-}
-
-#undef msleep
-void msleep (mtime_t delay)
-{
- mwait (mdate () + delay);
-}
-
/* cpu */
unsigned vlc_GetCPUCount(void)
More information about the vlc-commits
mailing list