src/timer/unix/SDL_systimer.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 23 Jun 2013 22:19:38 -0700
changeset 7316 c3052ed2c310
parent 7191 75360622e65f
child 7628 ebf5f6859e40
permissions -rw-r--r--
Updated timer test and fixed performance counter on Mac OS X
slouken@1361
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
slouken@1361
     4
slouken@5535
     5
  This software is provided 'as-is', without any express or implied
slouken@5535
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@5535
     7
  arising from the use of this software.
slouken@1361
     8
slouken@5535
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@5535
    10
  including commercial applications, and to alter it and redistribute it
slouken@5535
    11
  freely, subject to the following restrictions:
slouken@1361
    12
slouken@5535
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@5535
    14
     claim that you wrote the original software. If you use this software
slouken@5535
    15
     in a product, an acknowledgment in the product documentation would be
slouken@5535
    16
     appreciated but is not required.
slouken@5535
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@5535
    18
     misrepresented as being the original software.
slouken@5535
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@1361
    20
*/
slouken@1402
    21
#include "SDL_config.h"
slouken@1361
    22
slouken@1635
    23
#ifdef SDL_TIMER_UNIX
slouken@1635
    24
slouken@1361
    25
#include <stdio.h>
slouken@1361
    26
#include <sys/time.h>
slouken@1361
    27
#include <unistd.h>
slouken@1361
    28
#include <errno.h>
slouken@1361
    29
slouken@1361
    30
#include "SDL_timer.h"
slouken@1361
    31
slouken@1361
    32
/* The clock_gettime provides monotonous time, so we should use it if
slouken@1361
    33
   it's available. The clock_gettime function is behind ifdef
slouken@1361
    34
   for __USE_POSIX199309
slouken@1361
    35
   Tommi Kyntola (tommi.kyntola@ray.fi) 27/09/2005
slouken@1361
    36
*/
urkle@7137
    37
/* Reworked monotonic clock to not assume the current system has one
urkle@7137
    38
   as not all linux kernels provide a monotonic clock (yeah recent ones
urkle@7137
    39
   probably do)
urkle@7137
    40
   Also added OS X Monotonic clock support
urkle@7137
    41
   Based on work in https://github.com/ThomasHabets/monotonic_clock
urkle@7137
    42
 */
slouken@1598
    43
#if HAVE_NANOSLEEP || HAVE_CLOCK_GETTIME
slouken@1361
    44
#include <time.h>
slouken@1361
    45
#endif
urkle@7137
    46
#ifdef __APPLE__
urkle@7137
    47
#include <mach/mach_time.h>
urkle@7137
    48
#endif
slouken@1361
    49
slouken@1361
    50
/* The first ticks value of the application */
urkle@7137
    51
#if HAVE_CLOCK_GETTIME
urkle@7137
    52
static struct timespec start_ts;
urkle@7137
    53
#elif defined(__APPLE__)
urkle@7137
    54
static uint64_t start_mach;
urkle@7137
    55
mach_timebase_info_data_t mach_base_info;
urkle@7137
    56
#endif
urkle@7137
    57
static SDL_bool has_monotonic_time = SDL_FALSE;
urkle@7137
    58
static struct timeval start_tv;
slouken@1361
    59
slouken@1895
    60
void
slouken@1895
    61
SDL_StartTicks(void)
slouken@1361
    62
{
slouken@1895
    63
    /* Set first ticks value */
slouken@1361
    64
#if HAVE_CLOCK_GETTIME
urkle@7137
    65
    if (clock_gettime(CLOCK_MONOTONIC, &start_ts) == 0) {
urkle@7137
    66
        has_monotonic_time = SDL_TRUE;
urkle@7137
    67
    } else
urkle@7137
    68
#elif defined(__APPLE__)
urkle@7137
    69
    kern_return_t ret = mach_timebase_info(&mach_base_info);
urkle@7137
    70
    if (ret == 0) {
urkle@7137
    71
        has_monotonic_time = SDL_TRUE;
slouken@7316
    72
        start_mach = mach_absolute_time();
urkle@7137
    73
    } else
slouken@1361
    74
#endif
urkle@7137
    75
    {
urkle@7137
    76
        gettimeofday(&start_tv, NULL);
urkle@7137
    77
    }
slouken@1361
    78
}
slouken@1361
    79
slouken@1895
    80
Uint32
slouken@1895
    81
SDL_GetTicks(void)
slouken@1361
    82
{
urkle@7137
    83
    Uint32 ticks;
urkle@7137
    84
    if (has_monotonic_time) {
slouken@1361
    85
#if HAVE_CLOCK_GETTIME
urkle@7137
    86
        struct timespec now;
urkle@7137
    87
        clock_gettime(CLOCK_MONOTONIC, &now);
slouken@7316
    88
        ticks = (now.tv_sec - start_ts.tv_sec) * 1000 + (now.tv_nsec -
urkle@7137
    89
                                                 start_ts.tv_nsec) / 1000000;
urkle@7137
    90
#elif defined(__APPLE__)
urkle@7137
    91
        uint64_t now = mach_absolute_time();
slouken@7316
    92
        ticks = (((now - start_mach) * mach_base_info.numer) / mach_base_info.denom) / 1000000;
urkle@7137
    93
#endif
urkle@7137
    94
    } else {
urkle@7137
    95
        struct timeval now;
slouken@5514
    96
urkle@7137
    97
        gettimeofday(&now, NULL);
urkle@7137
    98
        ticks =
urkle@7137
    99
            (now.tv_sec - start_tv.tv_sec) * 1000 + (now.tv_usec -
urkle@7137
   100
                                                  start_tv.tv_usec) / 1000;
urkle@7137
   101
    }
slouken@1895
   102
    return (ticks);
slouken@1361
   103
}
slouken@1361
   104
slouken@5514
   105
Uint64
slouken@5514
   106
SDL_GetPerformanceCounter(void)
slouken@5514
   107
{
urkle@7137
   108
    Uint64 ticks;
urkle@7137
   109
    if (has_monotonic_time) {
slouken@5514
   110
#if HAVE_CLOCK_GETTIME
urkle@7137
   111
        struct timespec now;
slouken@5514
   112
urkle@7137
   113
        clock_gettime(CLOCK_MONOTONIC, &now);
urkle@7137
   114
        ticks = now.tv_sec;
urkle@7137
   115
        ticks *= 1000000000;
urkle@7137
   116
        ticks += now.tv_nsec;
urkle@7137
   117
#elif defined(__APPLE__)
urkle@7137
   118
        ticks = mach_absolute_time();
urkle@7137
   119
#endif
urkle@7137
   120
    } else {
urkle@7137
   121
        struct timeval now;
urkle@7137
   122
urkle@7137
   123
        gettimeofday(&now, NULL);
urkle@7137
   124
        ticks = now.tv_sec;
urkle@7137
   125
        ticks *= 1000000;
urkle@7137
   126
        ticks += now.tv_usec;
urkle@7137
   127
    }
slouken@5514
   128
    return (ticks);
slouken@5514
   129
}
slouken@5514
   130
slouken@5514
   131
Uint64
slouken@5514
   132
SDL_GetPerformanceFrequency(void)
slouken@5514
   133
{
urkle@7137
   134
    if (has_monotonic_time) {
slouken@5514
   135
#if HAVE_CLOCK_GETTIME
urkle@7137
   136
        return 1000000000;
urkle@7137
   137
#elif defined(__APPLE__)
slouken@7316
   138
        Uint64 freq = mach_base_info.numer;
slouken@7316
   139
        freq *= 1000000000;
slouken@7316
   140
        freq /= mach_base_info.denom;
slouken@7316
   141
        return freq;
slouken@5514
   142
#endif
urkle@7137
   143
    } else {
urkle@7137
   144
        return 1000000;
urkle@7137
   145
    }
slouken@5514
   146
}
slouken@5514
   147
slouken@1895
   148
void
slouken@1895
   149
SDL_Delay(Uint32 ms)
slouken@1361
   150
{
slouken@1895
   151
    int was_error;
slouken@1361
   152
slouken@1361
   153
#if HAVE_NANOSLEEP
slouken@1895
   154
    struct timespec elapsed, tv;
slouken@1361
   155
#else
slouken@1895
   156
    struct timeval tv;
slouken@1895
   157
    Uint32 then, now, elapsed;
slouken@1361
   158
#endif
slouken@1361
   159
slouken@1895
   160
    /* Set the timeout interval */
slouken@1361
   161
#if HAVE_NANOSLEEP
slouken@1895
   162
    elapsed.tv_sec = ms / 1000;
slouken@1895
   163
    elapsed.tv_nsec = (ms % 1000) * 1000000;
slouken@1361
   164
#else
slouken@1895
   165
    then = SDL_GetTicks();
slouken@1361
   166
#endif
slouken@1895
   167
    do {
slouken@1895
   168
        errno = 0;
slouken@1361
   169
slouken@1361
   170
#if HAVE_NANOSLEEP
slouken@1895
   171
        tv.tv_sec = elapsed.tv_sec;
slouken@1895
   172
        tv.tv_nsec = elapsed.tv_nsec;
slouken@1895
   173
        was_error = nanosleep(&tv, &elapsed);
slouken@1361
   174
#else
slouken@1895
   175
        /* Calculate the time interval left (in case of interrupt) */
slouken@1895
   176
        now = SDL_GetTicks();
slouken@1895
   177
        elapsed = (now - then);
slouken@1895
   178
        then = now;
slouken@1895
   179
        if (elapsed >= ms) {
slouken@1895
   180
            break;
slouken@1895
   181
        }
slouken@1895
   182
        ms -= elapsed;
slouken@1895
   183
        tv.tv_sec = ms / 1000;
slouken@1895
   184
        tv.tv_usec = (ms % 1000) * 1000;
slouken@1361
   185
slouken@1895
   186
        was_error = select(0, NULL, NULL, NULL, &tv);
slouken@1361
   187
#endif /* HAVE_NANOSLEEP */
slouken@2735
   188
    } while (was_error && (errno == EINTR));
slouken@1361
   189
}
slouken@1361
   190
slouken@5111
   191
#endif /* SDL_TIMER_UNIX */
slouken@1361
   192
slouken@1895
   193
/* vi: set ts=4 sw=4 expandtab: */