[RFC+PATCH] Introducing posix timers to linux SDL_GetTicks()

(my first contact with sdl mailing list, so bear with me)

DESCRIPTION
Here’s an example use of the posix clock_gettime function
to calculate time difference for src/timer/linux/SDL_systimer.c

MOTIVATION
gettimeofday does not provide monotonous time on linux
systems and therefore setting the system time easily
breaks the SDL timer subsystem. However most modern
linux systems are equiped with posix timers functions
that indeed do provide a monotonous time source.

I was unable to locate anything with SDL and clock_gettime
so I’m guessing this has not been discussed here before.
(And sorry for the intrusion if it has been discussed.)

The clock_gettime claims the following:
“On POSIX systems on which these functions are available,
the symbol _POSIX_TIMERS is defined in <unistd.h> to
a value greater than 0.”

This should be available on many other posix systems aswell.
Also on most systems these clock_ functions are implemented
in glibc librt.

The following patch is also availabe at:
http://www.hut.fi/u/tkyntola/SDL-1.2.9-clockfix.patch

It’s against 1.2.9, but I can easily rediffit against
the cvs branch is needed.

cheers,
Tommi Kyntola @Tommi_Kyntola

diff -Naur SDL-1.2.9/src/timer/linux/SDL_systimer.c SDL-1.2.9-clockfix/src/timer/linux/SDL_systimer.c
— SDL-1.2.9/src/timer/linux/SDL_systimer.c 2004-01-04 18:49:19.000000000 +0200
+++ SDL-1.2.9-clockfix/src/timer/linux/SDL_systimer.c 2005-09-27 10:49:26.000000000 +0300
@@ -34,6 +34,16 @@
#include <string.h>
#include <errno.h>

+/* The clock_gettime provides monotonous time, so we should use it if

  • it’s available. The clock_gettime function is behind ifdef
  • for __USE_POSIX199309
  • Tommi Kyntola (@Tommi_Kyntola) 27/09/2005
    +/
    +#if (defined _POSIX_TIMERS && _POSIX_TIMERS > 0)
    +#include <time.h>
    +#define USE_CLOCK_GETTIME
    +#endif+
    #include “SDL_error.h”
    #include “SDL_timer.h”
    #include “SDL_timer_c.h”
    @@ -86,6 +96,19 @@
    float cpu_mhz;
    unsigned long long tsc_start;
    unsigned long long tsc_end;
    +/
    Slight code doubling here for the sake of readability */
    +#ifdef USE_CLOCK_GETTIME
  •   struct timespec tv_start, tv_end;
    
  •   long usec_delay;
    
  •   rdtsc(tsc_start);
    
  •   clock_gettime(CLOCK_MONOTONIC,&tv_start);
    
  •   sleep(1);
    
  •   rdtsc(tsc_end);
    
  •   clock_gettime(CLOCK_MONOTONIC,&tv_end);
    
  •   usec_delay = (1000000000L * (tv_end.tv_sec - tv_start.tv_sec) +
    
  •                 (tv_end.tv_nsec - tv_start.tv_nsec)) / 1000;
    

+#else
struct timeval tv_start, tv_end;
long usec_delay;

@@ -96,6 +119,7 @@
gettimeofday(&tv_end, NULL);
usec_delay = 1000000L * (tv_end.tv_sec - tv_start.tv_sec) +
(tv_end.tv_usec - tv_start.tv_usec);
+#endif /* USE_CLOCK_GETTIME */
cpu_mhz = (float)(tsc_end-tsc_start) / usec_delay;
#if 0
printf(“cpu MHz\t\t: %.3f\n”, cpu_mhz);
@@ -105,8 +129,12 @@

#else

+#ifdef USE_CLOCK_GETTIME
/* The first ticks value of the application /
+static struct timespec start;
+#else
static struct timeval start;
+#endif /
USE_CLOCK_GETTIME */

#endif /* USE_RDTSC */

@@ -120,7 +148,11 @@
}
rdtsc(start);
#else
+#ifdef USE_CLOCK_GETTIME

  •   clock_gettime(CLOCK_MONOTONIC,&start);
    

+#else
gettimeofday(&start, NULL);
+#endif /* USE_CLOCK_GETTIME /
#endif /
USE_RDTSC */
}

@@ -134,11 +166,17 @@
rdtsc(now);
return (Uint32)((now-start)/cpu_mhz1000);
#else

  •   struct timeval now;
       Uint32 ticks;
    

+#ifdef USE_CLOCK_GETTIME

  •   struct timespec now;
    
  •   clock_gettime(CLOCK_MONOTONIC,&now);
    
  •   ticks=(now.tv_sec-start.tv_sec)*1000+(now.tv_nsec-start.tv_nsec)/1000000;
    

+#else

  •   struct timeval now;
       gettimeofday(&now, NULL);
       ticks=(now.tv_sec-start.tv_sec)*1000+(now.tv_usec-start.tv_usec)/1000;
    

+#endif /* USE_CLOCK_GETTIME /
return(ticks);
#endif /
USE_RDTSC */
}