From: RĂ©mi Denis-Courmont Date: Tue, 12 Jul 2011 15:02:54 +0000 (+0300) Subject: Split mdate(), mwait(), msleep() to POSIX and Win32 files X-Git-Tag: 1.2.0-pre1~1801 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=0f9a94f2183fc6c6e9ce8b77eb497aab160cbbbd;p=vlc Split mdate(), mwait(), msleep() to POSIX and Win32 files Also implement correct run-time POSIX clock selection. --- diff --git a/configure.ac b/configure.ac index e567c2598b..c5bf290def 100644 --- a/configure.ac +++ b/configure.ac @@ -566,6 +566,7 @@ dnl Check for system libs needed need_libc=false dnl Check for usual libc functions +AC_CHECK_DECLS([nanosleep],,,[#include ]) AC_CHECK_FUNCS([daemon fcntl fdopendir fstatvfs fork getenv getpwuid_r gettimeofday if_nameindex if_nametoindex isatty lstat memalign mmap openat pread posix_fadvise posix_madvise posix_memalign setlocale stricmp strnicmp uselocale]) AC_REPLACE_FUNCS([asprintf atof atoll dirfd flockfile fsync getdelim getpid gmtime_r lldiv localtime_r nrand48 rewind setenv strcasecmp strcasestr strdup strlcpy strncasecmp strndup strnlen strsep strtof strtok_r strtoll swab tdestroy vasprintf]) AC_CHECK_FUNCS(fdatasync,, @@ -772,23 +773,19 @@ if test "${SYS}" != "mingw32" -a "${SYS}" != "mingwce"; then AC_CHECK_LIB(rt, clock_nanosleep, [ VLC_ADD_LIBS([libvlccore],[-lrt]) - AC_DEFINE(HAVE_CLOCK_NANOSLEEP, 1, [Define to 1 if you have clock_nanosleep.]) ], [ + AC_CHECK_FUNC(nanosleep,,[ + AC_CHECK_LIB(rt,nanosleep, [ + VLC_ADD_LIBS([libvlccore],[-lrt]) + ], [ + AC_CHECK_LIB(posix4,nanosleep, [ + VLC_ADD_LIBS([libvlccore],[-lposix4]) + ]) + ]) + ]) dnl HP/UX port AC_CHECK_LIB(rt,sem_init, [VLC_ADD_LIBS([libvlccore],[-lrt])]) ]) - - have_nanosleep=false - AC_CHECK_FUNCS(nanosleep,have_nanosleep=:,[ - AC_CHECK_LIB(rt,nanosleep, - [VLC_ADD_LIBS([libvlccore],[-lrt]) have_nanosleep=:], - [AC_CHECK_LIB(posix4,nanosleep, - [VLC_ADD_LIBS([libvlccore],[-lposix4]) have_nanosleep=:])] - ) - ]) - if ${have_nanosleep}; then - AC_DEFINE(HAVE_NANOSLEEP, 1, [Define if nanosleep is available.]) - fi fi # end "${SYS}" != "mingw32" -a "${SYS}" != "mingwce" dnl Check for misc headers @@ -834,28 +831,6 @@ then fi ]) -dnl Mac OS X and other OSes don't have declaration for nanosleep -if test "${SYS}" != "mingw32" -a "${SYS}" != "mingwce"; then - AC_MSG_CHECKING(for nanosleep in time.h) - AC_EGREP_HEADER(nanosleep,time.h,[ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_DECL_NANOSLEEP, 1, - Define if defines nanosleep.) - ],[ - AC_MSG_RESULT(no) - ]) -fi # end "${SYS}" != "mingw32" -a "${SYS}" != "mingwce" - -dnl Make sure we have timespecs -AC_MSG_CHECKING(for timespec in sys/time.h) -AC_EGREP_HEADER(timespec,sys/time.h,[ - AC_MSG_RESULT(yes) - AC_DEFINE(HAVE_STRUCT_TIMESPEC, 1, - Define if defines struct timespec.) -],[ - AC_MSG_RESULT(no) -]) - dnl Check for threads library if test "${SYS}" != "mingw32" -a "${SYS}" != "mingwce"; then AC_CHECK_HEADERS(pthread.h) diff --git a/include/vlc_mtime.h b/include/vlc_mtime.h index 46b666a63b..0e623c2074 100644 --- a/include/vlc_mtime.h +++ b/include/vlc_mtime.h @@ -55,68 +55,8 @@ * Prototypes *****************************************************************************/ VLC_API char * mstrtime( char *psz_buffer, mtime_t date ); -VLC_API mtime_t mdate( void ); -VLC_API void mwait( mtime_t date ); -VLC_API void msleep( mtime_t delay ); VLC_API char * secstotimestr( char *psz_buffer, int32_t secs ); -# define VLC_HARD_MIN_SLEEP 10000 /* 10 milliseconds = 1 tick at 100Hz */ - -#if defined (__GNUC__) \ - && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) -/* Linux has 100, 250, 300 or 1000Hz - * - * HZ=100 by default on FreeBSD, but some architectures use a 1000Hz timer - */ -# define VLC_SOFT_MIN_SLEEP 9000000 /* 9 seconds */ - -static -__attribute__((unused)) -__attribute__((noinline)) -__attribute__((error("sorry, cannot sleep for such short a time"))) -mtime_t impossible_delay( mtime_t delay ) -{ - (void) delay; - return VLC_HARD_MIN_SLEEP; -} - -static -__attribute__((unused)) -__attribute__((noinline)) -__attribute__((warning("use proper event handling instead of short delay"))) -mtime_t harmful_delay( mtime_t delay ) -{ - return delay; -} - -# define check_delay( d ) \ - ((__builtin_constant_p(d < VLC_HARD_MIN_SLEEP) \ - && (d < VLC_HARD_MIN_SLEEP)) \ - ? impossible_delay(d) \ - : ((__builtin_constant_p(d < VLC_SOFT_MIN_SLEEP) \ - && (d < VLC_SOFT_MIN_SLEEP)) \ - ? harmful_delay(d) \ - : d)) - -static -__attribute__((unused)) -__attribute__((noinline)) -__attribute__((error("deadlines can not be constant"))) -mtime_t impossible_deadline( mtime_t deadline ) -{ - return deadline; -} - -# define check_deadline( d ) \ - (__builtin_constant_p(d) ? impossible_deadline(d) : d) -#else -# define check_delay(d) (d) -# define check_deadline(d) (d) -#endif - -#define msleep(d) msleep(check_delay(d)) -#define mwait(d) mwait(check_deadline(d)) - /***************************************************************************** * date_t: date incrementation without long-term rounding errors *****************************************************************************/ diff --git a/include/vlc_threads.h b/include/vlc_threads.h index d052f13984..8fa2cf0906 100644 --- a/include/vlc_threads.h +++ b/include/vlc_threads.h @@ -200,6 +200,67 @@ VLC_API void vlc_cancel(vlc_thread_t); VLC_API void vlc_join(vlc_thread_t, void **); VLC_API void vlc_control_cancel (int cmd, ...); +VLC_API mtime_t mdate(void); +VLC_API void mwait(mtime_t deadline); +VLC_API void msleep(mtime_t delay); + +#define VLC_HARD_MIN_SLEEP 10000 /* 10 milliseconds = 1 tick at 100Hz */ +#define VLC_SOFT_MIN_SLEEP 9000000 /* 9 seconds */ + +#if defined (__GNUC__) \ + && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) +/* Linux has 100, 250, 300 or 1000Hz + * + * HZ=100 by default on FreeBSD, but some architectures use a 1000Hz timer + */ + +static +__attribute__((unused)) +__attribute__((noinline)) +__attribute__((error("sorry, cannot sleep for such short a time"))) +mtime_t impossible_delay( mtime_t delay ) +{ + (void) delay; + return VLC_HARD_MIN_SLEEP; +} + +static +__attribute__((unused)) +__attribute__((noinline)) +__attribute__((warning("use proper event handling instead of short delay"))) +mtime_t harmful_delay( mtime_t delay ) +{ + return delay; +} + +# define check_delay( d ) \ + ((__builtin_constant_p(d < VLC_HARD_MIN_SLEEP) \ + && (d < VLC_HARD_MIN_SLEEP)) \ + ? impossible_delay(d) \ + : ((__builtin_constant_p(d < VLC_SOFT_MIN_SLEEP) \ + && (d < VLC_SOFT_MIN_SLEEP)) \ + ? harmful_delay(d) \ + : d)) + +static +__attribute__((unused)) +__attribute__((noinline)) +__attribute__((error("deadlines can not be constant"))) +mtime_t impossible_deadline( mtime_t deadline ) +{ + return deadline; +} + +# define check_deadline( d ) \ + (__builtin_constant_p(d) ? impossible_deadline(d) : d) +#else +# define check_delay(d) (d) +# define check_deadline(d) (d) +#endif + +#define msleep(d) msleep(check_delay(d)) +#define mwait(d) mwait(check_deadline(d)) + VLC_API int vlc_timer_create(vlc_timer_t *, void (*) (void *), void *) VLC_USED; VLC_API void vlc_timer_destroy(vlc_timer_t); VLC_API void vlc_timer_schedule(vlc_timer_t, bool, mtime_t, mtime_t); diff --git a/src/misc/mtime.c b/src/misc/mtime.c index 5f8e7300d6..fc4abdfff6 100644 --- a/src/misc/mtime.c +++ b/src/misc/mtime.c @@ -34,62 +34,16 @@ #endif #include - -#include /* clock_gettime(), clock_nanosleep() */ #include -#include #ifdef HAVE_UNISTD_H -# include /* select() */ -#endif - -#ifdef HAVE_KERNEL_OS_H -# include -#endif - -#if defined( WIN32 ) || defined( UNDER_CE ) -# include -# include -#endif - -#if defined(HAVE_SYS_TIME_H) -# include -#endif - -#if defined(__APPLE__) && !defined(__powerpc__) && !defined(__ppc__) && !defined(__ppc64__) -#define USE_APPLE_MACH 1 -# include -# include -#endif - -#if !defined(HAVE_STRUCT_TIMESPEC) -struct timespec -{ - time_t tv_sec; - int32_t tv_nsec; -}; -#endif - -#if defined(HAVE_NANOSLEEP) && !defined(HAVE_DECL_NANOSLEEP) -int nanosleep(struct timespec *, struct timespec *); -#endif - -#if !defined (_POSIX_CLOCK_SELECTION) -# define _POSIX_CLOCK_SELECTION (-1) +# include #endif - -# if (_POSIX_CLOCK_SELECTION < 0) -/* - * We cannot use the monotonic clock if clock selection is not available, - * as it would screw vlc_cond_timedwait() completely. Instead, we have to - * stick to the realtime clock. Nevermind it screws everything up when ntpdate - * warps the wall clock. - */ -# undef CLOCK_MONOTONIC -# define CLOCK_MONOTONIC CLOCK_REALTIME -#elif !defined (HAVE_CLOCK_NANOSLEEP) -/* Clock selection without clock in the first place, I don't think so. */ -# error We have quite a situation here! Fix me if it ever happens. +#if !defined (_POSIX_TIMERS) +# define _POSIX_TIMERS (-1) +# include +#else +# include /* clock_gettime() */ #endif /** @@ -149,211 +103,6 @@ char *secstotimestr( char *psz_buffer, int32_t i_seconds ) 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) - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once( &once, mprec_once ); - return prec; -#else - return 0; -#endif -} - -#ifdef USE_APPLE_MACH -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 - * - * 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 ) -{ - mtime_t res; - -#if defined (HAVE_CLOCK_NANOSLEEP) - struct timespec ts; - - /* Try to use POSIX monotonic clock if available */ - if( clock_gettime( CLOCK_MONOTONIC, &ts ) == EINVAL ) - /* Run-time fallback to real-time clock (always available) */ - (void)clock_gettime( CLOCK_REALTIME, &ts ); - - res = ((mtime_t)ts.tv_sec * (mtime_t)1000000) - + (mtime_t)(ts.tv_nsec / 1000); - -#elif defined( HAVE_KERNEL_OS_H ) - res = real_time_clock_usecs(); - -#elif defined( USE_APPLE_MACH ) - pthread_once(&mtime_timebase_info_once, mtime_init_timebase); - uint64_t date = mach_absolute_time(); - mach_timebase_info_data_t tb = mtime_timebase_info; - - /* tb.denom is uint32_t, switch to 64 bits to prevent overflow. */ - uint64_t denom = tb.denom; - - /* Switch to microsecs */ - denom *= 1000LL; - - /* Split the division to prevent overflow */ - lldiv_t d = lldiv (tb.numer, denom); - - res = (d.quot * date) + ((d.rem * date) / denom); - -#elif defined( WIN32 ) || defined( UNDER_CE ) - /* We don't need the real date, just the value of a high precision timer */ - LARGE_INTEGER counter, freq; - if (!QueryPerformanceCounter (&counter) - || !QueryPerformanceFrequency (&freq)) - abort(); - - /* Convert to from (1/freq) to microsecond resolution */ - /* We need to split the division to avoid 63-bits overflow */ - lldiv_t d = lldiv (counter.QuadPart, freq.QuadPart); - - res = (d.quot * 1000000) + ((d.rem * 1000000) / freq.QuadPart); - -#else - struct timeval tv_date; - - /* gettimeofday() cannot fail given &tv_date is a valid address */ - (void)gettimeofday( &tv_date, NULL ); - res = (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec; -#endif - - return res; -} - -#undef mwait -/** - * Wait for a date - * - * This function uses select() and an system date function to wake up at a - * precise date. It should be used for process synchronization. If current date - * is posterior to wished date, the function returns immediately. - * \param date The date to wake up at - */ -void mwait( mtime_t date ) -{ - /* If the deadline is already elapsed, or within the clock precision, - * do not even bother the system timer. */ - date -= mprec(); - -#if defined (HAVE_CLOCK_NANOSLEEP) - lldiv_t d = lldiv( date, 1000000 ); - struct timespec ts = { d.quot, d.rem * 1000 }; - - int val; - while( ( val = clock_nanosleep( CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, - NULL ) ) == EINTR ); - if( val == EINVAL ) - { - ts.tv_sec = d.quot; ts.tv_nsec = d.rem * 1000; - while( clock_nanosleep( CLOCK_REALTIME, 0, &ts, NULL ) == EINTR ); - } - -#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 - -/** - * Portable usleep(). Cancellation point. - * - * \param delay the amount of time to sleep - */ -void msleep( mtime_t delay ) -{ -#if defined( HAVE_CLOCK_NANOSLEEP ) - lldiv_t d = lldiv( delay, 1000000 ); - struct timespec ts = { d.quot, d.rem * 1000 }; - - int val; - while( ( val = clock_nanosleep( CLOCK_MONOTONIC, 0, &ts, &ts ) ) == EINTR ); - if( val == EINVAL ) - { - ts.tv_sec = d.quot; ts.tv_nsec = d.rem * 1000; - while( clock_nanosleep( CLOCK_REALTIME, 0, &ts, &ts ) == EINTR ); - } - -#elif defined( HAVE_KERNEL_OS_H ) - snooze( delay ); - -#elif defined( WIN32 ) || defined( UNDER_CE ) - mwait (mdate () + delay); - -#elif defined( HAVE_NANOSLEEP ) - struct timespec ts_delay; - - ts_delay.tv_sec = delay / 1000000; - ts_delay.tv_nsec = (delay % 1000000) * 1000; - - while( nanosleep( &ts_delay, &ts_delay ) && ( errno == EINTR ) ); - -#elif defined (USE_APPLE_MACH) - /* 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; - - tv_delay.tv_sec = delay / 1000000; - tv_delay.tv_usec = delay % 1000000; - - /* If a signal is caught, you are screwed. Update your OS to nanosleep() - * or clock_nanosleep() if this is an issue. */ - select( 0, NULL, NULL, NULL, &tv_delay ); -#endif -} - /* * Date management (internal and external) */ @@ -528,16 +277,21 @@ static int gettimeofday (struct timeval *tv, void *tz ) */ uint64_t NTPtime64 (void) { +#if (_POSIX_TIMERS > 0) struct timespec ts; -#if defined (CLOCK_REALTIME) && !defined (__OS2__) + clock_gettime (CLOCK_REALTIME, &ts); #else + struct timeval tv; + struct { - struct timeval tv; - gettimeofday (&tv, NULL); - ts.tv_sec = tv.tv_sec; - ts.tv_nsec = tv.tv_usec * 1000; - } + uint32_t tv_sec; + uint32_t tv_nsec; + } ts; + + gettimeofday (&tv, NULL); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; #endif /* Convert nanoseconds to 32-bits fraction (232 picosecond units) */ diff --git a/src/posix/thread.c b/src/posix/thread.c index 024d83b6fc..eed0687684 100644 --- a/src/posix/thread.c +++ b/src/posix/thread.c @@ -37,6 +37,7 @@ #include /* fsync() */ #include #include +#include #include #ifdef __linux__ @@ -66,6 +67,74 @@ # include #endif +#if !defined (_POSIX_TIMERS) +# define _POSIX_TIMERS (-1) +#endif +#if !defined (_POSIX_CLOCK_SELECTION) +/* Clock selection was defined in 2001 and became mandatory in 2008. */ +# define _POSIX_CLOCK_SELECTION (-1) +#endif +#if !defined (_POSIX_MONOTONIC_CLOCK) +# define _POSIX_MONOTONIC_CLOCK (-1) +#endif + +#if (_POSIX_TIMERS > 0) +static unsigned vlc_clock_prec; + +# if (_POSIX_CLOCK_SELECTION > 0) +/* POSIX clock selection is needed so that vlc_cond_timewait() is consistent + * with mdate() and mwait(). Otherwise, the monotonic clock cannot be used. + * Fortunately, clock selection has become mandatory as of 2008 so that really + * only broken old systems still lack it. */ + +# if (_POSIX_MONOTONIC_CLOCK > 0) +/* Compile-time POSIX monotonic clock support */ +# define vlc_clock_id (CLOCK_MONOTONIC) + +# elif (_POSIX_MONOTONIC_CLOCK == 0) +/* Run-time POSIX monotonic clock support (see clock_setup() below) */ +static clockid_t vlc_clock_id; + +# else +/* No POSIX monotonic clock support */ +# define vlc_clock_id (CLOCK_REALTIME) +# warning Monotonic clock not available. Expect timing issues. + +# endif /* _POSIX_MONOTONIC_CLOKC */ +# else +/* No POSIX clock selection. */ +# define pthread_condattr_setclock(attr, clock) (attr, clock, 0) +# warning Clock selection not available. Expect timing issues. + +# endif /* _POSIX_CLOCK_SELECTION */ + +static void vlc_clock_setup_once (void) +{ +# if (_POSIX_MONOTONIC_CLOCK == 0) + long val = sysconf (_SC_MONOTONIC_CLOCK); + assert (val != 0); + vlc_clock_id = (val < 0) ? CLOCK_REALTIME : CLOCK_MONOTONIC; +# endif + + struct timespec res; + if (unlikely(clock_getres (vlc_clock_id, &res) != 0 || res.tv_sec != 0)) + abort (); + vlc_clock_prec = (res.tv_nsec + 500) / 1000; +} + +static pthread_once_t vlc_clock_once = PTHREAD_ONCE_INIT; + +# define vlc_clock_setup() \ + pthread_once(&vlc_clock_once, vlc_clock_setup_once) + +#else /* _POSIX_TIMERS */ + +# include /* gettimeofday() */ +# if defined (HAVE_DECL_NANOSLEEP) && !HAVE_DECL_NANOSLEEP +int nanosleep (struct timespec *, struct timespec *); +# endif + +#endif /* _POSIX_TIMERS */ /** * Print a backtrace to the standard error for debugging purpose. @@ -280,16 +349,10 @@ void vlc_cond_init (vlc_cond_t *p_condvar) { pthread_condattr_t attr; + vlc_clock_setup (); if (unlikely(pthread_condattr_init (&attr))) abort (); -#if !defined (_POSIX_CLOCK_SELECTION) - /* Fairly outdated POSIX support (that was defined in 2001) */ -# define _POSIX_CLOCK_SELECTION (-1) -#endif -#if (_POSIX_CLOCK_SELECTION >= 0) - /* NOTE: This must be the same clock as the one in mtime.c */ - pthread_condattr_setclock (&attr, CLOCK_MONOTONIC); -#endif + pthread_condattr_setclock (&attr, vlc_clock_id); if (unlikely(pthread_cond_init (p_condvar, &attr))) abort (); @@ -863,6 +926,89 @@ void vlc_control_cancel (int cmd, ...) assert (0); } +/** + * Precision monotonic clock. + * + * In principles, the clock has a precision of 1 MHz. But the actual resolution + * may be much lower, especially when it comes to sleeping with mwait() or + * msleep(). Most general-purpose operating systems provide a resolution of + * only 100 to 1000 Hz. + * + * @warning The origin date (time value "zero") is not specified. It is + * typically the time the kernel started, but this is platform-dependent. + * If you need wall clock time, use gettimeofday() instead. + * + * @return a timestamp in microseconds. + */ +mtime_t mdate (void) +{ +#if (_POSIX_TIMERS > 0) + struct timespec ts; + + vlc_clock_setup (); + if (unlikely(clock_gettime (vlc_clock_id, &ts) != 0)) + abort (); + + return (INT64_C(1000000) * ts.tv_sec) + (ts.tv_nsec / 1000); + +#else + struct timeval tv; + + if (unlikely(gettimeofday (&tv, NULL) != 0)) + abort (); + return (INT64_C(1000000) * tv.tv_sec) + tv.tv_nsec; + +#endif +} + +#undef mwait +/** + * Waits until a deadline (possibly later due to OS scheduling). + * @param deadline timestamp to wait for (see mdate()) + */ +void mwait (mtime_t deadline) +{ +#if (_POSIX_TIMERS > 0) + vlc_clock_setup (); + /* If the deadline is already elapsed, or within the clock precision, + * do not even bother the system timer. */ + deadline -= vlc_clock_prec; + + lldiv_t d = lldiv (deadline, 1000000); + struct timespec ts = { d.quot, d.rem * 1000 }; + + while (clock_nanosleep (vlc_clock_id, TIMER_ABSTIME, &ts, NULL) == EINTR); + +#else + deadline -= mdate (); + if (deadline > 0) + msleep (deadline); + +#endif +} + +#undef msleep +/** + * Waits for an interval of time. + * @param delay how long to wait (in microseconds) + */ +void msleep (mtime_t delay) +{ + vlc_clock_setup (); + + lldiv_t d = lldiv (delay, 1000000); + struct timespec ts = { d.quot, d.rem * 1000 }; + +#if (_POSIX_TIMERS > 0) + while (clock_nanosleep (vlc_clock_id, 0, &ts, &ts) == EINTR); + +#else + while (nanosleep (&ts, &ts) == -1) + assert (errno == EINTR); + +#endif +} + struct vlc_timer { diff --git a/src/win32/thread.c b/src/win32/thread.c index 9b83f84cc6..360a411f3c 100644 --- a/src/win32/thread.c +++ b/src/win32/thread.c @@ -778,6 +778,45 @@ void vlc_control_cancel (int cmd, ...) } +/*** Clock ***/ +mtime_t mdate (void) +{ + /* We don't need the real date, just the value of a high precision timer */ + LARGE_INTEGER counter, freq; + if (!QueryPerformanceCounter (&counter) + || !QueryPerformanceFrequency (&freq)) + abort(); + + /* Convert to from (1/freq) to microsecond resolution */ + /* We need to split the division to avoid 63-bits overflow */ + lldiv_t d = lldiv (counter.QuadPart, freq.QuadPart); + + return (d.quot * 1000000) + ((d.rem * 1000000) / freq.QuadPart); +} + +#undef mwait +void mwait (mtime_t deadline) +{ + mtime_t delay; + + vlc_testcancel(); + while ((delay = (deadline - mdate())) > 0) + { + delay /= 1000; + if (unlikely(delay > 0x7fffffff)) + delay = 0x7fffffff; + SleepEx (delay, TRUE); + vlc_testcancel(); + } +} + +#undef msleep +void msleep (mtime_t delay) +{ + mwait (mdate () + delay); +} + + /*** Timers ***/ struct vlc_timer {