[vlc-devel] [PATCH] src: darwin/thread: reimplement monotonic clock for darwin

david.fuhrmann at gmail.com david.fuhrmann at gmail.com
Tue Dec 31 11:47:46 CET 2013


From: David Fuhrmann <david.fuhrmann at googlemail.com>

This is based on code which was silently removed in
0f9a94f2183fc6c6e9ce8b77eb497aab160cbbbd and
45c2bc0811cc2d9fe8e11448a05742d7ff6da1d8.
---
 src/darwin/thread.c | 47 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 10 deletions(-)

diff --git a/src/darwin/thread.c b/src/darwin/thread.c
index b69e7f9..2ada136 100644
--- a/src/darwin/thread.c
+++ b/src/darwin/thread.c
@@ -39,11 +39,21 @@
 
 #include <pthread.h>
 #include <mach/mach_init.h> /* mach_task_self in semaphores */
+#include <mach/mach_time.h>
 #include <execinfo.h>
-#include <sys/time.h> /* gettimeofday() */
 
-#define vlc_clock_setup() (void)0
-#warning Monotonic clock not available. Expect timing issues.
+static mach_timebase_info_data_t vlc_clock_conversion_factor;
+
+static void vlc_clock_setup_once (void)
+{
+    if (unlikely(mach_timebase_info (&vlc_clock_conversion_factor) != 0))
+        abort ();
+}
+
+static pthread_once_t vlc_clock_once = PTHREAD_ONCE_INIT;
+
+#define vlc_clock_setup() \
+    pthread_once(&vlc_clock_once, vlc_clock_setup_once)
 
 static struct timespec mtime_to_ts (mtime_t date)
 {
@@ -332,8 +342,16 @@ 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)
 {
-    struct timespec ts = mtime_to_ts (deadline);
-    int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts);
+    /* mdate() is the monotonic clock, timedwait origin is gettimeofday() which
+     * isn't monotonic. Use timedwait_relative_np() instead
+     */
+    mtime_t base = mdate();
+    deadline -= base;
+    if (deadline < 0)
+        deadline = 0;
+    struct timespec ts = mtime_to_ts(deadline);
+
+    int val = pthread_cond_timedwait_relative_np(p_condvar, p_mutex, &ts);
     if (val != ETIMEDOUT)
         VLC_THREAD_ASSERT ("timed-waiting on condition");
     return val;
@@ -698,11 +716,19 @@ void vlc_control_cancel (int cmd, ...)
  * returns a timestamp in microseconds. */
 mtime_t mdate (void)
 {
-    struct timeval tv;
+    vlc_clock_setup();
+    uint64_t date = mach_absolute_time();
 
-    if (unlikely(gettimeofday (&tv, NULL) != 0))
-        abort ();
-    return (INT64_C(1000000) * tv.tv_sec) + tv.tv_usec;
+    /* denom is uint32_t, switch to 64 bits to prevent overflow. */
+    uint64_t denom = vlc_clock_conversion_factor.denom;
+
+    /* Switch to microsecs */
+    denom *= 1000LL;
+
+    /* Split the division to prevent overflow */
+    lldiv_t d = lldiv (vlc_clock_conversion_factor.numer, denom);
+
+    return (d.quot * date) + ((d.rem * date) / denom);
 }
 
 #undef mwait
@@ -722,11 +748,12 @@ void msleep (mtime_t delay)
 {
     struct timespec ts = mtime_to_ts (delay);
 
+    /* nanosleep uses mach_absolute_time and mach_wait_until internally,
+       but also handles kernel errors. Thus we use just this. */
     while (nanosleep (&ts, &ts) == -1)
         assert (errno == EINTR);
 }
 
-
 /* Count CPUs.
  * returns the number of available (logical) CPUs. */
 unsigned vlc_GetCPUCount(void)
-- 
1.8.3.4 (Apple Git-47)




More information about the vlc-devel mailing list