[vlc-devel] [PATCH] nacl: Add custom thread implementation

Jean-Baptiste Kempf jb at videolan.org
Wed Apr 5 21:56:10 CEST 2017


From: Dennis Hamester <dennis.hamester at startmail.com>

Similar to Android, NaCl has a pthread implementation without support
for thread cancellation.

We reuse android/thread in order to minimize new threading code
but we complement that with a custom implementation of futexes,
which falls back to pthread mutexes and condition variables.
Actual futexes are not available to regular NaCl modules.

Signed-off-by: Jean-Baptiste Kempf <jb at videolan.org>
---
 include/vlc_threads.h |   2 +-
 src/Makefile.am       |   2 +
 src/nacl/thread.c     | 170 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 173 insertions(+), 1 deletion(-)
 create mode 100644 src/nacl/thread.c

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 9911d2eacf..98e8c5976e 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -157,7 +157,7 @@ static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
 }
 # define poll(u,n,t) vlc_poll(u, n, t)
 
-#elif defined (__ANDROID__)      /* pthreads subset without pthread_cancel() */
+#elif defined (__ANDROID__) || defined(__native_client__)      /* pthreads subset without pthread_cancel() */
 # include <unistd.h>
 # include <pthread.h>
 # include <poll.h>
diff --git a/src/Makefile.am b/src/Makefile.am
index 954322b7f4..ebd90daa3f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -387,6 +387,8 @@ else
 if HAVE_NACL
 libvlccore_la_SOURCES += \
 	android/error.c \
+	android/thread.c \
+	nacl/thread.c \
 	posix/dirs.c \
 	posix/filesystem.c \
 	posix/netconf.c \
diff --git a/src/nacl/thread.c b/src/nacl/thread.c
new file mode 100644
index 0000000000..3d800a7cfb
--- /dev/null
+++ b/src/nacl/thread.c
@@ -0,0 +1,170 @@
+/*****************************************************************************
+ * thread.c : nacl thread functions and futexes
+ *****************************************************************************
+ * Copyright (C) 2017 VLC authors and VideoLAN
+ *
+ * Authors: Dennis Hamester <dhamester at jusst.de>
+ *
+ * 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 <vlc_common.h>
+#include <vlc_atomic.h>
+
+#include "libvlc.h"
+#include <errno.h>
+#include <time.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <pthread.h>
+
+unsigned long vlc_thread_id(void)
+{
+    return (unsigned long)(void *)pthread_self();
+}
+
+typedef struct {
+    void *next;
+    void *addr;
+    int ref_count;
+    pthread_cond_t cv;
+} futex_t;
+
+static futex_t *futex_list = NULL;
+static pthread_mutex_t futex_list_mtx = PTHREAD_MUTEX_INITIALIZER;
+
+static futex_t* get_futex(void *addr, bool create) {
+    futex_t *empty = NULL;
+    futex_t *prev = NULL;
+    futex_t *futex = futex_list;
+    while (futex && (futex->addr != addr)) {
+        if (!futex->addr)
+            empty = futex;
+
+        prev = futex;
+        futex = futex->next;
+    }
+
+    if (!futex && create) {
+        if(empty) {
+            empty->addr = addr;
+            futex = empty;
+        }
+        else {
+            futex_t **last;
+            if (prev)
+                last = (futex_t **)&prev->next;
+            else
+                last = &futex_list;
+
+            *last = futex = malloc(sizeof(futex_t));
+            if (!futex)
+                abort();
+            futex->next = NULL;
+            futex->addr = addr;
+            futex->ref_count = 0;
+            pthread_cond_init(&futex->cv, NULL);
+        }
+    }
+
+    if (futex)
+        ++futex->ref_count;
+
+    return futex;
+}
+
+static void release_futex(futex_t *futex) {
+    --futex->ref_count;
+    if (!futex->ref_count)
+        futex->addr = NULL;
+}
+
+void vlc_addr_signal(void *addr)
+{
+    if(pthread_mutex_lock(&futex_list_mtx))
+        return;
+
+    futex_t *futex = get_futex(addr, false);
+    if (futex) {
+        pthread_cond_signal(&futex->cv);
+        release_futex(futex);
+    }
+
+    pthread_mutex_unlock(&futex_list_mtx);
+}
+
+void vlc_addr_broadcast(void *addr)
+{
+    if(pthread_mutex_lock(&futex_list_mtx))
+        return;
+
+    futex_t *futex = get_futex(addr, false);
+    if (futex) {
+        pthread_cond_broadcast(&futex->cv);
+        release_futex(futex);
+    }
+
+    pthread_mutex_unlock(&futex_list_mtx);
+}
+
+void vlc_addr_wait(void *addr, unsigned val)
+{
+    volatile unsigned *ptr = (volatile unsigned *)addr;
+    if (*ptr != val)
+        return;
+
+    if(pthread_mutex_lock(&futex_list_mtx))
+        return;
+
+    futex_t *futex = get_futex(addr, true);
+    while (*ptr == val) {
+        if (pthread_cond_wait(&futex->cv, &futex_list_mtx))
+            break;
+    }
+
+    release_futex(futex);
+    pthread_mutex_unlock(&futex_list_mtx);
+}
+
+bool vlc_addr_timedwait(void *addr, unsigned val, mtime_t delay)
+{
+    volatile unsigned *ptr = (volatile unsigned *)addr;
+    if (*ptr != val)
+        return true;
+
+    if(pthread_mutex_lock(&futex_list_mtx))
+        return true;
+
+    bool timeout = false;
+    futex_t *futex = get_futex(addr, true);
+
+    mtime_t end = mdate() + delay;
+    lldiv_t d = lldiv(end, CLOCK_FREQ);
+    struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
+
+    while (*ptr == val) {
+        if(pthread_cond_timedwait(&futex->cv, &futex_list_mtx, &ts))
+            break;
+    }
+
+    release_futex(futex);
+    pthread_mutex_unlock(&futex_list_mtx);
+    return !timeout;
+}
-- 
2.11.0



More information about the vlc-devel mailing list