[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