]> git.sesse.net Git - vlc/blob - src/misc/mtime.c
Fix stupid logic
[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 #include <vlc/vlc.h>
33
34 #include <time.h>                      /* clock_gettime(), clock_nanosleep() */
35 #include <assert.h>
36 #include <errno.h>
37
38
39 #if defined( PTH_INIT_IN_PTH_H )                                  /* GNU Pth */
40 #   include <pth.h>
41 #endif
42
43 #ifdef HAVE_UNISTD_H
44 #   include <unistd.h>                                           /* select() */
45 #endif
46
47 #ifdef HAVE_KERNEL_OS_H
48 #   include <kernel/OS.h>
49 #endif
50
51 #if defined( WIN32 ) || defined( UNDER_CE )
52 #   include <windows.h>
53 #endif
54 #if defined(HAVE_SYS_TIME_H)
55 #   include <sys/time.h>
56 #endif
57
58 #if !defined(HAVE_STRUCT_TIMESPEC)
59 struct timespec
60 {
61     time_t  tv_sec;
62     int32_t tv_nsec;
63 };
64 #endif
65
66 #if defined(HAVE_NANOSLEEP) && !defined(HAVE_DECL_NANOSLEEP)
67 int nanosleep(struct timespec *, struct timespec *);
68 #endif
69
70 #if (!defined (_POSIX_CLOCK_SELECTION)) || (_POSIX_CLOCK_SELECTION < 0)
71 /*
72  * We cannot use the monotonic clock is clock selection is not available,
73  * as it would screw vlc_cond_timedwait() completely. Instead, we have to
74  * stick to the realtime clock. Nevermind it screws everything when ntpdate
75  * warps the wall clock.
76  */
77 #  undef CLOCK_MONOTONIC
78 #  define CLOCK_MONOTONIC CLOCK_REALTIME
79 #elif !defined (HAVE_CLOCK_NANOSLEEP)
80 /* Clock selection without clock in the first place, I don't think so. */
81 #  error We have quite a situation here! Fix me if it ever happens.
82 #endif
83
84 /**
85  * Return a date in a readable format
86  *
87  * This function converts a mtime date into a string.
88  * psz_buffer should be a buffer long enough to store the formatted
89  * date.
90  * \param date to be converted
91  * \param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
92  * \return psz_buffer is returned so this can be used as printf parameter.
93  */
94 char *mstrtime( char *psz_buffer, mtime_t date )
95 {
96     static mtime_t ll1000 = 1000, ll60 = 60, ll24 = 24;
97
98     snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%02d:%02d:%02d-%03d.%03d",
99              (int) (date / (ll1000 * ll1000 * ll60 * ll60) % ll24),
100              (int) (date / (ll1000 * ll1000 * ll60) % ll60),
101              (int) (date / (ll1000 * ll1000) % ll60),
102              (int) (date / ll1000 % ll1000),
103              (int) (date % ll1000) );
104     return( psz_buffer );
105 }
106
107 /**
108  * Convert seconds to a time in the format h:mm:ss.
109  *
110  * This function is provided for any interface function which need to print a
111  * time string in the format h:mm:ss
112  * date.
113  * \param secs  the date to be converted
114  * \param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
115  * \return psz_buffer is returned so this can be used as printf parameter.
116  */
117 char *secstotimestr( char *psz_buffer, int i_seconds )
118 {
119     int i_hours, i_mins;
120     i_mins = i_seconds / 60;
121     i_hours = i_mins / 60 ;
122     if( i_hours )
123     {
124         snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%d:%2.2d:%2.2d",
125                  (int) i_hours,
126                  (int) (i_mins % 60),
127                  (int) (i_seconds % 60) );
128     }
129     else
130     {
131          snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%2.2d:%2.2d",
132                    (int) i_mins ,
133                    (int) (i_seconds % 60) );
134     }
135     return( psz_buffer );
136 }
137
138 /**
139  * Return a value that is no bigger than the clock precision
140  * (possibly zero).
141  */
142 static inline unsigned mprec( void )
143 {
144 #if defined (HAVE_CLOCK_NANOSLEEP)
145     struct timespec ts;
146     if( clock_getres( CLOCK_MONOTONIC, &ts ))
147         clock_getres( CLOCK_REALTIME, &ts );
148
149     return ts.tv_nsec / 1000;
150 #endif
151     return 0;
152 }
153
154 static unsigned prec = 0;
155 static volatile mtime_t cached_time = 0;
156
157 /**
158  * Return high precision date
159  *
160  * Uses the gettimeofday() function when possible (1 MHz resolution) or the
161  * ftime() function (1 kHz resolution).
162  */
163 mtime_t mdate( void )
164 {
165     mtime_t res;
166
167 #if defined (HAVE_CLOCK_NANOSLEEP)
168     struct timespec ts;
169
170     /* Try to use POSIX monotonic clock if available */
171     if( clock_gettime( CLOCK_MONOTONIC, &ts ) == EINVAL )
172         /* Run-time fallback to real-time clock (always available) */
173         (void)clock_gettime( CLOCK_REALTIME, &ts );
174
175     res = ((mtime_t)ts.tv_sec * (mtime_t)1000000)
176            + (mtime_t)(ts.tv_nsec / 1000);
177
178 #elif defined( HAVE_KERNEL_OS_H )
179     res = real_time_clock_usecs();
180
181 #elif defined( WIN32 ) || defined( UNDER_CE )
182     /* We don't need the real date, just the value of a high precision timer */
183     static mtime_t freq = I64C(-1);
184
185     if( freq == I64C(-1) )
186     {
187         /* Extract from the Tcl source code:
188          * (http://www.cs.man.ac.uk/fellowsd-bin/TIP/7.html)
189          *
190          * Some hardware abstraction layers use the CPU clock
191          * in place of the real-time clock as a performance counter
192          * reference.  This results in:
193          *    - inconsistent results among the processors on
194          *      multi-processor systems.
195          *    - unpredictable changes in performance counter frequency
196          *      on "gearshift" processors such as Transmeta and
197          *      SpeedStep.
198          * There seems to be no way to test whether the performance
199          * counter is reliable, but a useful heuristic is that
200          * if its frequency is 1.193182 MHz or 3.579545 MHz, it's
201          * derived from a colorburst crystal and is therefore
202          * the RTC rather than the TSC.  If it's anything else, we
203          * presume that the performance counter is unreliable.
204          */
205         LARGE_INTEGER buf;
206
207         freq = ( QueryPerformanceFrequency( &buf ) &&
208                  (buf.QuadPart == I64C(1193182) || buf.QuadPart == I64C(3579545) ) )
209                ? buf.QuadPart : 0;
210     }
211
212     if( freq != 0 )
213     {
214         LARGE_INTEGER counter;
215         QueryPerformanceCounter (&counter);
216
217         /* Convert to from (1/freq) to microsecond resolution */
218         /* We need to split the division to avoid 63-bits overflow */
219         lldiv_t d = lldiv (counter.QuadPart, freq);
220
221         res = (d.quot * 1000000) + ((d.rem * 1000000) / freq);
222     }
223     else
224     {
225         /* Fallback on GetTickCount() which has a milisecond resolution
226          * (actually, best case is about 10 ms resolution)
227          * GetTickCount() only returns a DWORD thus will wrap after
228          * about 49.7 days so we try to detect the wrapping. */
229
230         static CRITICAL_SECTION date_lock;
231         static mtime_t i_previous_time = I64C(-1);
232         static int i_wrap_counts = -1;
233
234         if( i_wrap_counts == -1 )
235         {
236             /* Initialization */
237             i_previous_time = I64C(1000) * GetTickCount();
238             InitializeCriticalSection( &date_lock );
239             i_wrap_counts = 0;
240         }
241
242         EnterCriticalSection( &date_lock );
243         res = I64C(1000) *
244             (i_wrap_counts * I64C(0x100000000) + GetTickCount());
245         if( i_previous_time > res )
246         {
247             /* Counter wrapped */
248             i_wrap_counts++;
249             res += I64C(0x100000000) * 1000;
250         }
251         i_previous_time = res;
252         LeaveCriticalSection( &date_lock );
253     }
254 #else
255     struct timeval tv_date;
256
257     /* gettimeofday() cannot fail given &tv_date is a valid address */
258     (void)gettimeofday( &tv_date, NULL );
259     res = (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec;
260 #endif
261
262     return cached_time = res;
263 }
264
265 /**
266  * Wait for a date
267  *
268  * This function uses select() and an system date function to wake up at a
269  * precise date. It should be used for process synchronization. If current date
270  * is posterior to wished date, the function returns immediately.
271  * \param date The date to wake up at
272  */
273 void mwait( mtime_t date )
274 {
275     if( prec == 0 )
276         prec = mprec();
277
278     /* If the deadline is already elapsed, or within the clock precision,
279      * do not even bother the clock. */
280     if( ( date - cached_time ) < (mtime_t)prec ) // OK: mtime_t is signed
281         return;
282
283 #if 0 && defined (HAVE_CLOCK_NANOSLEEP)
284     lldiv_t d = lldiv( date, 1000000 );
285     struct timespec ts = { d.quot, d.rem * 1000 };
286
287     int val;
288     while( ( val = clock_nanosleep( CLOCK_MONOTONIC, TIMER_ABSTIME, &ts,
289                                     NULL ) ) == EINTR );
290     if( val == EINVAL )
291     {
292         ts.tv_sec = d.quot; ts.tv_nsec = d.rem * 1000;
293         while( clock_nanosleep( CLOCK_REALTIME, 0, &ts, NULL ) == EINTR );
294     }
295 #else
296
297     mtime_t delay = date - mdate();
298     if( delay > 0 )
299         msleep( delay );
300
301 #endif
302 }
303
304 /**
305  * More precise sleep()
306  *
307  * Portable usleep() function.
308  * \param delay the amount of time to sleep
309  */
310 void msleep( mtime_t delay )
311 {
312     mtime_t earlier = cached_time;
313
314 #if defined( HAVE_CLOCK_NANOSLEEP )
315     lldiv_t d = lldiv( delay, 1000000 );
316     struct timespec ts = { d.quot, d.rem * 1000 };
317
318     int val;
319     while( ( val = clock_nanosleep( CLOCK_MONOTONIC, 0, &ts, &ts ) ) == EINTR );
320     if( val == EINVAL )
321     {
322         ts.tv_sec = d.quot; ts.tv_nsec = d.rem * 1000;
323         while( clock_nanosleep( CLOCK_REALTIME, 0, &ts, &ts ) == EINTR );
324     }
325
326 #elif defined( HAVE_KERNEL_OS_H )
327     snooze( delay );
328
329 #elif defined( PTH_INIT_IN_PTH_H )
330     pth_usleep( delay );
331
332 #elif defined( ST_INIT_IN_ST_H )
333     st_usleep( delay );
334
335 #elif defined( WIN32 ) || defined( UNDER_CE )
336     Sleep( (int) (delay / 1000) );
337
338 #elif defined( HAVE_NANOSLEEP )
339     struct timespec ts_delay;
340
341     ts_delay.tv_sec = delay / 1000000;
342     ts_delay.tv_nsec = (delay % 1000000) * 1000;
343
344     while( nanosleep( &ts_delay, &ts_delay ) && ( errno == EINTR ) );
345
346 #else
347     struct timeval tv_delay;
348
349     tv_delay.tv_sec = delay / 1000000;
350     tv_delay.tv_usec = delay % 1000000;
351
352     /* If a signal is caught, you are screwed. Update your OS to nanosleep()
353      * or clock_nanosleep() if this is an issue. */
354     select( 0, NULL, NULL, NULL, &tv_delay );
355 #endif
356
357     earlier += delay;
358     if( cached_time < earlier )
359         cached_time = earlier;
360 }
361
362 /*
363  * Date management (internal and external)
364  */
365
366 /**
367  * Initialize a date_t.
368  *
369  * \param date to initialize
370  * \param divider (sample rate) numerator
371  * \param divider (sample rate) denominator
372  */
373
374 void date_Init( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
375 {
376     p_date->date = 0;
377     p_date->i_divider_num = i_divider_n;
378     p_date->i_divider_den = i_divider_d;
379     p_date->i_remainder = 0;
380 }
381
382 /**
383  * Change a date_t.
384  *
385  * \param date to change
386  * \param divider (sample rate) numerator
387  * \param divider (sample rate) denominator
388  */
389
390 void date_Change( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
391 {
392     p_date->i_divider_num = i_divider_n;
393     p_date->i_divider_den = i_divider_d;
394 }
395
396 /**
397  * Set the date value of a date_t.
398  *
399  * \param date to set
400  * \param date value
401  */
402 void date_Set( date_t *p_date, mtime_t i_new_date )
403 {
404     p_date->date = i_new_date;
405     p_date->i_remainder = 0;
406 }
407
408 /**
409  * Get the date of a date_t
410  *
411  * \param date to get
412  * \return date value
413  */
414 mtime_t date_Get( const date_t *p_date )
415 {
416     return p_date->date;
417 }
418
419 /**
420  * Move forwards or backwards the date of a date_t.
421  *
422  * \param date to move
423  * \param difference value
424  */
425 void date_Move( date_t *p_date, mtime_t i_difference )
426 {
427     p_date->date += i_difference;
428 }
429
430 /**
431  * Increment the date and return the result, taking into account
432  * rounding errors.
433  *
434  * \param date to increment
435  * \param incrementation in number of samples
436  * \return date value
437  */
438 mtime_t date_Increment( date_t *p_date, uint32_t i_nb_samples )
439 {
440     mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000;
441     p_date->date += i_dividend / p_date->i_divider_num * p_date->i_divider_den;
442     p_date->i_remainder += (int)(i_dividend % p_date->i_divider_num);
443
444     if( p_date->i_remainder >= p_date->i_divider_num )
445     {
446         /* This is Bresenham algorithm. */
447         p_date->date += p_date->i_divider_den;
448         p_date->i_remainder -= p_date->i_divider_num;
449     }
450
451     return p_date->date;
452 }
453
454 #ifndef HAVE_GETTIMEOFDAY
455
456 #ifdef WIN32
457
458 /*
459  * Number of micro-seconds between the beginning of the Windows epoch
460  * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970).
461  *
462  * This assumes all Win32 compilers have 64-bit support.
463  */
464 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__)
465 #   define DELTA_EPOCH_IN_USEC  11644473600000000Ui64
466 #else
467 #   define DELTA_EPOCH_IN_USEC  11644473600000000ULL
468 #endif
469
470 static uint64_t filetime_to_unix_epoch (const FILETIME *ft)
471 {
472     uint64_t res = (uint64_t) ft->dwHighDateTime << 32;
473
474     res |= ft->dwLowDateTime;
475     res /= 10;                   /* from 100 nano-sec periods to usec */
476     res -= DELTA_EPOCH_IN_USEC;  /* from Win epoch to Unix epoch */
477     return (res);
478 }
479
480 static int gettimeofday (struct timeval *tv, void *tz )
481 {
482     FILETIME  ft;
483     uint64_t tim;
484
485     if (!tv) {
486         return VLC_EGENERIC;
487     }
488     GetSystemTimeAsFileTime (&ft);
489     tim = filetime_to_unix_epoch (&ft);
490     tv->tv_sec  = (long) (tim / 1000000L);
491     tv->tv_usec = (long) (tim % 1000000L);
492     return (0);
493 }
494
495 #endif
496
497 #endif
498
499 /**
500  * @return NTP 64-bits timestamp in host byte order.
501  */
502 uint64_t NTPtime64 (void)
503 {
504     struct timespec ts;
505 #if defined (CLOCK_REALTIME)
506     clock_gettime (CLOCK_REALTIME, &ts);
507 #else
508     {
509         struct timeval tv;
510         gettimeofday (&tv, NULL);
511         ts.tv_sec = tv.tv_sec;
512         ts.tv_nsec = tv.tv_usec * 1000;
513     }
514 #endif
515
516     /* Convert nanoseconds to 32-bits fraction (232 picosecond units) */
517     uint64_t t = (uint64_t)(ts.tv_nsec) << 32;
518     t /= 1000000000;
519
520
521     /* There is 70 years (incl. 17 leap ones) offset to the Unix Epoch.
522      * No leap seconds during that period since they were not invented yet.
523      */
524     assert (t < 0x100000000);
525     t |= ((70LL * 365 + 17) * 24 * 60 * 60 + ts.tv_sec) << 32;
526     return t;
527 }
528