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