[vlc-commits] linux: add wait-on-address/futex functions

Rémi Denis-Courmont git at videolan.org
Fri May 27 23:43:03 CEST 2016


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed May 25 23:10:32 2016 +0300| [16f049a0ffb00a25fb9f6f686b34f4a0d28c15e9] | committer: Rémi Denis-Courmont

linux: add wait-on-address/futex functions

This only provides the Linux back-end. Those functions are not exported
since they are not universally available (and not meant to be used by
plugins at this point).

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=16f049a0ffb00a25fb9f6f686b34f4a0d28c15e9
---

 include/vlc_threads.h |   53 ++++++++++++++++++++++++++++++++++++++++++++++++-
 src/linux/thread.c    |   52 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index e82c2bb..5733aeb 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -3,7 +3,7 @@
  * This header provides portable declarations for mutexes & conditions
  *****************************************************************************
  * Copyright (C) 1999, 2002 VLC authors and VideoLAN
- * Copyright © 2007-2008 Rémi Denis-Courmont
+ * Copyright © 2007-2016 Rémi Denis-Courmont
  *
  * Authors: Jean-Marc Dressler <polux at via.ecp.fr>
  *          Samuel Hocevar <sam at via.ecp.fr>
@@ -600,6 +600,57 @@ VLC_API int vlc_threadvar_set(vlc_threadvar_t key, void *value);
 VLC_API void *vlc_threadvar_get(vlc_threadvar_t);
 
 /**
+ * Waits on an address.
+ *
+ * Puts the calling thread to sleep if a specific value is stored at a
+ * specified address. If the value does not match, do nothing and return
+ * immediately.
+ *
+ * \param addr address to check for
+ * \param val value to match at the address
+ */
+void vlc_addr_wait(void *addr, int val);
+
+/**
+ * Waits on an address with a time-out.
+ *
+ * This function operates as vlc_addr_wait() but provides an additional
+ * time-out. If the time-out elapses, the thread resumes and the function
+ * returns.
+ *
+ * \param addr address to check for
+ * \param val value to match at the address
+ * \param delay time-out duration
+ *
+ * \return true if the function was woken up before the time-out,
+ * false if the time-out elapsed.
+ */
+bool vlc_addr_timedwait(void *addr, int val, mtime_t delay);
+
+/**
+ * Wakes up one thread on an address.
+ *
+ * Wakes up (at least) one of the thread sleeping on the specified address.
+ * The address must be equal to the first parameter given by at least one
+ * thread sleeping within the vlc_addr_wait() or vlc_addr_timedwait()
+ * functions. If no threads are found, this function does nothing.
+ *
+ * \param addr address identifying which threads may be woken up
+ */
+void vlc_addr_signal(void *addr);
+
+/**
+ * Wakes up all thread on an address.
+ *
+ * Wakes up all threads sleeping on the specified address (if any).
+ * Any thread sleeping within a call to vlc_addr_wait() or vlc_addr_timedwait()
+ * with the specified address as first call parameter will be woken up.
+ *
+ * \param addr address identifying which threads to wake up
+ */
+void vlc_addr_broadcast(void *addr);
+
+/**
  * Creates and starts a new thread.
  *
  * The thread must be <i>joined</i> with vlc_join() to reclaim resources
diff --git a/src/linux/thread.c b/src/linux/thread.c
index f9acb87..617bd5f 100644
--- a/src/linux/thread.c
+++ b/src/linux/thread.c
@@ -22,11 +22,20 @@
 # include "config.h"
 #endif
 
-#include <vlc_common.h>
-
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
 #include <sys/types.h>
 #include <unistd.h>
 #include <sys/syscall.h>
+#include <linux/futex.h>
+
+#ifndef FUTEX_PRIVATE_FLAG
+#define FUTEX_WAKE_PRIVATE FUTEX_WAKE
+#define FUTEX_WAIT_PRIVATE FUTEX_WAIT
+#endif
+
+#include <vlc_common.h>
 
 unsigned long vlc_thread_id(void)
 {
@@ -37,3 +46,42 @@ unsigned long vlc_thread_id(void)
 
      return tid;
 }
+
+static int sys_futex(void *addr, int op, int val, const struct timespec *to,
+                     void *addr2, int val3)
+{
+    return syscall(SYS_futex, addr, op, val, to, addr2, val3);
+}
+
+static int vlc_futex_wake(void *addr, int nr)
+{
+    return sys_futex(addr, FUTEX_WAKE_PRIVATE, nr, NULL, NULL, 0);
+}
+
+static int vlc_futex_wait(void *addr, int val, const struct timespec *to)
+{
+    return sys_futex(addr, FUTEX_WAIT_PRIVATE, val, to, NULL, 0);
+}
+
+void vlc_addr_signal(void *addr)
+{
+    vlc_futex_wake(addr, 1);
+}
+
+void vlc_addr_broadcast(void *addr)
+{
+    vlc_futex_wake(addr, INT_MAX);
+}
+
+void vlc_addr_wait(void *addr, int val)
+{
+    vlc_futex_wait(addr, val, NULL);
+}
+
+bool vlc_addr_timedwait(void *addr, int val, mtime_t delay)
+{
+    lldiv_t d = lldiv(delay, CLOCK_FREQ);
+    struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
+
+    return (vlc_futex_wait(addr, val, &ts) == 0 || errno != ETIMEDOUT);
+}



More information about the vlc-commits mailing list