Commit a8c16439 authored by Rafaël Carré's avatar Rafaël Carré

remove applied threads patch

parent 37cdb9bb
...@@ -89,7 +89,7 @@ export PLATFORM_SHORT_ARCH ...@@ -89,7 +89,7 @@ export PLATFORM_SHORT_ARCH
export PATH=${ANDROID_NDK}/toolchains/${PATH_HOST}-${GCCVER}/prebuilt/`uname|tr A-Z a-z`-x86/bin:${PATH} export PATH=${ANDROID_NDK}/toolchains/${PATH_HOST}-${GCCVER}/prebuilt/`uname|tr A-Z a-z`-x86/bin:${PATH}
# 1/ libvlc, libvlccore and its plugins # 1/ libvlc, libvlccore and its plugins
TESTED_HASH=26b84afd TESTED_HASH=4a742a33
if [ ! -d "vlc" ]; then if [ ! -d "vlc" ]; then
echo "VLC source not found, cloning" echo "VLC source not found, cloning"
git clone git://git.videolan.org/vlc.git vlc git clone git://git.videolan.org/vlc.git vlc
......
From 1c54a378849090489b1c83159217f24375e66627 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C3=ABl=20Carr=C3=A9?= <funman@videolan.org>
Date: Sat, 10 Mar 2012 04:54:23 -0500
Subject: [PATCH 1/6] android: threads support
emulate pthread_cancel (based on win32 code)
TODO:
- move initialization somewhere else
- use lock for cond/killed/killable?
-> ndk gcc doesn't support atomic ops nor __thread
-> read/writes should be atomic on arm (ldr/str)
-> cond atomic access should be guaranteed by using the cond's
mutex when signaling
- split thread.c to move specific code to own file:
affected functions are:
* vlc_cond_wait()
* vlc_cond_timedwait()
* vlc_clone_attr()
* vlc_join()
* vlc_cancel()
* vlc_savecancel()
* vlc_testcancel()
* vlc_restorecancel()
* vlc_control_cancel()
* vlc_sem_wait()
* msleep()
timer, rwlocks, mutexes, clock, threadvar
are 100% shared with linux so it'd be useless to have 2 copies.
---
include/vlc_threads.h | 13 +++
lib/error.c | 10 +++
src/Makefile.am | 17 ++++
src/posix/thread.c | 239 ++++++++++++++++++++++++++++++++++++++++++++------
4 files changed, 253 insertions(+), 26 deletions(-)
diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index cc0e8b1..77ab8a5 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -42,6 +42,15 @@
# define pthread_sigmask sigprocmask
+#elif defined( __ANDROID__ ) /* pthreads without pthread_cancel() */
+
+# define LIBVLC_USE_PTHREAD 1
+
+# include <unistd.h> /* _POSIX_SPIN_LOCKS */
+# include <pthread.h>
+# include <poll.h>
+# include <semaphore.h>
+
#else /* pthreads (like Linux & BSD) */
# define LIBVLC_USE_PTHREAD 1
# define LIBVLC_USE_PTHREAD_CANCEL 1
@@ -117,7 +126,11 @@
*****************************************************************************/
#if defined (LIBVLC_USE_PTHREAD)
+# ifdef LIBVLC_USE_PTHREAD_CANCEL
typedef pthread_t vlc_thread_t;
+# else
+typedef struct vlc_thread *vlc_thread_t;
+# endif
typedef pthread_mutex_t vlc_mutex_t;
#define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
typedef pthread_cond_t vlc_cond_t;
diff --git a/lib/error.c b/lib/error.c
index d053faa..52840e8 100644
--- a/lib/error.c
+++ b/lib/error.c
@@ -33,11 +33,17 @@ static vlc_threadvar_t context;
static vlc_mutex_t lock = VLC_STATIC_MUTEX;
static uintptr_t refs = 0;
+void andro_init_threads(bool);
+
void libvlc_threads_init (void)
{
vlc_mutex_lock (&lock);
if (refs++ == 0)
{
+#ifdef __ANDROID__
+ /* XXX: move somewhere else? */
+ andro_init_threads(true);
+#endif
vlc_threadvar_create (&context, free);
libvlc_log_init ();
}
@@ -52,6 +58,10 @@ void libvlc_threads_deinit (void)
{
libvlc_log_deinit ();
vlc_threadvar_delete (&context);
+#ifdef __ANDROID__
+ /* XXX: move somewhere else? */
+ andro_init_threads(false);
+#endif
}
vlc_mutex_unlock (&lock);
}
diff --git a/src/posix/thread.c b/src/posix/thread.c
index c414def..ab2a3af 100644
--- a/src/posix/thread.c
+++ b/src/posix/thread.c
@@ -1,5 +1,5 @@
/*****************************************************************************
- * thread.c : pthread back-end for LibVLC
+ * thread.c : android pthread back-end for LibVLC
*****************************************************************************
* Copyright (C) 1999-2009 VLC authors and VideoLAN
*
@@ -43,6 +43,8 @@
#include <pthread.h>
#include <sched.h>
+# include <android/log.h>
+
#ifdef __linux__
# include <sys/syscall.h> /* SYS_gettid */
#endif
@@ -68,6 +70,17 @@
# define _POSIX_MONOTONIC_CLOCK (-1)
#endif
+
+#undef assert
+#define assert(x) do { \
+ if (!x) { \
+ __android_log_print(ANDROID_LOG_ERROR, "vlc", "assert failed %s:%d: %s", \
+ __FILE__, __LINE__, #x \
+ ); \
+ abort(); \
+ } \
+} while(0)
+
#if (_POSIX_TIMERS > 0)
static unsigned vlc_clock_prec;
@@ -162,7 +175,7 @@ vlc_thread_fatal (const char *action, int error,
const char *function, const char *file, unsigned line)
{
int canc = vlc_savecancel ();
- fprintf (stderr, "LibVLC fatal error %s (%d) in thread %lu ",
+ __android_log_print(ANDROID_LOG_ERROR, "vlc", "LibVLC fatal error %s (%d) in thread %lu ",
action, error, vlc_threadid ());
vlc_trace (function, file, line);
@@ -318,6 +331,57 @@ void vlc_mutex_unlock (vlc_mutex_t *p_mutex)
VLC_THREAD_ASSERT ("unlocking mutex");
}
+struct vlc_thread
+{
+ pthread_t thread;
+ pthread_cond_t *cond; /// Non-null if thread waiting on cond
+ pthread_mutex_t *lock ; /// Non-null if thread waiting on cond
+ vlc_cleanup_t *cleaners;
+
+ void *(*entry)(void*);
+ void *data;
+
+ bool killable;
+ bool killed;
+ bool finished;
+};
+
+static pthread_key_t thread_key = 0;
+
+/* XXX: move somewhere else? */
+void andro_init_threads(bool init)
+{
+ static struct vlc_thread main_thread = {
+ .cond = NULL,
+ .lock = NULL,
+ .cleaners = NULL,
+ .killable = false,
+ .killed = false,
+ .finished = false,
+ .entry = NULL,
+ .data = NULL,
+ };
+
+ if (init) {
+ main_thread.thread = pthread_self();
+ pthread_key_create(&thread_key, NULL);
+ if (pthread_setspecific(thread_key, &main_thread))
+ abort();
+ } else {
+ pthread_key_delete(thread_key);
+ }
+}
+
+static void *andro_Thread(void *data)
+{
+ vlc_thread_t thread = data;
+ if (pthread_setspecific(thread_key, thread))
+ abort();
+ void *ret = thread->entry(thread->data);
+ thread->finished = true;
+ return ret;
+}
+
/**
* Initializes a condition variable.
*/
@@ -411,7 +475,22 @@ void vlc_cond_broadcast (vlc_cond_t *p_condvar)
*/
void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
{
+ vlc_thread_t thread = pthread_getspecific(thread_key);
+
+ if (thread) {
+ vlc_testcancel();
+ thread->cond = p_condvar;
+ thread->lock = p_mutex;
+ }
+
int val = pthread_cond_wait( p_condvar, p_mutex );
+
+ if (thread) {
+ thread->cond = NULL;
+ thread->lock = NULL;
+ vlc_testcancel();
+ }
+
VLC_THREAD_ASSERT ("waiting on condition");
}
@@ -433,10 +512,25 @@ void vlc_cond_wait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex)
int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
mtime_t deadline)
{
+ vlc_thread_t thread = pthread_getspecific(thread_key);
struct timespec ts = mtime_to_ts (deadline);
+
+ if (thread) {
+ vlc_testcancel();
+ thread->cond = p_condvar;
+ thread->lock = p_mutex;
+ }
+
int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts);
if (val != ETIMEDOUT)
VLC_THREAD_ASSERT ("timed-waiting on condition");
+
+ if (thread) {
+ thread->cond = NULL;
+ thread->lock = NULL;
+ vlc_testcancel();
+ }
+
return val;
}
@@ -515,10 +609,14 @@ void vlc_sem_wait (vlc_sem_t *sem)
val = EINVAL;
#else
- do
- if (likely(sem_wait (sem) == 0))
+ do {
+ vlc_testcancel();
+ struct timespec t = mtime_to_ts (mdate());
+ t.tv_nsec += 10 * 1000 * 1000;
+ if (likely(sem_timedwait (sem, &t) == 0))
return;
- while ((val = errno) == EINTR);
+ val = errno;
+ } while (val == EINTR || val == ETIMEDOUT);
#endif
VLC_THREAD_ASSERT ("locking semaphore");
@@ -705,7 +803,22 @@ static int vlc_clone_attr (vlc_thread_t *th, pthread_attr_t *attr,
assert (ret == 0); /* fails iif VLC_STACKSIZE is invalid */
#endif
- ret = pthread_create (th, attr, entry, data);
+ vlc_thread_t thread = malloc (sizeof (*thread));
+ if (unlikely(thread == NULL))
+ return ENOMEM;
+
+ thread->killable = true;
+ thread->killed = false;
+ thread->finished = false,
+ thread->cond = NULL;
+ thread->lock = NULL;
+ thread->cleaners = NULL;
+ thread->entry = entry;
+ thread->data = data;
+
+ *th = thread;
+ ret = pthread_create (&thread->thread, attr, andro_Thread, thread);
+
pthread_sigmask (SIG_SETMASK, &oldset, NULL);
pthread_attr_destroy (attr);
return ret;
@@ -746,8 +859,14 @@ int vlc_clone (vlc_thread_t *th, void *(*entry) (void *), void *data,
*/
void vlc_join (vlc_thread_t handle, void **result)
{
- int val = pthread_join (handle, result);
+ do {
+ vlc_testcancel();
+ msleep(CLOCK_FREQ / 100);
+ } while (!handle->finished);
+
+ int val = pthread_join (handle->thread, result);
VLC_THREAD_ASSERT ("joining thread");
+ free(handle);
}
/**
@@ -827,10 +946,25 @@ int vlc_set_priority (vlc_thread_t th, int priority)
*/
void vlc_cancel (vlc_thread_t thread_id)
{
- pthread_cancel (thread_id);
-#ifdef HAVE_MAEMO
- pthread_kill (thread_id, SIGRTMIN);
-#endif
+ bool self = thread_id == pthread_getspecific(thread_key);
+
+ thread_id->killed = true;
+ if (!thread_id->killable)
+ return;
+
+ vlc_mutex_t *lock = thread_id->lock;
+
+ if (lock) {
+ if (!self)
+ vlc_mutex_lock(lock);
+ if (thread_id->cond)
+ pthread_cond_broadcast(thread_id->cond);
+ if (!self)
+ vlc_mutex_unlock(lock);
+ }
+
+ if (self)
+ vlc_testcancel();
}
/**
@@ -843,11 +977,13 @@ void vlc_cancel (vlc_thread_t thread_id)
*/
int vlc_savecancel (void)
{
- int state;
- int val = pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
+ vlc_thread_t thread = pthread_getspecific(thread_key);
+ if (!thread) /* not created by VLC, can't be cancelled */
+ return true;
- VLC_THREAD_ASSERT ("saving cancellation");
- return state;
+ int oldstate = thread->killable;
+ thread->killable = false;
+ return oldstate;
}
/**
@@ -857,18 +993,19 @@ int vlc_savecancel (void)
*/
void vlc_restorecancel (int state)
{
+ vlc_thread_t thread = pthread_getspecific(thread_key);
+ if (!thread) /* not created by VLC, can't be cancelled */
+ return;
#ifndef NDEBUG
- int oldstate, val;
+ int oldstate = thread->killable;
- val = pthread_setcancelstate (state, &oldstate);
- /* This should fail if an invalid value for given for state */
- VLC_THREAD_ASSERT ("restoring cancellation");
+ thread->killable = state;
- if (unlikely(oldstate != PTHREAD_CANCEL_DISABLE))
+ if (unlikely(oldstate != false))
vlc_thread_fatal ("restoring cancellation while not disabled", EINVAL,
__func__, __FILE__, __LINE__);
#else
- pthread_setcancelstate (state, NULL);
+ thread->killable = state;
#endif
}
@@ -881,13 +1018,48 @@ void vlc_restorecancel (int state)
*/
void vlc_testcancel (void)
{
- pthread_testcancel ();
+ vlc_thread_t thread = pthread_getspecific(thread_key);
+ if (!thread) /* not created by VLC, can't be cancelled */
+ return;
+ if (!thread->killable || !thread->killed)
+ return;
+
+ for (vlc_cleanup_t *p = thread->cleaners; p != NULL; p = p->next)
+ p->proc (p->data);
+
+ thread->finished = true;
+ pthread_exit(NULL);
}
void vlc_control_cancel (int cmd, ...)
{
- (void) cmd;
- assert (0);
+ vlc_thread_t thread = pthread_getspecific(thread_key);
+ if (!thread) /* not created by VLC, can't be cancelled */
+ return;
+ /* NOTE: This function only modifies thread-specific data, so there is no
+ * need to lock anything. */
+ va_list ap;
+
+ va_start (ap, cmd);
+ switch (cmd)
+ {
+ case VLC_CLEANUP_PUSH:
+ {
+ /* cleaner is a pointer to the caller stack, no need to allocate
+ * and copy anything. As a nice side effect, this cannot fail. */
+ vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
+ cleaner->next = thread->cleaners;
+ thread->cleaners = cleaner;
+ break;
+ }
+
+ case VLC_CLEANUP_POP:
+ {
+ thread->cleaners = thread->cleaners->next;
+ break;
+ }
+ }
+ va_end (ap);
}
/**
@@ -964,8 +1136,23 @@ void msleep (mtime_t delay)
while (clock_nanosleep (vlc_clock_id, 0, &ts, &ts) == EINTR);
#else
- while (nanosleep (&ts, &ts) == -1)
- assert (errno == EINTR);
+ vlc_testcancel();
+ for (;;) {
+ struct timespec t = { 0, 10 * 1000 * 1000 };
+ if (ts.tv_sec <= 0 && t.tv_nsec > ts.tv_nsec)
+ t.tv_nsec = ts.tv_nsec;
+ while (nanosleep (&t, &t) == -1) {
+ vlc_testcancel();
+ assert (errno == EINTR);
+ }
+
+ ts.tv_nsec -= 10 * 1000 * 1000;
+ if (ts.tv_nsec < 0) {
+ if (--ts.tv_sec < 0)
+ return;
+ ts.tv_nsec += 1000 * 1000 * 1000;
+ }
+ }
#endif
}
--
1.7.12.1
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