mtime.c 7.2 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 6
 * Copyright (C) 1998-2001 VideoLAN
 * $Id: mtime.c,v 1.25 2001/11/28 15:08:06 massiot 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

Sam Hocevar's avatar
 
Sam Hocevar committed
37 38 39 40
#if defined( PTH_INIT_IN_PTH_H )                                  /* GNU Pth */
#   include <pth.h>
#endif

Sam Hocevar's avatar
 
Sam Hocevar committed
41
#ifdef HAVE_UNISTD_H
Sam Hocevar's avatar
 
Sam Hocevar committed
42
#   include <unistd.h>                                           /* select() */
Sam Hocevar's avatar
 
Sam Hocevar committed
43
#endif
Michel Kaempf's avatar
Michel Kaempf committed
44

45
#ifdef HAVE_KERNEL_OS_H
Sam Hocevar's avatar
 
Sam Hocevar committed
46
#   include <kernel/OS.h>
47 48
#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>
#else
#   include <sys/time.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
53 54
#endif

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

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

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

#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 */
Sam Hocevar's avatar
 
Sam Hocevar committed
92
    mtime_t freq, usec_time;
Sam Hocevar's avatar
 
Sam Hocevar committed
93

Sam Hocevar's avatar
 
Sam Hocevar committed
94
    if( QueryPerformanceFrequency( (LARGE_INTEGER *)&freq ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
95
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
96 97
        /* Microsecond resolution */
        QueryPerformanceCounter( (LARGE_INTEGER *)&usec_time );
gbazin's avatar
 
gbazin committed
98
        return ( usec_time * 1000000 ) / freq;
Sam Hocevar's avatar
 
Sam Hocevar committed
99 100 101
    }
    else
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
102 103
        /* Milisecond resolution */
        return 1000 * GetTickCount();
Sam Hocevar's avatar
 
Sam Hocevar committed
104 105
    }

106
#else
Michel Kaempf's avatar
Michel Kaempf committed
107 108 109 110 111 112 113
    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
114

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

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

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

    usec_time = mdate();
    delay = date - usec_time;
    if( delay <= 0 )
    {
        return;
    }
gbazin's avatar
 
gbazin committed
146
    msleep( delay );
147 148 149

#else

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

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

    /* calculate delay and check if current date is before wished date */
Sam Hocevar's avatar
 
Sam Hocevar committed
161 162 163 164
    delay = date - (mtime_t) tv_date.tv_sec * 1000000
                 - (mtime_t) tv_date.tv_usec
                 - 10000;

165 166
    /* Linux/i386 has a granularity of 10 ms. It's better to be in advance
     * than to be late. */
167
    if( delay <= 0 )                 /* wished date is now or already passed */
Michel Kaempf's avatar
Michel Kaempf committed
168 169 170
    {
        return;
    }
171

Sam Hocevar's avatar
 
Sam Hocevar committed
172 173 174 175
#   if defined( PTH_INIT_IN_PTH_H )
    pth_usleep( delay );

#   elif defined( HAVE_USLEEP )
176
    usleep( delay );
Sam Hocevar's avatar
 
Sam Hocevar committed
177

Sam Hocevar's avatar
 
Sam Hocevar committed
178
#   else
Michel Kaempf's avatar
Michel Kaempf committed
179
    tv_delay.tv_sec = delay / 1000000;
Michel Kaempf's avatar
Michel Kaempf committed
180
    tv_delay.tv_usec = delay % 1000000;
Michel Kaempf's avatar
Michel Kaempf committed
181 182
    /* see msleep() about select() errors */
    select( 0, NULL, NULL, NULL, &tv_delay );
Sam Hocevar's avatar
 
Sam Hocevar committed
183

Sam Hocevar's avatar
 
Sam Hocevar committed
184
#   endif
185

Sam Hocevar's avatar
 
Sam Hocevar committed
186
#endif
Michel Kaempf's avatar
Michel Kaempf committed
187 188
}

189
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
190
 * msleep: more precise sleep() (inline function)                        (ok ?)
191
 *****************************************************************************
192
 * Portable usleep() function.
193
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
194 195
void msleep( mtime_t delay )
{
Sam Hocevar's avatar
 
Sam Hocevar committed
196
#if defined( HAVE_KERNEL_OS_H )
197 198
    snooze( delay );

Sam Hocevar's avatar
 
Sam Hocevar committed
199 200 201 202 203 204
#elif defined( PTH_INIT_IN_PTH_H )
    struct timeval tv_delay;
    tv_delay.tv_sec = delay / 1000000;
    tv_delay.tv_usec = delay % 1000000;
    pth_select( 0, NULL, NULL, NULL, &tv_delay );

gbazin's avatar
 
gbazin committed
205
#elif defined( HAVE_USLEEP )
Sam Hocevar's avatar
 
Sam Hocevar committed
206 207
    usleep( delay );

gbazin's avatar
 
gbazin committed
208 209 210
#elif defined( WIN32 )
    Sleep( (int) (delay / 1000) );

211
#else
Michel Kaempf's avatar
Michel Kaempf committed
212 213 214 215 216 217 218 219 220
    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 );
221

Sam Hocevar's avatar
 
Sam Hocevar committed
222
#endif
Michel Kaempf's avatar
Michel Kaempf committed
223
}
Sam Hocevar's avatar
 
Sam Hocevar committed
224