I found myself writing code to run at a specified frequency more than once, so I decided to make this simple timer. My main concern is that this is not the most efficient way of doing this since with SDL
I would just ask for the time in ms and sleep in ms.
I'm storing the current time in timer_update()
to avoid the possibility of it becoming greater than the final time and generating a huge pause since it's unsigned.
Usage is pretty simple, timer_init()
is called once before the loop and timer_update()
is called once at the end of every iteration.
timer.h
#ifndef TIMER_H
#define TIMER_H
typedef struct {
double step;
double tfinal;
} Timer;
void timer_init(Timer *timer, double hertz);
void timer_update(Timer *timer);
#endif
timer.c
#include "timer.h"
#define _POSIX_C_SOURCE 199309L
#include <time.h>
#include <errno.h>
#include <stdio.h>
static unsigned long get_ms(void)
{
struct timespec buffer;
unsigned long temp;
if(clock_gettime(CLOCK_MONOTONIC, &buffer) != 0){
perror("clock_gettime");
return 0;
}
temp = buffer.tv_sec * 1000;
temp += buffer.tv_nsec / 1000000;
return temp;
}
static struct timespec ms_to_timespec(unsigned long ms)
{
struct timespec temp = {ms / 1000, (ms % 1000) * 1000000};
return temp;
}
void timer_init(Timer *timer, double hertz)
{
timer->step = 1000 / hertz;
timer->tfinal = get_ms() + timer->step;
}
void timer_update(Timer *timer)
{
unsigned long now = get_ms();
struct timespec required_sleep, rem;
if(now < timer->tfinal){
required_sleep = ms_to_timespec(timer->tfinal - now);
timer->tfinal += timer->step;
try_to_sleep:
if(nanosleep(&required_sleep, &rem) == -1 && errno == EINTR)
if(nanosleep(&rem, &required_sleep) == -1 && errno == EINTR)
goto try_to_sleep;
}
else
timer->tfinal += timer->step;
}