mtime.c 7.13 KB
Newer Older
1
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
2 3
 * mtime.c: high rezolution time management functions
 * Functions are prototyped in mtime.h.
4
 *****************************************************************************
5
 * Copyright (C) 1998, 1999, 2000 VideoLAN
Sam Hocevar's avatar
 
Sam Hocevar committed
6
 * $Id: mtime.c,v 1.19 2001/05/31 01:37:08 sam Exp $
7
 *
8
 * Authors: Vincent Seguin <seguin@via.ecp.fr>
9 10 11 12 13
 *
 * 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.
14
 * 
15 16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20 21 22
 * 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.
23
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
24

25 26 27 28 29
/*
 * TODO:
 *  see if using Linux real-time extensions is possible and profitable
 */

30
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
31
 * Preamble
32
 *****************************************************************************/
33 34
#include "defs.h"

35
#include <stdio.h>                                              /* sprintf() */
Sam Hocevar's avatar
 
Sam Hocevar committed
36 37

#ifdef HAVE_UNISTD_H
38
#include <unistd.h>                                              /* select() */
Sam Hocevar's avatar
 
Sam Hocevar committed
39 40 41
#endif

#if !defined( _MSC_VER )
Michel Kaempf's avatar
Michel Kaempf committed
42
#include <sys/time.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
43
#endif
Michel Kaempf's avatar
Michel Kaempf committed
44

45
#ifdef HAVE_KERNEL_OS_H
46 47 48
#include <kernel/OS.h>
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
49
#if defined( WIN32 )
Sam Hocevar's avatar
 
Sam Hocevar committed
50 51 52
#include <windows.h>
#endif

53
#include "config.h"
Michel Kaempf's avatar
Michel Kaempf committed
54 55 56
#include "common.h"
#include "mtime.h"

57
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
58
 * mstrtime: return a date in a readable format
59
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
60 61
 * 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
Michel Kaempf's avatar
Michel Kaempf committed
62
 * date.
63
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
64 65
char *mstrtime( char *psz_buffer, mtime_t date )
{
Michel Kaempf's avatar
Michel Kaempf committed
66
    sprintf( psz_buffer, "%02d:%02d:%02d-%03d.%03d",
Sam Hocevar's avatar
 
Sam Hocevar committed
67 68 69 70 71
             (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)) );
Michel Kaempf's avatar
Michel Kaempf committed
72 73 74
    return( psz_buffer );
}

75
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
76
 * mdate: return high precision date (inline function)
77
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
78 79
 * Uses the gettimeofday() function when possible (1 MHz resolution) or the
 * ftime() function (1 kHz resolution).
80
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
81
mtime_t mdate( void )
Michel Kaempf's avatar
Michel Kaempf committed
82
{
Sam Hocevar's avatar
 
Sam Hocevar committed
83
#if defined( HAVE_KERNEL_OS_H )
84
    return( real_time_clock_usecs() );
Sam Hocevar's avatar
 
Sam Hocevar committed
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102

#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) )
    {
        /* Milisecond resolution */
        FILETIME file_time;
        GetSystemTimeAsFileTime((FILETIME *)&file_time);
        usec_time *= 1000;
    }
    else
    {
        /* Microsecond resolution */
        QueryPerformanceCounter((LARGE_INTEGER *)&usec_time);
Sam Hocevar's avatar
 
Sam Hocevar committed
103
        usec_time /= (freq/1000000);
Sam Hocevar's avatar
 
Sam Hocevar committed
104 105 106
    }
    return( usec_time );

107
#else
Michel Kaempf's avatar
Michel Kaempf committed
108 109 110 111 112 113 114
    struct timeval tv_date;

    /* gettimeofday() could return an error, and should be tested. However, the
     * only possible error, according to 'man', is EFAULT, which can not happen
     * 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 );
Sam Hocevar's avatar
 
Sam Hocevar committed
115

116
#endif
Michel Kaempf's avatar
Michel Kaempf committed
117 118
}

119
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
120
 * mwait: wait for a date (inline function)
121
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
122 123 124
 * 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.
125
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
126 127
void mwait( mtime_t date )
{
Sam Hocevar's avatar
 
Sam Hocevar committed
128
#if defined( HAVE_KERNEL_OS_H )
129 130 131 132 133 134 135 136 137
    mtime_t delay;
    
    delay = date - real_time_clock_usecs();
    if( delay <= 0 )
    {
        return;
    }
    snooze( delay );

Sam Hocevar's avatar
 
Sam Hocevar committed
138 139 140 141 142 143 144 145 146 147 148
#elif defined( WIN32 )
    mtime_t usec_time, delay;

    usec_time = mdate();
    delay = date - usec_time;
    if( delay <= 0 )
    {
        return;
    }
    /* Sleep only has milisecond resolution */
    Sleep( (DWORD)(delay/1000) );
149 150 151

#else

Sam Hocevar's avatar
 
Sam Hocevar committed
152 153 154 155 156
#   ifdef HAVE_USLEEP
    struct timeval tv_date;
#   else
    struct timeval tv_date, tv_delay;
#   endif
157
    mtime_t        delay;          /* delay in msec, signed to detect errors */
Michel Kaempf's avatar
Michel Kaempf committed
158 159 160 161 162

    /* see mdate() about gettimeofday() possible errors */
    gettimeofday( &tv_date, NULL );

    /* calculate delay and check if current date is before wished date */
163 164 165
    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. */
166
    if( delay <= 0 )                 /* wished date is now or already passed */
Michel Kaempf's avatar
Michel Kaempf committed
167 168 169
    {
        return;
    }
170

Sam Hocevar's avatar
 
Sam Hocevar committed
171
#   ifdef HAVE_USLEEP
172
    usleep( delay );
Sam Hocevar's avatar
 
Sam Hocevar committed
173
#   else
Michel Kaempf's avatar
Michel Kaempf committed
174
    tv_delay.tv_sec = delay / 1000000;
Michel Kaempf's avatar
Michel Kaempf committed
175 176
    tv_delay.tv_usec = delay % 1000000;

Michel Kaempf's avatar
Michel Kaempf committed
177 178
    /* see msleep() about select() errors */
    select( 0, NULL, NULL, NULL, &tv_delay );
Sam Hocevar's avatar
 
Sam Hocevar committed
179
#   endif
180

Sam Hocevar's avatar
 
Sam Hocevar committed
181
#endif
Michel Kaempf's avatar
Michel Kaempf committed
182 183
}

184
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
185
 * msleep: more precise sleep() (inline function)                        (ok ?)
186
 *****************************************************************************
187
 * Portable usleep() function.
188
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
189 190
void msleep( mtime_t delay )
{
Sam Hocevar's avatar
 
Sam Hocevar committed
191
#if defined( HAVE_KERNEL_OS_H )
192 193
    snooze( delay );

Sam Hocevar's avatar
 
Sam Hocevar committed
194 195 196 197 198 199
#elif defined( WIN32 )
    Sleep( delay/1000 );             /* Sleep only has milisecond resolution */
  /* Maybe we could use the multimedia timer to reach the right resolution,  */
  /* or the old Winsock select() function ?*/

#elif defined( HAVE_USLEEP )
200
    usleep( delay );
Sam Hocevar's avatar
 
Sam Hocevar committed
201

202
#else
Michel Kaempf's avatar
Michel Kaempf committed
203 204 205 206 207 208 209 210 211
    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. */
    select( 0, NULL, NULL, NULL, &tv_delay );
212

Sam Hocevar's avatar
 
Sam Hocevar committed
213
#endif
Michel Kaempf's avatar
Michel Kaempf committed
214
}
Sam Hocevar's avatar
 
Sam Hocevar committed
215