1 /*---------------------------------------------------------------------------*
2 * ptimer.c *
3 * *
4 * Copyright 2007, 2008 Nuance Communciations, Inc. *
5 * *
6 * Licensed under the Apache License, Version 2.0 (the 'License'); *
7 * you may not use this file except in compliance with the License. *
8 * *
9 * You may obtain a copy of the License at *
10 * http://www.apache.org/licenses/LICENSE-2.0 *
11 * *
12 * Unless required by applicable law or agreed to in writing, software *
13 * distributed under the License is distributed on an 'AS IS' BASIS, *
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 * See the License for the specific language governing permissions and *
16 * limitations under the License. *
17 * *
18 *---------------------------------------------------------------------------*/
19
20
21
22 #include "pmemory.h"
23 #include "ptimer.h"
24 #include "pmutex.h"
25
26 #ifdef _WIN32
27
28 /*
29 Note that this implementation assumes that QueryPerformanceCounter is
30 available (requires NT 3.1 and above) and that 64 bit arithmetic is
31 available (requires VC)
32 */
33
34 struct PTimer_t
35 {
36 LARGE_INTEGER PerformanceFreq;
37 LARGE_INTEGER RefTime;
38 LARGE_INTEGER elapsed;
39 };
40
41
42
43 /**
44 * Creates a new timer object.
45 **/
PTimerCreate(PTimer ** timer)46 ESR_ReturnCode PTimerCreate(PTimer **timer)
47 {
48 PTimer *tmp = NULL;
49
50 if (timer == NULL)
51 return ESR_INVALID_ARGUMENT;
52 tmp = NEW(PTimer, "PTimer");
53 if (tmp == NULL)
54 return ESR_OUT_OF_MEMORY;
55
56 if (QueryPerformanceFrequency(&tmp->PerformanceFreq) == 0)
57 {
58 FREE(tmp);
59 return ESR_NOT_SUPPORTED;
60 }
61 tmp->PerformanceFreq.QuadPart /= 1000;
62
63 tmp->RefTime.QuadPart = 0;
64 tmp->elapsed.QuadPart = 0;
65 *timer = tmp;
66 return ESR_SUCCESS;
67 }
68
PTimerDestroy(PTimer * timer)69 ESR_ReturnCode PTimerDestroy(PTimer *timer)
70 {
71 if (timer == NULL) return ESR_INVALID_ARGUMENT;
72 FREE(timer);
73 return ESR_SUCCESS;
74 }
75
76 /**
77 * Starts the timer. This sets the reference time from which all new elapsed
78 * time are computed. This does not reset the elapsed time to 0. This is
79 * useful to pause the timer.
80 **/
PTimerStart(PTimer * timer)81 ESR_ReturnCode PTimerStart(PTimer *timer)
82 {
83 if (timer == NULL) return ESR_INVALID_ARGUMENT;
84 return (QueryPerformanceCounter(&timer->RefTime) ?
85 ESR_SUCCESS :
86 ESR_NOT_SUPPORTED);
87 }
88
89 /**
90 * Stops the timer.
91 **/
PTimerStop(PTimer * timer)92 ESR_ReturnCode PTimerStop(PTimer *timer)
93 {
94 if (timer == NULL) return ESR_INVALID_ARGUMENT;
95 if (timer->RefTime.QuadPart != 0)
96 {
97 LARGE_INTEGER now;
98 if (!QueryPerformanceCounter(&now)) return ESR_NOT_SUPPORTED;
99 timer->elapsed.QuadPart += now.QuadPart - timer->RefTime.QuadPart;
100 timer->RefTime.QuadPart = 0;
101 }
102 return ESR_SUCCESS;
103 }
104
105 /**
106 * Returns the timer elapsed time. If the Timer is in the stopped state,
107 * successive calls to getElapsed() will always return the same value. If
108 * the Timer is in the started state, successive calls will return the
109 * elapsed time since the last time PTimerStart() was called.
110 */
PTimerGetElapsed(PTimer * timer,asr_uint32_t * elapsed)111 ESR_ReturnCode PTimerGetElapsed(PTimer *timer, asr_uint32_t* elapsed)
112 {
113 if (timer == NULL || elapsed == NULL)
114 return ESR_INVALID_ARGUMENT;
115
116 if (timer->RefTime.QuadPart != 0)
117 {
118 LARGE_INTEGER now;
119 if (!QueryPerformanceCounter(&now)) return ESR_NOT_SUPPORTED;
120 *elapsed = (asr_uint32_t) ((timer->elapsed.QuadPart + (now.QuadPart - timer->RefTime.QuadPart))
121 / timer->PerformanceFreq.QuadPart);
122 }
123 else
124 *elapsed = (asr_uint32_t) (timer->elapsed.QuadPart / timer->PerformanceFreq.QuadPart);
125
126 return ESR_SUCCESS;
127 }
128
129
130 /**
131 * Resets the elapsed time to 0 and resets the reference time of the Timer.
132 * This effectively reset the timer in the same state it was right after creation.
133 **/
PTimerReset(PTimer * timer)134 ESR_ReturnCode PTimerReset(PTimer *timer)
135 {
136 if (timer == NULL) return ESR_INVALID_ARGUMENT;
137 timer->RefTime.QuadPart = 0;
138 timer->elapsed.QuadPart = 0;
139 return ESR_SUCCESS;
140 }
141
142 #elif defined(POSIX)
143 #include "ptrd.h"
144 /*
145 POSIX has a timer
146 */
147 /* Clocks and timers: clock_settime, clock_gettime, clock_getres, timer_xxx and nanosleep */
148 #ifndef _POSIX_TIMERS
149 #ifndef __vxworks /* __vxworks does not define it! */
150 #error "Timer is not defined!"
151 #endif /* __vxworks */
152 #endif /* _POSIX_TIMERS */
153
154 #define TIMER_MAX_VAL 10000
155
156 struct PTimer_t
157 {
158 timer_t timer;
159 asr_uint32_t elapsed;
160 };
161
162 /**
163 * Creates a new timer object.
164 **/
PTimerCreate(PTimer ** timer)165 ESR_ReturnCode PTimerCreate(PTimer **timer)
166 {
167 PTimer *tmp = NULL;
168
169 if (timer == NULL) return ESR_INVALID_ARGUMENT;
170 tmp = NEW(PTimer, "PTimer");
171 if (tmp == NULL) return ESR_OUT_OF_MEMORY;
172
173 *timer = tmp;
174 if (timer_create(CLOCK_REALTIME, NULL, &(tmp->timer)) < 0)
175 return ESR_NOT_SUPPORTED;
176
177 return ESR_SUCCESS;
178 }
179
PTimerDestroy(PTimer * timer)180 ESR_ReturnCode PTimerDestroy(PTimer *timer)
181 {
182 if (timer == NULL) return ESR_INVALID_ARGUMENT;
183 timer_delete(timer->timer);
184 FREE(timer);
185
186 return ESR_SUCCESS;
187 }
188
189 /**
190 * Starts the timer. This sets the reference time from which all new elapsed
191 * time are computed. This does not reset the elapsed time to 0. This is
192 * useful to pause the timer.
193 **/
PTimerStart(PTimer * timer)194 ESR_ReturnCode PTimerStart(PTimer *timer)
195 {
196 struct itimerspec expire_time;
197
198 if (timer == NULL) return ESR_INVALID_ARGUMENT;
199
200 expire_time.it_value.tv_sec = TIMER_MAX_VAL; /* set a large time for the timer */
201 expire_time.it_value.tv_nsec = 0;
202 return (timer_settime(timer->timer, 0, &expire_time, NULL) == 0 ?
203 ESR_SUCCESS :
204 ESR_NOT_SUPPORTED);
205 }
206
207 /**
208 * Stops the timer.
209 **/
PTimerStop(PTimer * timer)210 ESR_ReturnCode PTimerStop(PTimer *timer)
211 {
212 struct itimerspec remaining;
213
214 if (timer == NULL) return ESR_INVALID_ARGUMENT;
215
216 if (timer_gettime(timer->timer, &remaining) != 0) return ESR_NOT_SUPPORTED;
217 #if defined(__vxworks)
218 timer_cancel(timer->timer);
219 #endif
220 timer->elapsed = (asr_uint32_t) ((TIMER_MAX_VAL - remaining.it_value.tv_sec) * SECOND2MSECOND
221 - remaining.it_value.tv_nsec / MSECOND2NSECOND);
222
223 return ESR_SUCCESS;
224 }
225
226 /**
227 * Returns the timer elapsed time. If the Timer is in the stopped state,
228 * successive calls to getElapsed() will always return the same value. If
229 * the Timer is in the started state, successive calls will return the
230 * elapsed time since the last time PTimerStart() was called.
231 */
PTimerGetElapsed(PTimer * timer,asr_uint32_t * elapsed)232 ESR_ReturnCode PTimerGetElapsed(PTimer *timer, asr_uint32_t* elapsed)
233 {
234 if (timer == NULL || elapsed == NULL)
235 return ESR_INVALID_ARGUMENT;
236
237 if (timer->elapsed == 0) /* stop is not called */
238 {
239 struct itimerspec remaining;
240 if (timer_gettime(timer->timer, &remaining) != 0) return ESR_NOT_SUPPORTED;
241 *elapsed = (asr_uint32_t) ((TIMER_MAX_VAL - remaining.it_value.tv_sec) * SECOND2MSECOND
242 - remaining.it_value.tv_nsec / MSECOND2NSECOND);
243 }
244 else
245 *elapsed = timer->elapsed;
246
247 return ESR_SUCCESS;
248 }
249
250
251 /**
252 * Resets the elapsed time to 0 and resets the reference time of the Timer.
253 * This effectively reset the timer in the same state it was right after creation.
254 **/
PTimerReset(PTimer * timer)255 ESR_ReturnCode PTimerReset(PTimer *timer)
256 {
257 if (timer == NULL) return ESR_INVALID_ARGUMENT;
258 timer->elapsed = 0;
259 return ESR_SUCCESS;
260 }
261
262 #else
263 #error "Ptimer not implemented for this platform."
264 #endif
265