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 **/ 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 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 **/ 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 **/ 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 */ 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 **/ 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 **/ 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 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 **/ 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 **/ 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 */ 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 **/ 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