1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Unix timer module.
12 *
13 * By Peter Wang.
14 *
15 * _unix_rest by Elias Pschernig.
16 *
17 * See readme.txt for copyright information.
18 */
19
20
21 #include "allegro.h"
22 #include "allegro/platform/aintunix.h"
23 #include <sys/time.h>
24
25
26 #ifndef ALLEGRO_MACOSX
27
28 /* System drivers provide their own lists, so this is just to keep the
29 * Allegro framework happy. */
30 _DRIVER_INFO _timer_driver_list[] = {
31 { 0, 0, 0 }
32 };
33
34 #endif
35
36
37
38 /* timeval_subtract:
39 * Subtract the `struct timeval' values X and Y, storing the result
40 * in RESULT. Return 1 if the difference is negative, otherwise 0.
41 *
42 * This function is from the glibc manual. It handles weird platforms
43 * where the tv_sec is unsigned.
44 */
timeval_subtract(struct timeval * result,struct timeval * x,struct timeval * y)45 static int timeval_subtract(struct timeval *result,
46 struct timeval *x,
47 struct timeval *y)
48 {
49 /* Perform the carry for the later subtraction by updating Y. */
50 if (x->tv_usec < y->tv_usec) {
51 int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
52 y->tv_usec -= 1000000 * nsec;
53 y->tv_sec += nsec;
54 }
55 if (x->tv_usec - y->tv_usec > 1000000) {
56 int nsec = (x->tv_usec - y->tv_usec) / 1000000;
57 y->tv_usec += 1000000 * nsec;
58 y->tv_sec -= nsec;
59 }
60
61 /* Compute the time remaining to wait.
62 * `tv_usec' is certainly positive. */
63 result->tv_sec = x->tv_sec - y->tv_sec;
64 result->tv_usec = x->tv_usec - y->tv_usec;
65 /* Return 1 if result is negative. */
66 return x->tv_sec < y->tv_sec;
67 }
68
69
70
_unix_rest(unsigned int ms,void (* callback)(void))71 void _unix_rest(unsigned int ms, void (*callback) (void))
72 {
73 if (callback) {
74 struct timeval tv, tv_end;
75
76 gettimeofday (&tv_end, NULL);
77 tv_end.tv_usec += ms * 1000;
78 tv_end.tv_sec += (tv_end.tv_usec / 1000000L);
79 tv_end.tv_usec %= 1000000L;
80
81 while (1)
82 {
83 (*callback)();
84 gettimeofday (&tv, NULL);
85 if (tv.tv_sec > tv_end.tv_sec)
86 break;
87 if (tv.tv_sec == tv_end.tv_sec && tv.tv_usec >= tv_end.tv_usec)
88 break;
89 }
90 }
91 else {
92 struct timeval now;
93 struct timeval end;
94 struct timeval delay;
95 int result;
96
97 gettimeofday(&now, NULL);
98
99 end = now;
100 end.tv_usec += ms * 1000;
101 end.tv_sec += (end.tv_usec / 1000000L);
102 end.tv_usec %= 1000000L;
103
104 while (1) {
105 if (timeval_subtract(&delay, &end, &now))
106 break;
107
108 #ifdef ALLEGRO_MACOSX
109 result = usleep((delay.tv_sec * 1000000L) + delay.tv_usec);
110 #else
111 result = select(0, NULL, NULL, NULL, &delay);
112 #endif
113 if (result == 0) /* ok */
114 break;
115 if ((result != -1) || (errno != EINTR))
116 break;
117
118 /* interrupted */
119 gettimeofday(&now, NULL);
120 }
121 }
122 }
123