X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmisc%2Fmtime.c;h=1d2ae6b9477059e0c1b6364cb73bf98a1d37c26f;hb=a08221745a28e350736f1ca68b6034074ed3f2e1;hp=9b27f39cc024de857b7041b2f4bae69d808ef0ca;hpb=1d5f5602ded3f1119abc593fb8066182a157bdcb;p=vlc diff --git a/src/misc/mtime.c b/src/misc/mtime.c index 9b27f39cc0..1d2ae6b947 100644 --- a/src/misc/mtime.c +++ b/src/misc/mtime.c @@ -1,52 +1,115 @@ -/****************************************************************************** +/***************************************************************************** * mtime.c: high rezolution time management functions - * (c)1998 VideoLAN - ****************************************************************************** * Functions are prototyped in mtime.h. - ****************************************************************************** - * to-do list: + ***************************************************************************** + * Copyright (C) 1998-2001 VideoLAN + * $Id: mtime.c,v 1.33 2002/07/12 21:57:25 massiot Exp $ + * + * Authors: Vincent Seguin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/* + * TODO: * see if using Linux real-time extensions is possible and profitable - ******************************************************************************/ + */ -/****************************************************************************** +/***************************************************************************** * Preamble - ******************************************************************************/ -#include -#include + *****************************************************************************/ +#include /* sprintf() */ + +#include + +#if defined( PTH_INIT_IN_PTH_H ) /* GNU Pth */ +# include +#endif + +#ifdef HAVE_UNISTD_H +# include /* select() */ +#endif -#include "common.h" -#include "mtime.h" +#ifdef HAVE_KERNEL_OS_H +# include +#endif + +#if defined( WIN32 ) +# include +#else +# include +#endif + +#if defined(HAVE_NANOSLEEP) && !defined(HAVE_STRUCT_TIMESPEC) +struct timespec +{ + time_t tv_sec; + int32_t tv_nsec; +}; +#endif -/****************************************************************************** +#if defined(HAVE_NANOSLEEP) && !defined(HAVE_DECL_NANOSLEEP) +int nanosleep(struct timespec *, struct timespec *); +#endif + +/***************************************************************************** * mstrtime: return a date in a readable format - ****************************************************************************** + ***************************************************************************** * This functions is provided for any interface function which need to print a * date. psz_buffer should be a buffer long enough to store the formatted * date. - ******************************************************************************/ + *****************************************************************************/ char *mstrtime( char *psz_buffer, mtime_t date ) { sprintf( psz_buffer, "%02d:%02d:%02d-%03d.%03d", - (int) (date / (1000LL * 1000LL * 60LL * 60LL) % 24LL), - (int) (date / (1000LL * 1000LL * 60LL) % 60LL), - (int) (date / (1000LL * 1000LL) % 60LL), - (int) (date / 1000LL % 1000LL), - (int) (date % 1000LL) ); + (int) (date / (I64C(1000) * I64C(1000) * I64C(60) * I64C(60)) % I64C(24)), + (int) (date / (I64C(1000) * I64C(1000) * I64C(60)) % I64C(60)), + (int) (date / (I64C(1000) * I64C(1000)) % I64C(60)), + (int) (date / I64C(1000) % I64C(1000)), + (int) (date % I64C(1000)) ); return( psz_buffer ); } -/****************************************************************************** - * mdate: return high precision date (inline function) - ****************************************************************************** +/***************************************************************************** + * mdate: return high precision date + ***************************************************************************** * Uses the gettimeofday() function when possible (1 MHz resolution) or the * ftime() function (1 kHz resolution). - ****************************************************************************** - * to-do list: ?? - * implement the function when gettimeofday is not available - * this function should be decalred as inline - ******************************************************************************/ + *****************************************************************************/ mtime_t mdate( void ) { +#if defined( HAVE_KERNEL_OS_H ) + return( real_time_clock_usecs() ); + +#elif defined( WIN32 ) + /* We don't get the real date, just the value of a high precision timer. + * this is because the usual time functions have at best only a milisecond + * resolution */ + mtime_t freq, usec_time; + + if( QueryPerformanceFrequency( (LARGE_INTEGER *)&freq ) ) + { + /* Microsecond resolution */ + QueryPerformanceCounter( (LARGE_INTEGER *)&usec_time ); + return ( usec_time * 1000000 ) / freq; + } + + /* Milisecond resolution */ + return 1000 * GetTickCount(); + +#else struct timeval tv_date; /* gettimeofday() could return an error, and should be tested. However, the @@ -54,59 +117,128 @@ mtime_t mdate( void ) * here, since tv is a local variable. */ gettimeofday( &tv_date, NULL ); return( (mtime_t) tv_date.tv_sec * 1000000 + (mtime_t) tv_date.tv_usec ); + +#endif } -/****************************************************************************** - * mwait: wait for a date (inline function) - ****************************************************************************** +/***************************************************************************** + * mwait: wait for a date + ***************************************************************************** * This function uses select() and an system date function to wake up at a * precise date. It should be used for process synchronization. If current date * is posterior to wished date, the function returns immediately. - ****************************************************************************** - * to-do list: - * implement the function when gettimeofday is not available - * optimize delay calculation - * ?? declare as inline - ******************************************************************************/ + *****************************************************************************/ void mwait( mtime_t date ) { - struct timeval tv_date, tv_delay; - mtime_t delay; /* delay in msec, signed to detect errors */ +#if defined( HAVE_KERNEL_OS_H ) + mtime_t delay; + + delay = date - real_time_clock_usecs(); + if( delay <= 0 ) + { + return; + } + snooze( delay ); + +#elif defined( WIN32 ) + mtime_t usec_time, delay; + + usec_time = mdate(); + delay = date - usec_time; + if( delay <= 0 ) + { + return; + } + msleep( delay ); + +#else + + struct timeval tv_date; + mtime_t delay; /* delay in msec, signed to detect errors */ /* see mdate() about gettimeofday() possible errors */ gettimeofday( &tv_date, NULL ); /* calculate delay and check if current date is before wished date */ - delay = date - (mtime_t) tv_date.tv_sec * 1000000 - (mtime_t) tv_date.tv_usec; - if( delay <= 0 ) /* wished date is now or already passed */ + delay = date - (mtime_t) tv_date.tv_sec * 1000000 + - (mtime_t) tv_date.tv_usec + - 10000; + + /* Linux/i386 has a granularity of 10 ms. It's better to be in advance + * than to be late. */ + if( delay <= 0 ) /* wished date is now or already passed */ { return; } - tv_delay.tv_sec = delay / 1000000; - tv_delay.tv_usec = delay % 1000000; +# if defined( PTH_INIT_IN_PTH_H ) + pth_usleep( delay ); + +# elif defined( ST_INIT_IN_ST_H ) + st_usleep( delay ); + +# else + +# if defined( HAVE_NANOSLEEP ) + { + struct timespec ts_delay; + ts_delay.tv_sec = delay / 1000000; + ts_delay.tv_nsec = (delay % 1000000) * 1000; + + nanosleep( &ts_delay, NULL ); + } + +# else + tv_date.tv_sec = delay / 1000000; + tv_date.tv_usec = delay % 1000000; /* see msleep() about select() errors */ - select( 0, NULL, NULL, NULL, &tv_delay ); + select( 0, NULL, NULL, NULL, &tv_date ); +# endif + +# endif + +#endif } -/****************************************************************************** - * msleep: more precise sleep() (inline function) (ok ?) - ****************************************************************************** - * This function uses select() in a classical way to implement a sleep() call - * with a microsecond precision. - * For synchronization purposes, mwait() should be prefered. - ****************************************************************************** - * ?? decalre as inline - ******************************************************************************/ +/***************************************************************************** + * msleep: more precise sleep() + ***************************************************************************** + * Portable usleep() function. + *****************************************************************************/ void msleep( mtime_t delay ) { +#if defined( HAVE_KERNEL_OS_H ) + snooze( delay ); + +#elif defined( PTH_INIT_IN_PTH_H ) + pth_usleep( delay ); + +#elif defined( ST_INIT_IN_ST_H ) + st_usleep( delay ); + +#elif defined( WIN32 ) + Sleep( (int) (delay / 1000) ); + +#elif defined( HAVE_NANOSLEEP ) + struct timespec ts_delay; + + ts_delay.tv_sec = delay / 1000000; + ts_delay.tv_nsec = (delay % 1000000) * 1000; + + nanosleep( &ts_delay, NULL ); + +#else struct timeval tv_delay; tv_delay.tv_sec = delay / 1000000; tv_delay.tv_usec = delay % 1000000; + /* select() return value should be tested, since several possible errors * can occur. However, they should only happen in very particular occasions * (i.e. when a signal is sent to the thread, or when memory is full), and - * can be ingnored. */ + * can be ignored. */ select( 0, NULL, NULL, NULL, &tv_delay ); + +#endif } +