]> git.sesse.net Git - vlc/blob - src/misc/mtime.c
mtime: Minimize imprecision and prevent overflow on darwin.
[vlc] / src / misc / mtime.c
1 /*****************************************************************************
2  * mtime.c: high resolution time management functions
3  * Functions are prototyped in vlc_mtime.h.
4  *****************************************************************************
5  * Copyright (C) 1998-2007 the VideoLAN team
6  * Copyright © 2006-2007 Rémi Denis-Courmont
7  * $Id$
8  *
9  * Authors: Vincent Seguin <seguin@via.ecp.fr>
10  *          Rémi Denis-Courmont <rem$videolan,org>
11  *          Gisle Vanem
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2 of the License, or
16  * (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
26  *****************************************************************************/
27
28 /*****************************************************************************
29  * Preamble
30  *****************************************************************************/
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <vlc_common.h>
37
38 #include <time.h>                      /* clock_gettime(), clock_nanosleep() */
39 #include <assert.h>
40 #include <errno.h>
41
42 #ifdef HAVE_UNISTD_H
43 #   include <unistd.h>                                           /* select() */
44 #endif
45
46 #ifdef HAVE_KERNEL_OS_H
47 #   include <kernel/OS.h>
48 #endif
49
50 #if defined( WIN32 ) || defined( UNDER_CE )
51 #   include <windows.h>
52 #   include <mmsystem.h>
53 #endif
54
55 #if defined(HAVE_SYS_TIME_H)
56 #   include <sys/time.h>
57 #endif
58
59 #if defined(__APPLE__) && !defined(__powerpc__) && !defined(__ppc__) && !defined(__ppc64__)
60 #define USE_APPLE_MACH 1
61 #   include <mach/mach.h>
62 #   include <mach/mach_time.h>
63 #endif
64
65 #if !defined(HAVE_STRUCT_TIMESPEC)
66 struct timespec
67 {
68     time_t  tv_sec;
69     int32_t tv_nsec;
70 };
71 #endif
72
73 #if defined(HAVE_NANOSLEEP) && !defined(HAVE_DECL_NANOSLEEP)
74 int nanosleep(struct timespec *, struct timespec *);
75 #endif
76
77 #if !defined (_POSIX_CLOCK_SELECTION)
78 #  define _POSIX_CLOCK_SELECTION (-1)
79 #endif
80
81 # if (_POSIX_CLOCK_SELECTION < 0)
82 /*
83  * We cannot use the monotonic clock if clock selection is not available,
84  * as it would screw vlc_cond_timedwait() completely. Instead, we have to
85  * stick to the realtime clock. Nevermind it screws everything up when ntpdate
86  * warps the wall clock.
87  */
88 #  undef CLOCK_MONOTONIC
89 #  define CLOCK_MONOTONIC CLOCK_REALTIME
90 #elif !defined (HAVE_CLOCK_NANOSLEEP)
91 /* Clock selection without clock in the first place, I don't think so. */
92 #  error We have quite a situation here! Fix me if it ever happens.
93 #endif
94
95 /**
96  * Return a date in a readable format
97  *
98  * This function converts a mtime date into a string.
99  * psz_buffer should be a buffer long enough to store the formatted
100  * date.
101  * \param date to be converted
102  * \param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
103  * \return psz_buffer is returned so this can be used as printf parameter.
104  */
105 char *mstrtime( char *psz_buffer, mtime_t date )
106 {
107     static const mtime_t ll1000 = 1000, ll60 = 60, ll24 = 24;
108
109     snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%02d:%02d:%02d-%03d.%03d",
110              (int) (date / (ll1000 * ll1000 * ll60 * ll60) % ll24),
111              (int) (date / (ll1000 * ll1000 * ll60) % ll60),
112              (int) (date / (ll1000 * ll1000) % ll60),
113              (int) (date / ll1000 % ll1000),
114              (int) (date % ll1000) );
115     return( psz_buffer );
116 }
117
118 /**
119  * Convert seconds to a time in the format h:mm:ss.
120  *
121  * This function is provided for any interface function which need to print a
122  * time string in the format h:mm:ss
123  * date.
124  * \param secs  the date to be converted
125  * \param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
126  * \return psz_buffer is returned so this can be used as printf parameter.
127  */
128 char *secstotimestr( char *psz_buffer, int32_t i_seconds )
129 {
130     if( unlikely(i_seconds < 0) )
131     {
132         secstotimestr( psz_buffer + 1, -i_seconds );
133         *psz_buffer = '-';
134         return psz_buffer;
135     }
136
137     div_t d;
138
139     d = div( i_seconds, 60 );
140     i_seconds = d.rem;
141     d = div( d.quot, 60 );
142
143     if( d.quot )
144         snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%u:%02u:%02u",
145                  d.quot, d.rem, i_seconds );
146     else
147         snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%02u:%02u",
148                   d.rem, i_seconds );
149     return psz_buffer;
150 }
151
152 #if defined (HAVE_CLOCK_NANOSLEEP)
153 static unsigned prec = 0;
154
155 static void mprec_once( void )
156 {
157     struct timespec ts;
158     if( clock_getres( CLOCK_MONOTONIC, &ts ))
159         clock_getres( CLOCK_REALTIME, &ts );
160
161     prec = ts.tv_nsec / 1000;
162 }
163 #endif
164
165 /**
166  * Return a value that is no bigger than the clock precision
167  * (possibly zero).
168  */
169 static inline unsigned mprec( void )
170 {
171 #if defined (HAVE_CLOCK_NANOSLEEP)
172     static pthread_once_t once = PTHREAD_ONCE_INIT;
173     pthread_once( &once, mprec_once );
174     return prec;
175 #else
176     return 0;
177 #endif
178 }
179
180 #ifdef USE_APPLE_MACH
181 static mach_timebase_info_data_t mtime_timebase_info;
182 static pthread_once_t mtime_timebase_info_once = PTHREAD_ONCE_INIT;
183 static void mtime_init_timebase(void)
184 {
185     mach_timebase_info(&mtime_timebase_info);
186 }
187 #endif
188
189 /**
190  * Return high precision date
191  *
192  * Use a 1 MHz clock when possible, or 1 kHz
193  *
194  * Beware ! It doesn't reflect the actual date (since epoch), but can be the machine's uptime or anything (when monotonic clock is used)
195  */
196 mtime_t mdate( void )
197 {
198     mtime_t res;
199
200 #if defined (HAVE_CLOCK_NANOSLEEP)
201     struct timespec ts;
202
203     /* Try to use POSIX monotonic clock if available */
204     if( clock_gettime( CLOCK_MONOTONIC, &ts ) == EINVAL )
205         /* Run-time fallback to real-time clock (always available) */
206         (void)clock_gettime( CLOCK_REALTIME, &ts );
207
208     res = ((mtime_t)ts.tv_sec * (mtime_t)1000000)
209            + (mtime_t)(ts.tv_nsec / 1000);
210
211 #elif defined( HAVE_KERNEL_OS_H )
212     res = real_time_clock_usecs();
213
214 #elif defined( USE_APPLE_MACH )
215     pthread_once(&mtime_timebase_info_once, mtime_init_timebase);
216     uint64_t date = mach_absolute_time();
217     mach_timebase_info_data_t tb = mtime_timebase_info;
218
219     /* tb.denom is uint32_t, switch to 64 bits to prevent overflow. */
220     uint64_t denom = tb.denom;
221
222     /* Switch to microsecs */
223     denom *= 1000LL;
224
225     /* Split the division to prevent overflow */
226     lldiv_t d = lldiv (tb.numer, denom);
227
228     res = (d.quot * date) + ((d.rem * date) / denom);
229
230 #elif defined( WIN32 ) || defined( UNDER_CE )
231     /* We don't need the real date, just the value of a high precision timer */
232     LARGE_INTEGER counter, freq;
233     if (!QueryPerformanceCounter (&counter)
234      || !QueryPerformanceFrequency (&freq))
235         abort();
236
237     /* Convert to from (1/freq) to microsecond resolution */
238     /* We need to split the division to avoid 63-bits overflow */
239     lldiv_t d = lldiv (counter.QuadPart, freq.QuadPart);
240
241     res = (d.quot * 1000000) + ((d.rem * 1000000) / freq.QuadPart);
242
243 #else
244     struct timeval tv_date;
245
246     /* gettimeofday() cannot fail given &tv_date is a valid address */
247     (void)gettimeofday( &tv_date, NULL );
248     res = (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec;
249 #endif
250
251     return res;
252 }
253
254 #undef mwait
255 /**
256  * Wait for a date
257  *
258  * This function uses select() and an system date function to wake up at a
259  * precise date. It should be used for process synchronization. If current date
260  * is posterior to wished date, the function returns immediately.
261  * \param date The date to wake up at
262  */
263 void mwait( mtime_t date )
264 {
265     /* If the deadline is already elapsed, or within the clock precision,
266      * do not even bother the system timer. */
267     date -= mprec();
268
269 #if defined (HAVE_CLOCK_NANOSLEEP)
270     lldiv_t d = lldiv( date, 1000000 );
271     struct timespec ts = { d.quot, d.rem * 1000 };
272
273     int val;
274     while( ( val = clock_nanosleep( CLOCK_MONOTONIC, TIMER_ABSTIME, &ts,
275                                     NULL ) ) == EINTR );
276     if( val == EINVAL )
277     {
278         ts.tv_sec = d.quot; ts.tv_nsec = d.rem * 1000;
279         while( clock_nanosleep( CLOCK_REALTIME, 0, &ts, NULL ) == EINTR );
280     }
281
282 #elif defined (WIN32)
283     mtime_t i_total;
284
285     while( (i_total = (date - mdate())) > 0 )
286     {
287         const mtime_t i_sleep = i_total / 1000;
288         DWORD i_delay = (i_sleep > 0x7fffffff) ? 0x7fffffff : i_sleep;
289         vlc_testcancel();
290         SleepEx( i_delay, TRUE );
291     }
292     vlc_testcancel();
293
294 #else
295     mtime_t delay = date - mdate();
296     if( delay > 0 )
297         msleep( delay );
298
299 #endif
300 }
301
302
303 #include "libvlc.h" /* vlc_backtrace() */
304 #undef msleep
305
306 /**
307  * Portable usleep(). Cancellation point.
308  *
309  * \param delay the amount of time to sleep
310  */
311 void msleep( mtime_t delay )
312 {
313 #if defined( HAVE_CLOCK_NANOSLEEP )
314     lldiv_t d = lldiv( delay, 1000000 );
315     struct timespec ts = { d.quot, d.rem * 1000 };
316
317     int val;
318     while( ( val = clock_nanosleep( CLOCK_MONOTONIC, 0, &ts, &ts ) ) == EINTR );
319     if( val == EINVAL )
320     {
321         ts.tv_sec = d.quot; ts.tv_nsec = d.rem * 1000;
322         while( clock_nanosleep( CLOCK_REALTIME, 0, &ts, &ts ) == EINTR );
323     }
324
325 #elif defined( HAVE_KERNEL_OS_H )
326     snooze( delay );
327
328 #elif defined( WIN32 ) || defined( UNDER_CE )
329     mwait (mdate () + delay);
330
331 #elif defined( HAVE_NANOSLEEP )
332     struct timespec ts_delay;
333
334     ts_delay.tv_sec = delay / 1000000;
335     ts_delay.tv_nsec = (delay % 1000000) * 1000;
336
337     while( nanosleep( &ts_delay, &ts_delay ) && ( errno == EINTR ) );
338
339 #elif defined (USE_APPLE_MACH)
340     /* The version that should be used, if it was cancelable */
341     pthread_once(&mtime_timebase_info_once, mtime_init_timebase);
342     uint64_t mach_time = delay * 1000 * mtime_timebase_info.denom / mtime_timebase_info.numer;
343     mach_wait_until(mach_time + mach_absolute_time());
344
345 #else
346     struct timeval tv_delay;
347
348     tv_delay.tv_sec = delay / 1000000;
349     tv_delay.tv_usec = delay % 1000000;
350
351     /* If a signal is caught, you are screwed. Update your OS to nanosleep()
352      * or clock_nanosleep() if this is an issue. */
353     select( 0, NULL, NULL, NULL, &tv_delay );
354 #endif
355 }
356
357 /*
358  * Date management (internal and external)
359  */
360
361 /**
362  * Initialize a date_t.
363  *
364  * \param date to initialize
365  * \param divider (sample rate) numerator
366  * \param divider (sample rate) denominator
367  */
368
369 void date_Init( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
370 {
371     p_date->date = 0;
372     p_date->i_divider_num = i_divider_n;
373     p_date->i_divider_den = i_divider_d;
374     p_date->i_remainder = 0;
375 }
376
377 /**
378  * Change a date_t.
379  *
380  * \param date to change
381  * \param divider (sample rate) numerator
382  * \param divider (sample rate) denominator
383  */
384
385 void date_Change( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
386 {
387     /* change time scale of remainder */
388     p_date->i_remainder = p_date->i_remainder * i_divider_n / p_date->i_divider_num;
389     p_date->i_divider_num = i_divider_n;
390     p_date->i_divider_den = i_divider_d;
391 }
392
393 /**
394  * Set the date value of a date_t.
395  *
396  * \param date to set
397  * \param date value
398  */
399 void date_Set( date_t *p_date, mtime_t i_new_date )
400 {
401     p_date->date = i_new_date;
402     p_date->i_remainder = 0;
403 }
404
405 /**
406  * Get the date of a date_t
407  *
408  * \param date to get
409  * \return date value
410  */
411 mtime_t date_Get( const date_t *p_date )
412 {
413     return p_date->date;
414 }
415
416 /**
417  * Move forwards or backwards the date of a date_t.
418  *
419  * \param date to move
420  * \param difference value
421  */
422 void date_Move( date_t *p_date, mtime_t i_difference )
423 {
424     p_date->date += i_difference;
425 }
426
427 /**
428  * Increment the date and return the result, taking into account
429  * rounding errors.
430  *
431  * \param date to increment
432  * \param incrementation in number of samples
433  * \return date value
434  */
435 mtime_t date_Increment( date_t *p_date, uint32_t i_nb_samples )
436 {
437     mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000 * p_date->i_divider_den;
438     p_date->date += i_dividend / p_date->i_divider_num;
439     p_date->i_remainder += (int)(i_dividend % p_date->i_divider_num);
440
441     if( p_date->i_remainder >= p_date->i_divider_num )
442     {
443         /* This is Bresenham algorithm. */
444         assert( p_date->i_remainder < 2*p_date->i_divider_num);
445         p_date->date += 1;
446         p_date->i_remainder -= p_date->i_divider_num;
447     }
448
449     return p_date->date;
450 }
451
452 /**
453  * Decrement the date and return the result, taking into account
454  * rounding errors.
455  *
456  * \param date to decrement
457  * \param decrementation in number of samples
458  * \return date value
459  */
460 mtime_t date_Decrement( date_t *p_date, uint32_t i_nb_samples )
461 {
462     mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000 * p_date->i_divider_den;
463     p_date->date -= i_dividend / p_date->i_divider_num;
464     unsigned i_rem_adjust = i_dividend % p_date->i_divider_num;
465
466     if( p_date->i_remainder < i_rem_adjust )
467     {
468         /* This is Bresenham algorithm. */
469         assert( p_date->i_remainder > -p_date->i_divider_num);
470         p_date->date -= 1;
471         p_date->i_remainder += p_date->i_divider_num;
472     }
473
474     p_date->i_remainder -= i_rem_adjust;
475
476     return p_date->date;
477 }
478
479 #ifndef HAVE_GETTIMEOFDAY
480
481 #ifdef WIN32
482
483 /*
484  * Number of micro-seconds between the beginning of the Windows epoch
485  * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970).
486  *
487  * This assumes all Win32 compilers have 64-bit support.
488  */
489 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__)
490 #   define DELTA_EPOCH_IN_USEC  11644473600000000Ui64
491 #else
492 #   define DELTA_EPOCH_IN_USEC  11644473600000000ULL
493 #endif
494
495 static uint64_t filetime_to_unix_epoch (const FILETIME *ft)
496 {
497     uint64_t res = (uint64_t) ft->dwHighDateTime << 32;
498
499     res |= ft->dwLowDateTime;
500     res /= 10;                   /* from 100 nano-sec periods to usec */
501     res -= DELTA_EPOCH_IN_USEC;  /* from Win epoch to Unix epoch */
502     return (res);
503 }
504
505 static int gettimeofday (struct timeval *tv, void *tz )
506 {
507     FILETIME  ft;
508     uint64_t tim;
509
510     if (!tv) {
511         return VLC_EGENERIC;
512     }
513     GetSystemTimeAsFileTime (&ft);
514     tim = filetime_to_unix_epoch (&ft);
515     tv->tv_sec  = (long) (tim / 1000000L);
516     tv->tv_usec = (long) (tim % 1000000L);
517     return (0);
518 }
519
520 #endif
521
522 #endif
523
524 /**
525  * @return NTP 64-bits timestamp in host byte order.
526  */
527 uint64_t NTPtime64 (void)
528 {
529     struct timespec ts;
530 #if defined (CLOCK_REALTIME)
531     clock_gettime (CLOCK_REALTIME, &ts);
532 #else
533     {
534         struct timeval tv;
535         gettimeofday (&tv, NULL);
536         ts.tv_sec = tv.tv_sec;
537         ts.tv_nsec = tv.tv_usec * 1000;
538     }
539 #endif
540
541     /* Convert nanoseconds to 32-bits fraction (232 picosecond units) */
542     uint64_t t = (uint64_t)(ts.tv_nsec) << 32;
543     t /= 1000000000;
544
545
546     /* There is 70 years (incl. 17 leap ones) offset to the Unix Epoch.
547      * No leap seconds during that period since they were not invented yet.
548      */
549     assert (t < 0x100000000);
550     t |= ((70LL * 365 + 17) * 24 * 60 * 60 + ts.tv_sec) << 32;
551     return t;
552 }
553