* 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>
#include <errno.h>
-
-#if defined( PTH_INIT_IN_PTH_H ) /* GNU Pth */
-# include <pth.h>
-#endif
-
#ifdef HAVE_UNISTD_H
# include <unistd.h> /* select() */
#endif
#if defined( WIN32 ) || defined( UNDER_CE )
# include <windows.h>
+# include <mmsystem.h>
#endif
+
#if defined(HAVE_SYS_TIME_H)
# include <sys/time.h>
#endif
int nanosleep(struct timespec *, struct timespec *);
#endif
-#if (!defined (_POSIX_CLOCK_SELECTION)) || (_POSIX_CLOCK_SELECTION < 0)
+#if !defined (_POSIX_CLOCK_SELECTION)
+# define _POSIX_CLOCK_SELECTION (-1)
+#endif
+
+# if (_POSIX_CLOCK_SELECTION < 0)
/*
* We cannot use the monotonic clock is clock selection is not available,
* as it would screw vlc_cond_timedwait() completely. Instead, we have to
*/
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;
-
/**
* Return high precision date
*
- * Uses the gettimeofday() function when possible (1 MHz resolution) or the
- * ftime() function (1 kHz resolution).
+ * Use a 1 MHz clock when possible, or 1 kHz
+ *
+ * Beware ! It doesn't reflect the actual date (since epoch), but can be the machine's uptime or anything (when monotonic clock is used)
*/
mtime_t mdate( void )
{
#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 );
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();
+
+#elif defined( __APPLE__ )
+ /* Explicit hack: OSX does not cancel at nanosleep() */
+ vlc_mutex_t lock;
+ vlc_cond_t wait;
+
+ vlc_mutex_init (&lock);
+ vlc_cond_init (&wait);
+ vlc_mutex_lock (&lock);
+
+ vlc_cleanup_push (vlc_mutex_destroy, &lock);
+ vlc_cleanup_push (vlc_cond_destroy, &wait);
+ vlc_cleanup_push (vlc_mutex_unlock, &lock);
+
+ vlc_cond_timedwait (&wait, &lock, date);
+
+ vlc_cleanup_run ();
+ vlc_cleanup_run ();
+ vlc_cleanup_run ();
+
+#else
mtime_t delay = date - mdate();
if( delay > 0 )
msleep( delay );
#endif
}
+
+#include "libvlc.h" /* vlc_backtrace() */
+#undef msleep
+
+#if defined(__APPLE__) && defined( HAVE_NANOSLEEP )
+/* Mac OS X 10.5's nanosleep is not a cancellation point */
+static inline int
+semi_testcancelable_nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
+{
+ int ret;
+ pthread_testcancel();
+ ret = nanosleep(rqtp, rmtp);
+ pthread_testcancel();
+ return ret;
+}
+#define nanosleep semi_testcancelable_nanosleep
+#endif
+
/**
- * 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 };
#elif defined( HAVE_KERNEL_OS_H )
snooze( delay );
-#elif defined( PTH_INIT_IN_PTH_H )
- pth_usleep( delay );
-
-#elif defined( ST_INIT_IN_ST_H )
- st_usleep( delay );
-
-#elif defined( WIN32 ) || defined( UNDER_CE )
- Sleep( (int) (delay / 1000) );
+#elif defined( WIN32 ) || defined( UNDER_CE ) || defined( __APPLE__ )
+ mwait (mdate () + delay);
#elif defined( HAVE_NANOSLEEP )
struct timespec ts_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;
}