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