1 |
dpavlin |
1 |
/// @file systimer.cc |
2 |
|
|
/// @author Kimball Thurston |
3 |
|
|
/// |
4 |
|
|
|
5 |
|
|
// |
6 |
|
|
// Copyright (c) 2004 Kimball Thurston |
7 |
|
|
// |
8 |
|
|
// This program is free software; you can redistribute it and/or modify |
9 |
|
|
// it under the terms of the GNU General Public License version 2 as |
10 |
|
|
// published by the Free Software Foundation. |
11 |
|
|
// |
12 |
|
|
// This program is distributed in the hope that it will be useful, |
13 |
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
|
|
// GNU General Public License for more details. |
16 |
|
|
// |
17 |
|
|
// You should have received a copy of the GNU General Public License |
18 |
|
|
// along with this program; if not, write to the Free Software |
19 |
|
|
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
20 |
|
|
// |
21 |
|
|
|
22 |
|
|
#include <signal.h> |
23 |
|
|
#include <time.h> |
24 |
|
|
#include <stdio.h> |
25 |
|
|
#include <string.h> |
26 |
|
|
#include <sys/time.h> |
27 |
|
|
|
28 |
|
|
#include "system/systimer.h" |
29 |
|
|
#include "tools/snprintf.h" |
30 |
|
|
|
31 |
|
|
static const int kTimerSignal = SYSTIMER_SIGNAL; |
32 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
33 |
|
|
static void signal_handler(int signo, siginfo_t *extra, void *junk); |
34 |
|
|
static const int kClockRT = CLOCK_PROCESS_CPUTIME_ID; |
35 |
|
|
static const int kClock = CLOCK_REALTIME; |
36 |
|
|
#elif USE_POSIX_SETITIMER |
37 |
|
|
static void signal_handler(int signo); |
38 |
|
|
static const int kClock = ITIMER_REAL; |
39 |
|
|
struct sys_timer_struct; |
40 |
|
|
static sys_timer_struct *gSingleTimer = NULL; |
41 |
|
|
static const int kSignalFlags = 0; |
42 |
|
|
#else |
43 |
|
|
#error no timer support |
44 |
|
|
#endif |
45 |
|
|
|
46 |
|
|
struct sys_timer_struct |
47 |
|
|
{ |
48 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
49 |
|
|
struct sigevent event_info; |
50 |
|
|
timer_t timer_id; |
51 |
|
|
#endif |
52 |
|
|
sys_timer_callback callback; |
53 |
|
|
int clock; |
54 |
|
|
uint64 timer_res; |
55 |
|
|
|
56 |
|
|
sys_timer_struct(sys_timer_callback cb) |
57 |
|
|
: callback(cb), clock(kClock), timer_res(0) |
58 |
|
|
{ |
59 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
60 |
|
|
memset(&event_info, 0, sizeof event_info); |
61 |
|
|
timer_id = 0; |
62 |
|
|
|
63 |
|
|
event_info.sigev_notify = SIGEV_SIGNAL; |
64 |
|
|
event_info.sigev_signo = kTimerSignal; |
65 |
|
|
event_info.sigev_value.sival_ptr = this; |
66 |
|
|
#endif |
67 |
|
|
} |
68 |
|
|
}; |
69 |
|
|
|
70 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
71 |
|
|
static void signal_handler(int signo, siginfo_t *extra, void *junk) |
72 |
|
|
{ |
73 |
|
|
sys_timer_struct *timer = reinterpret_cast<sys_timer_struct *>(extra->si_value.sival_ptr); |
74 |
|
|
timer->callback(reinterpret_cast<sys_timer>(timer)); |
75 |
|
|
} |
76 |
|
|
#else |
77 |
|
|
# ifdef USE_POSIX_SETITIMER |
78 |
|
|
static void signal_handler(int signo) |
79 |
|
|
{ |
80 |
|
|
if (gSingleTimer != NULL) { |
81 |
|
|
gSingleTimer->callback(reinterpret_cast<sys_timer>(gSingleTimer)); |
82 |
|
|
} |
83 |
|
|
} |
84 |
|
|
# endif |
85 |
|
|
#endif |
86 |
|
|
|
87 |
|
|
bool sys_create_timer(sys_timer *t, sys_timer_callback cb_func) |
88 |
|
|
{ |
89 |
|
|
*t = 0; |
90 |
|
|
|
91 |
|
|
sys_timer_struct *newTimer = new sys_timer_struct(cb_func); |
92 |
|
|
|
93 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
94 |
|
|
int clocks[] = {kClockRT, kClock}; |
95 |
|
|
|
96 |
|
|
struct timespec clockRes; |
97 |
|
|
bool foundTimer = false; |
98 |
|
|
|
99 |
|
|
for (uint i=0; i < (sizeof clocks / sizeof clocks[0]); i++) { |
100 |
|
|
if (clock_getres(clocks[i], &clockRes) == 0 |
101 |
|
|
&& timer_create(clocks[i], &newTimer->event_info, |
102 |
|
|
&newTimer->timer_id) == 0) { |
103 |
|
|
|
104 |
|
|
newTimer->clock = clocks[i]; |
105 |
|
|
foundTimer = true; |
106 |
|
|
break; |
107 |
|
|
} |
108 |
|
|
} |
109 |
|
|
|
110 |
|
|
if (!foundTimer) { |
111 |
|
|
perror("Timer create error"); |
112 |
|
|
delete newTimer; |
113 |
|
|
return false; |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
newTimer->timer_res = (uint64)clockRes.tv_sec * 1000 * 1000 * 1000; |
117 |
|
|
newTimer->timer_res += (uint64)clockRes.tv_nsec; |
118 |
|
|
#else |
119 |
|
|
# ifdef USE_POSIX_SETITIMER |
120 |
|
|
if (gSingleTimer != NULL) { |
121 |
|
|
ht_printf("There can only be one active sys timer at a time using\n" |
122 |
|
|
"interval timers.\n"); |
123 |
|
|
delete newTimer; |
124 |
|
|
return false; |
125 |
|
|
} |
126 |
|
|
newTimer->timer_res = 10 * 1000 * 1000; |
127 |
|
|
# endif |
128 |
|
|
#endif |
129 |
|
|
|
130 |
|
|
struct sigaction act; |
131 |
|
|
|
132 |
|
|
sigemptyset(&act.sa_mask); |
133 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
134 |
|
|
act.sa_sigaction = signal_handler; |
135 |
|
|
act.sa_flags = SA_SIGINFO; |
136 |
|
|
#else |
137 |
|
|
# ifdef USE_POSIX_SETITIMER |
138 |
|
|
act.sa_handler = signal_handler; |
139 |
|
|
act.sa_flags = 0; |
140 |
|
|
# endif |
141 |
|
|
#endif |
142 |
|
|
|
143 |
|
|
if (sigemptyset(&act.sa_mask) == -1) { |
144 |
|
|
perror("Error calling sigemptyset"); |
145 |
|
|
return false; |
146 |
|
|
} |
147 |
|
|
|
148 |
|
|
if (sigaction(kTimerSignal, &act, 0) == -1) { |
149 |
|
|
perror("Error calling sigaction"); |
150 |
|
|
return false; |
151 |
|
|
} |
152 |
|
|
|
153 |
|
|
*t = reinterpret_cast<sys_timer>(newTimer); |
154 |
|
|
#ifdef USE_POSIX_SETITIMER |
155 |
|
|
gSingleTimer = newTimer; |
156 |
|
|
#endif |
157 |
|
|
|
158 |
|
|
return true; |
159 |
|
|
} |
160 |
|
|
|
161 |
|
|
void sys_delete_timer(sys_timer t) |
162 |
|
|
{ |
163 |
|
|
sys_timer_struct *timer = reinterpret_cast<sys_timer_struct *>(t); |
164 |
|
|
|
165 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
166 |
|
|
timer_delete(timer->timer_id); |
167 |
|
|
#else |
168 |
|
|
# ifdef USE_POSIX_SETITIMER |
169 |
|
|
struct itimerval itime; |
170 |
|
|
|
171 |
|
|
itime.it_value.tv_sec = 0; |
172 |
|
|
itime.it_value.tv_usec = 0; |
173 |
|
|
itime.it_interval.tv_sec = 0; |
174 |
|
|
itime.it_interval.tv_usec = 0; |
175 |
|
|
|
176 |
|
|
setitimer(timer->clock, &itime, NULL); |
177 |
|
|
gSingleTimer = NULL; |
178 |
|
|
# endif |
179 |
|
|
#endif |
180 |
|
|
|
181 |
|
|
delete timer; |
182 |
|
|
} |
183 |
|
|
|
184 |
|
|
void sys_set_timer(sys_timer t, time_t secs, long int nanosecs, bool periodic) |
185 |
|
|
{ |
186 |
|
|
sys_timer_struct *timer = reinterpret_cast<sys_timer_struct *>(t); |
187 |
|
|
#ifdef USE_POSIX_REALTIME_CLOCK |
188 |
|
|
struct itimerspec itime; |
189 |
|
|
|
190 |
|
|
itime.it_value.tv_sec = secs; |
191 |
|
|
// FIXME: Do we need to have rounding based on timer resolution here? |
192 |
|
|
itime.it_value.tv_nsec = nanosecs;// + (nanosecs % timer->timer_res); |
193 |
|
|
|
194 |
|
|
if (periodic) { |
195 |
|
|
itime.it_interval.tv_sec = secs; |
196 |
|
|
itime.it_interval.tv_nsec = nanosecs; |
197 |
|
|
} else { |
198 |
|
|
itime.it_interval.tv_sec = 0; |
199 |
|
|
itime.it_interval.tv_nsec = 0; |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
if (timer_settime(timer->timer_id, 0, &itime, NULL) < 0) { |
203 |
|
|
perror(__FUNCTION__); |
204 |
|
|
} |
205 |
|
|
|
206 |
|
|
#else |
207 |
|
|
# ifdef USE_POSIX_SETITIMER |
208 |
|
|
struct itimerval itime; |
209 |
|
|
|
210 |
|
|
itime.it_value.tv_sec = secs; |
211 |
|
|
itime.it_value.tv_usec = (nanosecs + 500) / 1000; |
212 |
|
|
|
213 |
|
|
if (periodic) { |
214 |
|
|
itime.it_interval = itime.it_value; |
215 |
|
|
} else { |
216 |
|
|
itime.it_interval.tv_sec = 0; |
217 |
|
|
itime.it_interval.tv_usec = 0; |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
setitimer(timer->clock, &itime, NULL); |
221 |
|
|
# endif |
222 |
|
|
#endif |
223 |
|
|
} |
224 |
|
|
|
225 |
|
|
uint64 sys_get_timer_resolution(sys_timer t) |
226 |
|
|
{ |
227 |
|
|
sys_timer_struct *timer = reinterpret_cast<sys_timer_struct *>(t); |
228 |
|
|
return timer->timer_res; |
229 |
|
|
} |
230 |
|
|
|
231 |
|
|
uint64 sys_get_hiresclk_ticks() |
232 |
|
|
{ |
233 |
|
|
#if HAVE_GETTIMEOFDAY |
234 |
|
|
struct timeval tv; |
235 |
|
|
struct timezone tz; |
236 |
|
|
|
237 |
|
|
gettimeofday(&tv, &tz); |
238 |
|
|
//__asm__ __volatile__("rdtsc" : "=A" (retval)); |
239 |
|
|
|
240 |
|
|
return ((uint64)tv.tv_sec * 1000000) + tv.tv_usec; |
241 |
|
|
#else |
242 |
|
|
return clock(); |
243 |
|
|
#endif |
244 |
|
|
} |
245 |
|
|
|
246 |
|
|
uint64 sys_get_hiresclk_ticks_per_second() |
247 |
|
|
{ |
248 |
|
|
#if HAVE_GETTIMEOFDAY |
249 |
|
|
return 1000000; |
250 |
|
|
#else |
251 |
|
|
return clock(); |
252 |
|
|
#endif |
253 |
|
|
} |