?? rvtimer.c
字號:
/***********************************************************************
Filename : rvtimer.c
Description: timer functions
************************************************************************
Copyright (c) 2001 RADVISION Inc. and RADVISION Ltd.
************************************************************************
NOTICE:
This document contains information that is confidential and proprietary
to RADVISION Inc. and RADVISION Ltd.. No part of this document may be
reproduced in any form whatsoever without written prior approval by
RADVISION Inc. or RADVISION Ltd..
RADVISION Inc. and RADVISION Ltd. reserve the right to revise this
publication and make changes without obligation to notify any person of
such revisions or changes.
***********************************************************************/
#include "rvtimer.h"
#include "rvtimestamp.h"
/* Internal timer structure containing information for each event. */
struct RvTimerEvent_s {
RvInt timertype; /* Type of timer event (ONESHOT or PERIODIC). */
RvTimerQueue *tqueue; /* Timer queue that event was placed on. */
RvInt state; /* Current state. */
RvUint id; /* id number of event, used for sanity check. */
RvInt64 starttime; /* timestamp at start time, used for sanity check. */
RvInt64 triggerlength; /* How long from starttime until timer should trigger. */
RvInt64 triggertime; /* Time at which event should be triggered. */
RvBool canceled; /* Set to RV_TRUE when canceled so PERIODIC timers won't repeat. */
RvSemaphore wait; /* Used to block tasks waiting to cancel the event. */
RvSize_t waitcount; /* Number of tasks waiting to cancel the event. */
RvObjPoolElement element; /* Required for using object in pool. */
RvSize_t index; /* Index of event in Priority Queue. */
void *userdata; /* User data to be passed into event callback. */
RvTimerFunc callback; /* User callback to be called upon event. */
}; /* typedef RvTimerEvent in header file */
/* Timer event states. */
#define RV_TIMER_EVENTSTATE_NOTINUSE RvIntConst(0)
#define RV_TIMER_EVENTSTATE_QUEUED RvIntConst(1)
#define RV_TIMER_EVENTSTATE_TRIGGERED RvIntConst(2)
/* Lets make error codes a little easier to type */
#define RvTimerErrorCode(_e) RvErrorCode(RV_ERROR_LIBCODE_CBASE, RV_CBASE_MODULE_TIMER, (_e))
static void *RvTimerEventConstruct(void *objptr, void *data);
static void RvTimerEventDestruct(void *objptr, void *data);
static void *RvTimerMemAlloc(RvSize_t size, void *data);
static void RvTimerMemFree(void *ptr, void *data);
static RvBool RvTimerPQueueItemCmp(void *ptr1, void *ptr2);
static void RvTimerPQueueNewIndex(void *item, RvSize_t index);
RvStatus RvTimerInit(void)
{
return RV_OK;
}
RvStatus RvTimerEnd(void)
{
return RV_OK;
}
/* tqtype: type of queue (see header file) */
/* starttimers: number of timers to start with in the pool. */
/* maxtimers: number of timers never to exceed this value (not used for FIXED) */
/* mintimers: number of timers never to go below this value (same as starttimers for FIXED) */
/* freelevel: percentage (0-100) of free timers to maintain (DYNAMIC only) */
/* pagetimers: number of timers per memory page in pool. */
/* memregion: memory region to allocate all needed memory from. */
RVCOREAPI RvStatus RVCALLCONV RvTimerQueueConstruct(RvTimerQueue *tqueue, RvInt tqtype, RvSize_t starttimers, RvSize_t maxtimers, RvSize_t mintimers, RvSize_t freelevel, RvSize_t pagetimers, RvMemory *memregion)
{
RvStatus result;
RvTimerEvent timerevent;
RvObjPoolFuncs poolcallbacks;
RvPQueueFuncs pqueuecallbacks;
RvSize_t startevents;
RvInt32 pooltype;
RvInt pqueuetype;
RvBool salvage;
RvSize_t numtimers;
#if defined(RV_NULLCHECK)
if(tqueue == NULL)
return RvTimerErrorCode(RV_ERROR_NULLPTR);
#endif
result = RvLockConstruct(&tqueue->lock);
if(result != RV_OK)
return result;
result = RvSemaphoreConstruct(&tqueue->wait, 0);
if(result != RV_OK){
RvLockDestruct(&tqueue->lock);
return result;
}
/* Set up pool and pqueue types based on timer queue type */
switch(tqtype) {
case RV_TIMER_QTYPE_FIXED: pooltype = RV_OBJPOOL_TYPE_FIXED;
pqueuetype = RV_PQUEUE_TYPE_FIXED;
salvage = RV_OBJPOOL_SALVAGE_NEVER; /* save space */
break;
case RV_TIMER_QTYPE_EXPANDING: pooltype = RV_OBJPOOL_TYPE_EXPANDING;
pqueuetype = RV_PQUEUE_TYPE_EXPANDING;
salvage = RV_OBJPOOL_SALVAGE_NEVER; /* save space */
break;
case RV_TIMER_QTYPE_DYNAMIC: pooltype = RV_OBJPOOL_TYPE_DYNAMIC;
pqueuetype = RV_PQUEUE_TYPE_DYNAMIC;
salvage = RV_OBJPOOL_SALVAGE_ALLOWED; /* required */
break;
default: RvSemaphoreDestruct(&tqueue->wait);
RvLockDestruct(&tqueue->lock);
return RvTimerErrorCode(RV_ERROR_OUTOFRANGE);
}
/* Contruct pool of events */
poolcallbacks.objconstruct = RvTimerEventConstruct;
poolcallbacks.objdestruct = RvTimerEventDestruct;
poolcallbacks.pagealloc = RvTimerMemAlloc;
poolcallbacks.pagefree = RvTimerMemFree;
poolcallbacks.objconstructdata = tqueue; /* tqueue Never changes so set it upon construction. */
poolcallbacks.objdestructdata = NULL;
poolcallbacks.pageallocdata = memregion;
poolcallbacks.pagefreedata = memregion;
if(RvObjPoolConstruct(&tqueue->pool, &timerevent, &timerevent.element, &poolcallbacks, sizeof(RvTimerEvent), pagetimers, 0, pooltype, salvage, maxtimers, mintimers, freelevel) == NULL) {
RvSemaphoreDestruct(&tqueue->wait);
RvLockDestruct(&tqueue->lock);
return RvTimerErrorCode(RV_TIMER_ERROR_POOL);
}
/* Create starting number of events in pool */
if(starttimers > RvObjPoolTotalItems(&tqueue->pool)) {
numtimers = starttimers - RvObjPoolTotalItems(&tqueue->pool);
if(RvObjPoolAddItems(&tqueue->pool, numtimers) < numtimers) {
RvObjPoolDestruct(&tqueue->pool);
RvSemaphoreDestruct(&tqueue->wait);
RvLockDestruct(&tqueue->lock);
return RvTimerErrorCode(RV_TIMER_ERROR_POOL);
}
}
/* Construct Priority Queue for events (minimum size is 2). */
startevents = RvObjPoolTotalItems(&tqueue->pool); /* start with pool & queue in sync */
if(startevents < 2)
startevents = 2;
pqueuecallbacks.memalloc = RvTimerMemAlloc;
pqueuecallbacks.memfree = RvTimerMemFree;
pqueuecallbacks.itemcmp = RvTimerPQueueItemCmp;
pqueuecallbacks.newindex = RvTimerPQueueNewIndex;
pqueuecallbacks.memallocdata = memregion;
pqueuecallbacks.memfreedata = memregion;
if(RvPQueueConstruct(&tqueue->pqueue, pqueuetype, startevents, &pqueuecallbacks) == NULL) {
RvObjPoolDestruct(&tqueue->pool);
RvSemaphoreDestruct(&tqueue->wait);
RvLockDestruct(&tqueue->lock);
return RvTimerErrorCode(RV_TIMER_ERROR_PQUEUE);
}
/* clear id number counter */
tqueue->idcounter = RvUintConst(0);
tqueue->callcount = 0;
tqueue->stopped = RV_FALSE;
return RV_OK;
}
/* This will stop all further operation of the timer queue. */
/* It will block until all callbacks currently in progress have */
/* completed and will not allow any further events to be processed. */
/* This should only be called once for each timer queue. */
RvStatus RvTimerQueueStop(RvTimerQueue *tqueue)
{
RvStatus result;
#if defined(RV_NULLCHECK)
if(tqueue == NULL)
return RvTimerErrorCode(RV_ERROR_NULLPTR);
#endif
result = RvLockGet(&tqueue->lock);
if(result != RV_OK)
return result;
if(tqueue->stopped == RV_TRUE) {
/* Already stopped, no harm done just report it. */
RvLockRelease(&tqueue->lock);
return RvTimerErrorCode(RV_TIMER_ERROR_QUEUESTOPPED);
}
tqueue->stopped = RV_TRUE;
/* First see if we have to wait for callbacks to complete. */
if(tqueue->callcount > 0) {
/* Wait until callbacks complete. */
RvLockRelease(&tqueue->lock);
result = RvSemaphoreWait(&tqueue->wait);
return RV_OK; /* We don't need to do anything else. */
}
RvLockRelease(&tqueue->lock);
return RV_OK;
}
/* Returns the current number event events waiting in the timer queue. */
RvSize_t RvTimerQueueNumEvents(RvTimerQueue *tqueue)
{
RvSize_t qsize;
#if defined(RV_NULLCHECK)
if(tqueue == NULL)
return 0;
#endif
if(RvLockGet(&tqueue->lock) != RV_OK)
return 0;
qsize = RvPQueueNumItems(&tqueue->pqueue);
RvLockRelease(&tqueue->lock);
return qsize;
}
/* Returns the current size of the timer queue. Note that this is */
/* the size of the timer pool and that the the size of the priority */
/* queue may be different since, for efficiency, they are not kept */
/* in sync except in the case of a FIXED queue. */
RVCOREAPI RvSize_t RVCALLCONV RvTimerQueueGetSize(RvTimerQueue *tqueue)
{
RvSize_t poolsize;
#if defined(RV_NULLCHECK)
if(tqueue == NULL)
return 0;
#endif
if(RvLockGet(&tqueue->lock) != RV_OK)
return 0;
poolsize = RvObjPoolTotalItems(&tqueue->pool);
RvLockRelease(&tqueue->lock);
return poolsize;
}
/* Changes the current size of the timer queue. The size may */
/* only be increased. The additional amount is added to the */
/* pool and to the priority queue. The new value will be returned */
/* and may be larger than the requested size based on page round-off. */
/* Changes are subject to the constraints of the maxtimers and */
/* mintimers settings. */
RvSize_t RvTimerQueueSetSize(RvTimerQueue *tqueue, RvSize_t newsize)
{
RvSize_t poolsize, newqsize, newitems, result;
#if defined(RV_NULLCHECK)
if(tqueue == NULL)
return 0;
#endif
if(RvLockGet(&tqueue->lock) != RV_OK)
return 0;
poolsize = RvObjPoolTotalItems(&tqueue->pool);
if(newsize <= poolsize) {
RvLockRelease(&tqueue->lock);
return poolsize;
}
newitems = newsize - poolsize;
newqsize = newsize;
if(newqsize < 2)
newqsize = 2; /* minimum size of priority queue. */
/* Ajdust the size of the priority queue. */
if(RvPQueueChangeSize(&tqueue->pqueue, newqsize) != newqsize) {
RvLockRelease(&tqueue->lock);
return poolsize;
}
/* Add the items to the timer pool. */
RvObjPoolAddItems(&tqueue->pool, newitems);
result = RvObjPoolTotalItems(&tqueue->pool);
RvLockRelease(&tqueue->lock);
return result;
}
/* Adds to the current size of the timer queue. The amount is added */
/* to the pool and to the priority queue. The actual amount will be */
/* returned and may be larger than the requested size based on page */
/* round-off. Changes are subject to the constraints of the maxtimers */
/* and mintimers settings. */
RVCOREAPI RvSize_t RVCALLCONV RvTimerQueueAddSize(RvTimerQueue *tqueue, RvSize_t addsize)
{
RvSize_t poolsize, newqsize, result;
#if defined(RV_NULLCHECK)
if(tqueue == NULL)
return 0;
#endif
if(RvLockGet(&tqueue->lock) != RV_OK)
return 0;
poolsize = RvObjPoolTotalItems(&tqueue->pool);
newqsize = poolsize + addsize;
if(newqsize < 2)
newqsize = 2; /* minimum size of priority queue. */
/* Ajdust the size of the priority queue. */
if(RvPQueueChangeSize(&tqueue->pqueue, newqsize) != newqsize) {
RvLockRelease(&tqueue->lock);
return poolsize;
}
/* Add the items to the timer pool. */
RvObjPoolAddItems(&tqueue->pool, addsize);
result = RvObjPoolTotalItems(&tqueue->pool) - poolsize;
RvLockRelease(&tqueue->lock);
return result;
}
/* Returns current value for maxtimers (not used by FIXED queues) */
RvSize_t RvTimerQueueGetMaxtimers(RvTimerQueue *tqueue)
{
RvSize_t maxtimers;
#if defined(RV_NULLCHECK)
if(tqueue == NULL)
return 0;
#endif
if(RvLockGet(&tqueue->lock) != RV_OK)
return 0;
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -