* Preamble
*****************************************************************************/
-#include <vlc/vlc.h>
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
#include <time.h> /* clock_gettime(), clock_nanosleep() */
#include <assert.h>
#if defined( WIN32 ) || defined( UNDER_CE )
# include <windows.h>
+# include <mmsystem.h>
#endif
+
#if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
#endif
+#ifdef __APPLE__
+# include <mach/mach.h>
+# include <mach/mach_time.h>
+#endif
+
#if !defined(HAVE_STRUCT_TIMESPEC)
struct timespec
{
*/
char *mstrtime( char *psz_buffer, mtime_t date )
{
- static mtime_t ll1000 = 1000, ll60 = 60, ll24 = 24;
+ static const mtime_t ll1000 = 1000, ll60 = 60, ll24 = 24;
snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%02d:%02d:%02d-%03d.%03d",
(int) (date / (ll1000 * ll1000 * ll60 * ll60) % ll24),
return( psz_buffer );
}
+#if defined (HAVE_CLOCK_NANOSLEEP)
+static unsigned prec = 0;
+
+static void mprec_once( void )
+{
+ struct timespec ts;
+ if( clock_getres( CLOCK_MONOTONIC, &ts ))
+ clock_getres( CLOCK_REALTIME, &ts );
+
+ prec = ts.tv_nsec / 1000;
+}
+#endif
+
/**
* Return a value that is no bigger than the clock precision
* (possibly zero).
static inline unsigned mprec( void )
{
#if defined (HAVE_CLOCK_NANOSLEEP)
- struct timespec ts;
- if( clock_getres( CLOCK_MONOTONIC, &ts ))
- clock_getres( CLOCK_REALTIME, &ts );
-
- return ts.tv_nsec / 1000;
-#endif
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once( &once, mprec_once );
+ return prec;
+#else
return 0;
+#endif
}
-static unsigned prec = 0;
-static volatile mtime_t cached_time = 0;
+#ifdef __APPLE__
+static mach_timebase_info_data_t mtime_timebase_info;
+static pthread_once_t mtime_timebase_info_once = PTHREAD_ONCE_INIT;
+static void mtime_init_timebase(void)
+{
+ mach_timebase_info(&mtime_timebase_info);
+}
+#endif
/**
* Return high precision date
#elif defined( HAVE_KERNEL_OS_H )
res = real_time_clock_usecs();
+#elif defined( __APPLE__ )
+ pthread_once(&mtime_timebase_info_once, mtime_init_timebase);
+ uint64_t date = mach_absolute_time();
+
+ /* Convert to nanoseconds */
+ date *= mtime_timebase_info.numer;
+ date /= mtime_timebase_info.denom;
+
+ /* Convert to microseconds */
+ res = date / 1000;
#elif defined( WIN32 ) || defined( UNDER_CE )
/* We don't need the real date, just the value of a high precision timer */
- static mtime_t freq = I64C(-1);
+ static mtime_t freq = INT64_C(-1);
- if( freq == I64C(-1) )
+ if( freq == INT64_C(-1) )
{
/* Extract from the Tcl source code:
* (http://www.cs.man.ac.uk/fellowsd-bin/TIP/7.html)
LARGE_INTEGER buf;
freq = ( QueryPerformanceFrequency( &buf ) &&
- (buf.QuadPart == I64C(1193182) || buf.QuadPart == I64C(3579545) ) )
+ (buf.QuadPart == INT64_C(1193182) || buf.QuadPart == INT64_C(3579545) ) )
? buf.QuadPart : 0;
+
+#if defined( WIN32 )
+ /* on windows 2000, XP and Vista detect if there are two
+ cores there - that makes QueryPerformanceFrequency in
+ any case not trustable?
+ (may also be true, for single cores with adaptive
+ CPU frequency and active power management?)
+ */
+ HINSTANCE h_Kernel32 = LoadLibrary(_T("kernel32.dll"));
+ if(h_Kernel32)
+ {
+ void WINAPI (*pf_GetSystemInfo)(LPSYSTEM_INFO);
+ pf_GetSystemInfo = (void WINAPI (*)(LPSYSTEM_INFO))
+ GetProcAddress(h_Kernel32, _T("GetSystemInfo"));
+ if(pf_GetSystemInfo)
+ {
+ SYSTEM_INFO system_info;
+ pf_GetSystemInfo(&system_info);
+ if(system_info.dwNumberOfProcessors > 1)
+ freq = 0;
+ }
+ FreeLibrary(h_Kernel32);
+ }
+#endif
}
if( freq != 0 )
}
else
{
- /* Fallback on GetTickCount() which has a milisecond resolution
- * (actually, best case is about 10 ms resolution)
- * GetTickCount() only returns a DWORD thus will wrap after
+ /* Fallback on timeGetTime() which has a millisecond resolution
+ * (actually, best case is about 5 ms resolution)
+ * timeGetTime() only returns a DWORD thus will wrap after
* about 49.7 days so we try to detect the wrapping. */
static CRITICAL_SECTION date_lock;
- static mtime_t i_previous_time = I64C(-1);
+ static mtime_t i_previous_time = INT64_C(-1);
static int i_wrap_counts = -1;
if( i_wrap_counts == -1 )
{
/* Initialization */
- i_previous_time = I64C(1000) * GetTickCount();
+#if defined( WIN32 )
+ i_previous_time = INT64_C(1000) * timeGetTime();
+#else
+ i_previous_time = INT64_C(1000) * GetTickCount();
+#endif
InitializeCriticalSection( &date_lock );
i_wrap_counts = 0;
}
EnterCriticalSection( &date_lock );
- res = I64C(1000) *
- (i_wrap_counts * I64C(0x100000000) + GetTickCount());
+#if defined( WIN32 )
+ res = INT64_C(1000) *
+ (i_wrap_counts * INT64_C(0x100000000) + timeGetTime());
+#else
+ res = INT64_C(1000) *
+ (i_wrap_counts * INT64_C(0x100000000) + GetTickCount());
+#endif
if( i_previous_time > res )
{
/* Counter wrapped */
i_wrap_counts++;
- res += I64C(0x100000000) * 1000;
+ res += INT64_C(0x100000000) * 1000;
}
i_previous_time = res;
LeaveCriticalSection( &date_lock );
}
+#elif defined( __APPLE__ ) /* The version that should be used, if it was cancelable */
+ pthread_once(&mtime_timebase_info_once, mtime_init_timebase);
+ uint64_t mach_time = date * 1000 * mtime_timebase_info.denom / mtime_timebase_info.numer;
+ mach_wait_until(mach_time);
+
#else
struct timeval tv_date;
res = (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec;
#endif
- return cached_time = res;
+ return res;
}
+#undef mwait
/**
* Wait for a date
*
*/
void mwait( mtime_t date )
{
- if( prec == 0 )
- prec = mprec();
-
/* If the deadline is already elapsed, or within the clock precision,
- * do not even bother the clock. */
- if( ( date - cached_time ) < (mtime_t)prec ) // OK: mtime_t is signed
- return;
+ * do not even bother the system timer. */
+ date -= mprec();
-#if 0 && defined (HAVE_CLOCK_NANOSLEEP)
+#if defined (HAVE_CLOCK_NANOSLEEP)
lldiv_t d = lldiv( date, 1000000 );
struct timespec ts = { d.quot, d.rem * 1000 };
ts.tv_sec = d.quot; ts.tv_nsec = d.rem * 1000;
while( clock_nanosleep( CLOCK_REALTIME, 0, &ts, NULL ) == EINTR );
}
-#else
+#elif defined (WIN32)
+ mtime_t i_total;
+
+ while( (i_total = (date - mdate())) > 0 )
+ {
+ const mtime_t i_sleep = i_total / 1000;
+ DWORD i_delay = (i_sleep > 0x7fffffff) ? 0x7fffffff : i_sleep;
+ vlc_testcancel();
+ SleepEx( i_delay, TRUE );
+ }
+ vlc_testcancel();
+
+#else
mtime_t delay = date - mdate();
if( delay > 0 )
msleep( delay );
#endif
}
+
+#include "libvlc.h" /* vlc_backtrace() */
+#undef msleep
+
/**
- * More precise sleep()
+ * Portable usleep(). Cancellation point.
*
- * Portable usleep() function.
* \param delay the amount of time to sleep
*/
void msleep( mtime_t delay )
{
- mtime_t earlier = cached_time;
-
#if defined( HAVE_CLOCK_NANOSLEEP )
lldiv_t d = lldiv( delay, 1000000 );
struct timespec ts = { d.quot, d.rem * 1000 };
snooze( delay );
#elif defined( WIN32 ) || defined( UNDER_CE )
- Sleep( (int) (delay / 1000) );
+ mwait (mdate () + delay);
#elif defined( HAVE_NANOSLEEP )
struct timespec ts_delay;
while( nanosleep( &ts_delay, &ts_delay ) && ( errno == EINTR ) );
+#elif defined( __APPLE__ ) /* The version that should be used, if it was cancelable */
+ pthread_once(&mtime_timebase_info_once, mtime_init_timebase);
+ uint64_t mach_time = delay * 1000 * mtime_timebase_info.denom / mtime_timebase_info.numer;
+ mach_wait_until(mach_time + mach_absolute_time());
+
#else
struct timeval tv_delay;
* or clock_nanosleep() if this is an issue. */
select( 0, NULL, NULL, NULL, &tv_delay );
#endif
-
- earlier += delay;
- if( cached_time < earlier )
- cached_time = earlier;
}
/*
void date_Change( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
{
+ /* change time scale of remainder */
+ p_date->i_remainder = p_date->i_remainder * i_divider_n / p_date->i_divider_num;
p_date->i_divider_num = i_divider_n;
p_date->i_divider_den = i_divider_d;
}
*/
mtime_t date_Increment( date_t *p_date, uint32_t i_nb_samples )
{
- mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000;
- p_date->date += i_dividend / p_date->i_divider_num * p_date->i_divider_den;
+ mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000 * p_date->i_divider_den;
+ p_date->date += i_dividend / p_date->i_divider_num;
p_date->i_remainder += (int)(i_dividend % p_date->i_divider_num);
if( p_date->i_remainder >= p_date->i_divider_num )
{
/* This is Bresenham algorithm. */
- p_date->date += p_date->i_divider_den;
+ assert( p_date->i_remainder < 2*p_date->i_divider_num);
+ p_date->date += 1;
p_date->i_remainder -= p_date->i_divider_num;
}