]> git.sesse.net Git - vlc/blob - src/misc/mtime.c
Remove State Threads support
[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 #ifdef HAVE_UNISTD_H
39 #   include <unistd.h>                                           /* select() */
40 #endif
41
42 #ifdef HAVE_KERNEL_OS_H
43 #   include <kernel/OS.h>
44 #endif
45
46 #if defined( WIN32 ) || defined( UNDER_CE )
47 #   include <windows.h>
48 #endif
49 #if defined(HAVE_SYS_TIME_H)
50 #   include <sys/time.h>
51 #endif
52
53 #if !defined(HAVE_STRUCT_TIMESPEC)
54 struct timespec
55 {
56     time_t  tv_sec;
57     int32_t tv_nsec;
58 };
59 #endif
60
61 #if defined(HAVE_NANOSLEEP) && !defined(HAVE_DECL_NANOSLEEP)
62 int nanosleep(struct timespec *, struct timespec *);
63 #endif
64
65 #if !defined (_POSIX_CLOCK_SELECTION)
66 #  define _POSIX_CLOCK_SELECTION (-1)
67 #endif
68
69 # if (_POSIX_CLOCK_SELECTION < 0)
70 /*
71  * We cannot use the monotonic clock is clock selection is not available,
72  * as it would screw vlc_cond_timedwait() completely. Instead, we have to
73  * stick to the realtime clock. Nevermind it screws everything when ntpdate
74  * warps the wall clock.
75  */
76 #  undef CLOCK_MONOTONIC
77 #  define CLOCK_MONOTONIC CLOCK_REALTIME
78 #elif !defined (HAVE_CLOCK_NANOSLEEP)
79 /* Clock selection without clock in the first place, I don't think so. */
80 #  error We have quite a situation here! Fix me if it ever happens.
81 #endif
82
83 /**
84  * Return a date in a readable format
85  *
86  * This function converts a mtime date into a string.
87  * psz_buffer should be a buffer long enough to store the formatted
88  * date.
89  * \param date to be converted
90  * \param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
91  * \return psz_buffer is returned so this can be used as printf parameter.
92  */
93 char *mstrtime( char *psz_buffer, mtime_t date )
94 {
95     static mtime_t ll1000 = 1000, ll60 = 60, ll24 = 24;
96
97     snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%02d:%02d:%02d-%03d.%03d",
98              (int) (date / (ll1000 * ll1000 * ll60 * ll60) % ll24),
99              (int) (date / (ll1000 * ll1000 * ll60) % ll60),
100              (int) (date / (ll1000 * ll1000) % ll60),
101              (int) (date / ll1000 % ll1000),
102              (int) (date % ll1000) );
103     return( psz_buffer );
104 }
105
106 /**
107  * Convert seconds to a time in the format h:mm:ss.
108  *
109  * This function is provided for any interface function which need to print a
110  * time string in the format h:mm:ss
111  * date.
112  * \param secs  the date to be converted
113  * \param psz_buffer should be a buffer at least MSTRTIME_MAX_SIZE characters
114  * \return psz_buffer is returned so this can be used as printf parameter.
115  */
116 char *secstotimestr( char *psz_buffer, int i_seconds )
117 {
118     int i_hours, i_mins;
119     i_mins = i_seconds / 60;
120     i_hours = i_mins / 60 ;
121     if( i_hours )
122     {
123         snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%d:%2.2d:%2.2d",
124                  (int) i_hours,
125                  (int) (i_mins % 60),
126                  (int) (i_seconds % 60) );
127     }
128     else
129     {
130          snprintf( psz_buffer, MSTRTIME_MAX_SIZE, "%2.2d:%2.2d",
131                    (int) i_mins ,
132                    (int) (i_seconds % 60) );
133     }
134     return( psz_buffer );
135 }
136
137 /**
138  * Return a value that is no bigger than the clock precision
139  * (possibly zero).
140  */
141 static inline unsigned mprec( void )
142 {
143 #if defined (HAVE_CLOCK_NANOSLEEP)
144     struct timespec ts;
145     if( clock_getres( CLOCK_MONOTONIC, &ts ))
146         clock_getres( CLOCK_REALTIME, &ts );
147
148     return ts.tv_nsec / 1000;
149 #endif
150     return 0;
151 }
152
153 static unsigned prec = 0;
154 static volatile mtime_t cached_time = 0;
155
156 /**
157  * Return high precision date
158  *
159  * Use a 1 MHz clock when possible, or 1 kHz
160  *
161  * Beware ! It doesn't reflect the actual date (since epoch), but can be the machine's uptime or anything (when monotonic clock is used)
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( WIN32 ) || defined( UNDER_CE )
330     Sleep( (int) (delay / 1000) );
331
332 #elif defined( HAVE_NANOSLEEP )
333     struct timespec ts_delay;
334
335     ts_delay.tv_sec = delay / 1000000;
336     ts_delay.tv_nsec = (delay % 1000000) * 1000;
337
338     while( nanosleep( &ts_delay, &ts_delay ) && ( errno == EINTR ) );
339
340 #else
341     struct timeval tv_delay;
342
343     tv_delay.tv_sec = delay / 1000000;
344     tv_delay.tv_usec = delay % 1000000;
345
346     /* If a signal is caught, you are screwed. Update your OS to nanosleep()
347      * or clock_nanosleep() if this is an issue. */
348     select( 0, NULL, NULL, NULL, &tv_delay );
349 #endif
350
351     earlier += delay;
352     if( cached_time < earlier )
353         cached_time = earlier;
354 }
355
356 /*
357  * Date management (internal and external)
358  */
359
360 /**
361  * Initialize a date_t.
362  *
363  * \param date to initialize
364  * \param divider (sample rate) numerator
365  * \param divider (sample rate) denominator
366  */
367
368 void date_Init( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
369 {
370     p_date->date = 0;
371     p_date->i_divider_num = i_divider_n;
372     p_date->i_divider_den = i_divider_d;
373     p_date->i_remainder = 0;
374 }
375
376 /**
377  * Change a date_t.
378  *
379  * \param date to change
380  * \param divider (sample rate) numerator
381  * \param divider (sample rate) denominator
382  */
383
384 void date_Change( date_t *p_date, uint32_t i_divider_n, uint32_t i_divider_d )
385 {
386     p_date->i_divider_num = i_divider_n;
387     p_date->i_divider_den = i_divider_d;
388 }
389
390 /**
391  * Set the date value of a date_t.
392  *
393  * \param date to set
394  * \param date value
395  */
396 void date_Set( date_t *p_date, mtime_t i_new_date )
397 {
398     p_date->date = i_new_date;
399     p_date->i_remainder = 0;
400 }
401
402 /**
403  * Get the date of a date_t
404  *
405  * \param date to get
406  * \return date value
407  */
408 mtime_t date_Get( const date_t *p_date )
409 {
410     return p_date->date;
411 }
412
413 /**
414  * Move forwards or backwards the date of a date_t.
415  *
416  * \param date to move
417  * \param difference value
418  */
419 void date_Move( date_t *p_date, mtime_t i_difference )
420 {
421     p_date->date += i_difference;
422 }
423
424 /**
425  * Increment the date and return the result, taking into account
426  * rounding errors.
427  *
428  * \param date to increment
429  * \param incrementation in number of samples
430  * \return date value
431  */
432 mtime_t date_Increment( date_t *p_date, uint32_t i_nb_samples )
433 {
434     mtime_t i_dividend = (mtime_t)i_nb_samples * 1000000;
435     p_date->date += i_dividend / p_date->i_divider_num * p_date->i_divider_den;
436     p_date->i_remainder += (int)(i_dividend % p_date->i_divider_num);
437
438     if( p_date->i_remainder >= p_date->i_divider_num )
439     {
440         /* This is Bresenham algorithm. */
441         p_date->date += p_date->i_divider_den;
442         p_date->i_remainder -= p_date->i_divider_num;
443     }
444
445     return p_date->date;
446 }
447
448 #ifndef HAVE_GETTIMEOFDAY
449
450 #ifdef WIN32
451
452 /*
453  * Number of micro-seconds between the beginning of the Windows epoch
454  * (Jan. 1, 1601) and the Unix epoch (Jan. 1, 1970).
455  *
456  * This assumes all Win32 compilers have 64-bit support.
457  */
458 #if defined(_MSC_VER) || defined(_MSC_EXTENSIONS) || defined(__WATCOMC__)
459 #   define DELTA_EPOCH_IN_USEC  11644473600000000Ui64
460 #else
461 #   define DELTA_EPOCH_IN_USEC  11644473600000000ULL
462 #endif
463
464 static uint64_t filetime_to_unix_epoch (const FILETIME *ft)
465 {
466     uint64_t res = (uint64_t) ft->dwHighDateTime << 32;
467
468     res |= ft->dwLowDateTime;
469     res /= 10;                   /* from 100 nano-sec periods to usec */
470     res -= DELTA_EPOCH_IN_USEC;  /* from Win epoch to Unix epoch */
471     return (res);
472 }
473
474 static int gettimeofday (struct timeval *tv, void *tz )
475 {
476     FILETIME  ft;
477     uint64_t tim;
478
479     if (!tv) {
480         return VLC_EGENERIC;
481     }
482     GetSystemTimeAsFileTime (&ft);
483     tim = filetime_to_unix_epoch (&ft);
484     tv->tv_sec  = (long) (tim / 1000000L);
485     tv->tv_usec = (long) (tim % 1000000L);
486     return (0);
487 }
488
489 #endif
490
491 #endif
492
493 /**
494  * @return NTP 64-bits timestamp in host byte order.
495  */
496 uint64_t NTPtime64 (void)
497 {
498     struct timespec ts;
499 #if defined (CLOCK_REALTIME)
500     clock_gettime (CLOCK_REALTIME, &ts);
501 #else
502     {
503         struct timeval tv;
504         gettimeofday (&tv, NULL);
505         ts.tv_sec = tv.tv_sec;
506         ts.tv_nsec = tv.tv_usec * 1000;
507     }
508 #endif
509
510     /* Convert nanoseconds to 32-bits fraction (232 picosecond units) */
511     uint64_t t = (uint64_t)(ts.tv_nsec) << 32;
512     t /= 1000000000;
513
514
515     /* There is 70 years (incl. 17 leap ones) offset to the Unix Epoch.
516      * No leap seconds during that period since they were not invented yet.
517      */
518     assert (t < 0x100000000);
519     t |= ((70LL * 365 + 17) * 24 * 60 * 60 + ts.tv_sec) << 32;
520     return t;
521 }
522