Home | History | Annotate | Download | only in src
      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