/* ______ ___ ___ * /\ _ \ /\_ \ /\_ \ * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___ * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\ * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \ * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/ * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/ * /\____/ * \_/__/ * * Unix timer module. * * By Peter Wang. * * _unix_rest by Elias Pschernig. * * See readme.txt for copyright information. */ #include "allegro.h" #include "allegro/platform/aintunix.h" #include #ifndef ALLEGRO_MACOSX /* System drivers provide their own lists, so this is just to keep the * Allegro framework happy. */ _DRIVER_INFO _timer_driver_list[] = { { 0, 0, 0 } }; #endif /* timeval_subtract: * Subtract the `struct timeval' values X and Y, storing the result * in RESULT. Return 1 if the difference is negative, otherwise 0. * * This function is from the glibc manual. It handles weird platforms * where the tv_sec is unsigned. */ static int timeval_subtract(struct timeval *result, struct timeval *x, struct timeval *y) { /* Perform the carry for the later subtraction by updating Y. */ if (x->tv_usec < y->tv_usec) { int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1; y->tv_usec -= 1000000 * nsec; y->tv_sec += nsec; } if (x->tv_usec - y->tv_usec > 1000000) { int nsec = (x->tv_usec - y->tv_usec) / 1000000; y->tv_usec += 1000000 * nsec; y->tv_sec -= nsec; } /* Compute the time remaining to wait. * `tv_usec' is certainly positive. */ result->tv_sec = x->tv_sec - y->tv_sec; result->tv_usec = x->tv_usec - y->tv_usec; /* Return 1 if result is negative. */ return x->tv_sec < y->tv_sec; } void _unix_rest(unsigned int ms, void (*callback) (void)) { if (callback) { struct timeval tv, tv_end; gettimeofday (&tv_end, NULL); tv_end.tv_usec += ms * 1000; tv_end.tv_sec += (tv_end.tv_usec / 1000000L); tv_end.tv_usec %= 1000000L; while (1) { (*callback)(); gettimeofday (&tv, NULL); if (tv.tv_sec > tv_end.tv_sec) break; if (tv.tv_sec == tv_end.tv_sec && tv.tv_usec >= tv_end.tv_usec) break; } } else { struct timeval now; struct timeval end; struct timeval delay; int result; gettimeofday(&now, NULL); end = now; end.tv_usec += ms * 1000; end.tv_sec += (end.tv_usec / 1000000L); end.tv_usec %= 1000000L; while (1) { if (timeval_subtract(&delay, &end, &now)) break; #ifdef ALLEGRO_MACOSX result = usleep((delay.tv_sec * 1000000L) + delay.tv_usec); #else result = select(0, NULL, NULL, NULL, &delay); #endif if (result == 0) /* ok */ break; if ((result != -1) || (errno != EINTR)) break; /* interrupted */ gettimeofday(&now, NULL); } } }