/*---------------------------------------------------------------------------*
* ptimer.c *
* *
* Copyright 2007, 2008 Nuance Communciations, Inc. *
* *
* Licensed under the Apache License, Version 2.0 (the 'License'); *
* you may not use this file except in compliance with the License. *
* *
* You may obtain a copy of the License at *
* http://www.apache.org/licenses/LICENSE-2.0 *
* *
* Unless required by applicable law or agreed to in writing, software *
* distributed under the License is distributed on an 'AS IS' BASIS, *
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
* See the License for the specific language governing permissions and *
* limitations under the License. *
* *
*---------------------------------------------------------------------------*/
#include "pmemory.h"
#include "ptimer.h"
#include "pmutex.h"
#ifdef _WIN32
/*
Note that this implementation assumes that QueryPerformanceCounter is
available (requires NT 3.1 and above) and that 64 bit arithmetic is
available (requires VC)
*/
struct PTimer_t
{
LARGE_INTEGER PerformanceFreq;
LARGE_INTEGER RefTime;
LARGE_INTEGER elapsed;
};
/**
* Creates a new timer object.
**/
ESR_ReturnCode PTimerCreate(PTimer **timer)
{
PTimer *tmp = NULL;
if (timer == NULL)
return ESR_INVALID_ARGUMENT;
tmp = NEW(PTimer, "PTimer");
if (tmp == NULL)
return ESR_OUT_OF_MEMORY;
if (QueryPerformanceFrequency(&tmp->PerformanceFreq) == 0)
{
FREE(tmp);
return ESR_NOT_SUPPORTED;
}
tmp->PerformanceFreq.QuadPart /= 1000;
tmp->RefTime.QuadPart = 0;
tmp->elapsed.QuadPart = 0;
*timer = tmp;
return ESR_SUCCESS;
}
ESR_ReturnCode PTimerDestroy(PTimer *timer)
{
if (timer == NULL) return ESR_INVALID_ARGUMENT;
FREE(timer);
return ESR_SUCCESS;
}
/**
* Starts the timer. This sets the reference time from which all new elapsed
* time are computed. This does not reset the elapsed time to 0. This is
* useful to pause the timer.
**/
ESR_ReturnCode PTimerStart(PTimer *timer)
{
if (timer == NULL) return ESR_INVALID_ARGUMENT;
return (QueryPerformanceCounter(&timer->RefTime) ?
ESR_SUCCESS :
ESR_NOT_SUPPORTED);
}
/**
* Stops the timer.
**/
ESR_ReturnCode PTimerStop(PTimer *timer)
{
if (timer == NULL) return ESR_INVALID_ARGUMENT;
if (timer->RefTime.QuadPart != 0)
{
LARGE_INTEGER now;
if (!QueryPerformanceCounter(&now)) return ESR_NOT_SUPPORTED;
timer->elapsed.QuadPart += now.QuadPart - timer->RefTime.QuadPart;
timer->RefTime.QuadPart = 0;
}
return ESR_SUCCESS;
}
/**
* Returns the timer elapsed time. If the Timer is in the stopped state,
* successive calls to getElapsed() will always return the same value. If
* the Timer is in the started state, successive calls will return the
* elapsed time since the last time PTimerStart() was called.
*/
ESR_ReturnCode PTimerGetElapsed(PTimer *timer, asr_uint32_t* elapsed)
{
if (timer == NULL || elapsed == NULL)
return ESR_INVALID_ARGUMENT;
if (timer->RefTime.QuadPart != 0)
{
LARGE_INTEGER now;
if (!QueryPerformanceCounter(&now)) return ESR_NOT_SUPPORTED;
*elapsed = (asr_uint32_t) ((timer->elapsed.QuadPart + (now.QuadPart - timer->RefTime.QuadPart))
/ timer->PerformanceFreq.QuadPart);
}
else
*elapsed = (asr_uint32_t) (timer->elapsed.QuadPart / timer->PerformanceFreq.QuadPart);
return ESR_SUCCESS;
}
/**
* Resets the elapsed time to 0 and resets the reference time of the Timer.
* This effectively reset the timer in the same state it was right after creation.
**/
ESR_ReturnCode PTimerReset(PTimer *timer)
{
if (timer == NULL) return ESR_INVALID_ARGUMENT;
timer->RefTime.QuadPart = 0;
timer->elapsed.QuadPart = 0;
return ESR_SUCCESS;
}
#elif defined(POSIX)
#include "ptrd.h"
/*
POSIX has a timer
*/
/* Clocks and timers: clock_settime, clock_gettime, clock_getres, timer_xxx and nanosleep */
#ifndef _POSIX_TIMERS
#ifndef __vxworks /* __vxworks does not define it! */
#error "Timer is not defined!"
#endif /* __vxworks */
#endif /* _POSIX_TIMERS */
#define TIMER_MAX_VAL 10000
struct PTimer_t
{
timer_t timer;
asr_uint32_t elapsed;
};
/**
* Creates a new timer object.
**/
ESR_ReturnCode PTimerCreate(PTimer **timer)
{
PTimer *tmp = NULL;
if (timer == NULL) return ESR_INVALID_ARGUMENT;
tmp = NEW(PTimer, "PTimer");
if (tmp == NULL) return ESR_OUT_OF_MEMORY;
*timer = tmp;
if (timer_create(CLOCK_REALTIME, NULL, &(tmp->timer)) < 0)
return ESR_NOT_SUPPORTED;
return ESR_SUCCESS;
}
ESR_ReturnCode PTimerDestroy(PTimer *timer)
{
if (timer == NULL) return ESR_INVALID_ARGUMENT;
timer_delete(timer->timer);
FREE(timer);
return ESR_SUCCESS;
}
/**
* Starts the timer. This sets the reference time from which all new elapsed
* time are computed. This does not reset the elapsed time to 0. This is
* useful to pause the timer.
**/
ESR_ReturnCode PTimerStart(PTimer *timer)
{
struct itimerspec expire_time;
if (timer == NULL) return ESR_INVALID_ARGUMENT;
expire_time.it_value.tv_sec = TIMER_MAX_VAL; /* set a large time for the timer */
expire_time.it_value.tv_nsec = 0;
return (timer_settime(timer->timer, 0, &expire_time, NULL) == 0 ?
ESR_SUCCESS :
ESR_NOT_SUPPORTED);
}
/**
* Stops the timer.
**/
ESR_ReturnCode PTimerStop(PTimer *timer)
{
struct itimerspec remaining;
if (timer == NULL) return ESR_INVALID_ARGUMENT;
if (timer_gettime(timer->timer, &remaining) != 0) return ESR_NOT_SUPPORTED;
#if defined(__vxworks)
timer_cancel(timer->timer);
#endif
timer->elapsed = (asr_uint32_t) ((TIMER_MAX_VAL - remaining.it_value.tv_sec) * SECOND2MSECOND
- remaining.it_value.tv_nsec / MSECOND2NSECOND);
return ESR_SUCCESS;
}
/**
* Returns the timer elapsed time. If the Timer is in the stopped state,
* successive calls to getElapsed() will always return the same value. If
* the Timer is in the started state, successive calls will return the
* elapsed time since the last time PTimerStart() was called.
*/
ESR_ReturnCode PTimerGetElapsed(PTimer *timer, asr_uint32_t* elapsed)
{
if (timer == NULL || elapsed == NULL)
return ESR_INVALID_ARGUMENT;
if (timer->elapsed == 0) /* stop is not called */
{
struct itimerspec remaining;
if (timer_gettime(timer->timer, &remaining) != 0) return ESR_NOT_SUPPORTED;
*elapsed = (asr_uint32_t) ((TIMER_MAX_VAL - remaining.it_value.tv_sec) * SECOND2MSECOND
- remaining.it_value.tv_nsec / MSECOND2NSECOND);
}
else
*elapsed = timer->elapsed;
return ESR_SUCCESS;
}
/**
* Resets the elapsed time to 0 and resets the reference time of the Timer.
* This effectively reset the timer in the same state it was right after creation.
**/
ESR_ReturnCode PTimerReset(PTimer *timer)
{
if (timer == NULL) return ESR_INVALID_ARGUMENT;
timer->elapsed = 0;
return ESR_SUCCESS;
}
#else
#error "Ptimer not implemented for this platform."
#endif