]> git.sesse.net Git - vlc/blobdiff - src/misc/mtime.c
Broadcast when the object is killed
[vlc] / src / misc / mtime.c
index b7beef5ae38d82ce3c93616cecee061881f904d9..37a28f928b9474cd001673b8b32b228f1536d596 100644 (file)
@@ -33,7 +33,7 @@
 # include "config.h"
 #endif
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
 
 #include <time.h>                      /* clock_gettime(), clock_nanosleep() */
 #include <assert.h>
@@ -102,7 +102,7 @@ int nanosleep(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),
@@ -172,8 +172,6 @@ static inline unsigned mprec( void )
 #endif
 }
 
-static volatile mtime_t cached_time = 0;
-
 /**
  * Return high precision date
  *
@@ -267,7 +265,7 @@ mtime_t mdate( void )
     }
     else
     {
-        /* Fallback on timeGetTime() which has a milisecond resolution
+        /* 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. */
@@ -313,9 +311,10 @@ mtime_t mdate( void )
     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
  *
@@ -327,11 +326,10 @@ mtime_t mdate( void )
 void mwait( mtime_t date )
 {
     /* If the deadline is already elapsed, or within the clock precision,
-     * do not even bother the clock. */
-    if( ( date - cached_time ) < (mtime_t)mprec() ) // 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 };
 
@@ -343,8 +341,20 @@ void mwait( mtime_t date )
         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 );
@@ -352,15 +362,37 @@ void mwait( mtime_t date )
 #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;
+#ifndef NDEBUG
+# if defined (__linux__)
+    /* We assume that proper use of msleep() will not use a constant period...
+     * Media synchronization is likely to use mwait() with at least slight
+     * sleep length variation at microsecond precision. Network protocols
+     * normally have exponential backoffs, or long delays. */
+    static __thread unsigned tick_period = 0;
+    static __thread unsigned tick_frequency = 0;
+    if (tick_period != delay)
+        tick_frequency = 0;
+    tick_frequency++;
+    tick_period = delay;
+    if (delay < (29 * CLOCK_FREQ) && tick_frequency == 20)
+    {
+         fprintf (stderr, "Likely bogus delay(%"PRIu64"µs) ", delay);
+         vlc_backtrace ();
+    }
+    //fprintf (stderr, "%u, %u\n", tick_period, tick_frequency);
+# endif
+#endif
 
 #if defined( HAVE_CLOCK_NANOSLEEP )
     lldiv_t d = lldiv( delay, 1000000 );
@@ -378,7 +410,7 @@ void msleep( mtime_t delay )
     snooze( delay );
 
 #elif defined( WIN32 ) || defined( UNDER_CE )
-    Sleep( (DWORD) (delay / 1000) );
+    mwait (mdate () + delay);
 
 #elif defined( HAVE_NANOSLEEP )
     struct timespec ts_delay;
@@ -398,10 +430,6 @@ void msleep( mtime_t 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;
 }
 
 /*
@@ -434,6 +462,8 @@ void date_Init( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
 
 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;
 }
@@ -482,14 +512,15 @@ void date_Move( date_t *p_date, mtime_t i_difference )
  */
 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;
     }