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 34struct 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 **/ 46ESR_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 69ESR_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 **/ 81ESR_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 **/ 92ESR_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 */ 111ESR_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 **/ 134ESR_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/* 145POSIX 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 156struct PTimer_t 157{ 158 timer_t timer; 159 asr_uint32_t elapsed; 160}; 161 162/** 163* Creates a new timer object. 164**/ 165ESR_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 180ESR_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**/ 194ESR_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**/ 210ESR_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*/ 232ESR_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**/ 255ESR_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