⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rvtimer.c

📁 基于h323协议的软phone
💻 C
📖 第 1 页 / 共 4 页
字号:
    event->id = tqueue->idcounter;
    event->starttime = starttime;
    event->triggerlength = delay;
    event->triggertime = starttime + delay;
    event->canceled = RV_FALSE;
    event->userdata = userdata;
    event->callback = callback;

    /* Add the new event to the Priority Queue. */
    if(RvPQueuePut(&tqueue->pqueue, event) == NULL) {
        RvObjPoolReleaseItem(&tqueue->pool, event);
        RvLockRelease(&tqueue->lock);
        return RvTimerErrorCode(RV_TIMER_ERROR_QUEUEFULL);
    }

    /* Fill in the timer identification information. */
    if(timer != NULL) {
        /* All 4 items guarantee being able to confirm sanity of the timer. */
        timer->event = event;
        timer->tqueue = tqueue;
        timer->starttime = starttime;
        timer->id = event->id;
    }

    RvLockRelease(&tqueue->lock);
    return(RV_OK);
}

/* Cancels the requested timer. If blocking is set to RV_TIMER_CANCEL_BLOCKING, cancel */
/* will block until any callback that is currently in progress has completed. When this */
/* function returns RV_OK the timer is guaranteed to have been canceled. If blocking is */
/* RV_TIMER_CANCEL_NONBLOCKING and a callback is in progress, RV_TIMER_WARNING_BUSY is */
/* returned but future triggers of PERIODIC timers are canceled. If RV_TIMER_WARNING_BUSY */
/* is returned, the cancel may be called again on that timer (with or without blocking). */
/* Do not call this on any timer which has been put on a timer queue that has been deleted. */
/* Also, do not call it with blocking set to RV_TIMER_CANCEL_BLOCKING from that timer's callback. */
RVCOREAPI RvStatus RVCALLCONV RvTimerCancel(RvTimer *timer, RvBool blocking)
{
    RvStatus result;
    RvTimerEvent *event;
    RvTimerQueue *tqueue;

#if defined(RV_NULLCHECK)
    if(timer == NULL)
        return RvTimerErrorCode(RV_ERROR_NULLPTR);
#endif
#if defined(RV_RANGECHECK)
    if((blocking != RV_TRUE) && (blocking != RV_FALSE))
        return RvTimerErrorCode(RV_ERROR_OUTOFRANGE);
#endif

    result = RvLockGet(&timer->tqueue->lock);
    if(result != RV_OK)
        return result;

    event = timer->event;
    tqueue = timer->tqueue;

    /* Check to insure timer event is still valid. */
    if((event->tqueue != tqueue) || (event->starttime != timer->starttime) ||
       (event->id != timer->id) || (event->state == RV_TIMER_EVENTSTATE_NOTINUSE)) {
        /* Timer isn't valid so just say that cancel worked. */
        RvLockRelease(&tqueue->lock);
        return RV_OK;
    }

    if(event->state == RV_TIMER_EVENTSTATE_QUEUED) {
        /* Event is in the Priority Queue, just remove it and return it to the pool. */
        RvPQueueRemove(&tqueue->pqueue, event->index);
        event->state = RV_TIMER_EVENTSTATE_NOTINUSE;
        RvObjPoolReleaseItem(&tqueue->pool, event);
        RvLockRelease(&tqueue->lock);
        return RV_OK;
    }

    /* The event is in the middle of its callback (TRIGGERED state). */

    event->canceled = RV_TRUE; /* Tell periodic timers not to repeat. */

    if(blocking == RV_FALSE) {
        /* Caller does not want to wait for callback completeion. */
        RvLockRelease(&tqueue->lock);
        return RvTimerErrorCode(RV_TIMER_WARNING_BUSY);
    }

    /* Caller wants to wait for timer callback to complete. */
    event->waitcount += 1;
    RvLockRelease(&tqueue->lock);
    result = RvSemaphoreWait(&event->wait);
    RvLockGet(&tqueue->lock);
    event->waitcount -= 1;

    if(event->waitcount == 0) {
        /* We're the last one that was waiting so return the event to the pool. */
        event->state = RV_TIMER_EVENTSTATE_NOTINUSE;
        RvObjPoolReleaseItem(&tqueue->pool, event);

        /* If the timer queue is stopped and we were waiting for the */
        /* last callback, wake up the task that has been waiting for us. */
        if((tqueue->stopped == RV_TRUE) && (tqueue->callcount == 0))
            RvSemaphorePost(&tqueue->wait);
    }

    RvLockRelease(&tqueue->lock);
    return result;
}

/* Returns the resoluion of the clock used by timers. */
RvInt64 RvTimerResolution(void)
{
    return RvTimestampResolution();
}

/* Check the timer queue and execute the next maxevents callbacks if they */
/* should be triggered. Setting maxevents to 0 indicates to execute as many */
/* events as are available. Will return the actual number of events executed */
/* in the numevents parameter. */
RVCOREAPI RvStatus RVCALLCONV RvTimerQueueService(RvTimerQueue *tqueue, RvSize_t maxevents, RvSize_t *numevents)
{
    RvStatus result;
    RvTimerEvent *event;
    RvBool callbackresult;
    RvSize_t i, *eventcount, defaultcount;
    RvInt64 curtime;

#if defined(RV_NULLCHECK)
    if(tqueue == NULL)
        return RvTimerErrorCode(RV_ERROR_NULLPTR);
#endif

    /* If numevents is NULL, we still need a counter. */
    if(numevents != NULL) {
        eventcount = numevents;
    } else eventcount = &defaultcount;

    *eventcount = 0;

    result = RvLockGet(&tqueue->lock);
    if(result != RV_OK)
        return result;

    if(tqueue->stopped == RV_TRUE) {
            /* Queue has been stopped. */
        RvLockRelease(&tqueue->lock);
        return RvTimerErrorCode(RV_TIMER_ERROR_QUEUESTOPPED);
    }

    curtime = RvTimestampGet();

    /* Event processing loop. */
    do {
        /* Check to see if the event at top of the queue should be triggered. */
        event = (RvTimerEvent *)RvPQueuePeek(&tqueue->pqueue);
        if((event == NULL) || (event->triggertime > curtime))
            break; /* No events to trigger. */

        /* Remove that first event and mark it as triggered. */
        RvPQueueRemove(&tqueue->pqueue, event->index); /* Faster than PQueueueGet */
        event->state = RV_TIMER_EVENTSTATE_TRIGGERED;
        *eventcount += 1;

        /* Call the users callback. */
        tqueue->callcount += 1;
        RvLockRelease(&tqueue->lock);
        callbackresult = event->callback(event->userdata);
        result = RvLockGet(&tqueue->lock);
        tqueue->callcount -= 1;

        /* Check to see if event is to be rescheduled. */
        if((event->timertype == RV_TIMER_TYPE_PERIODIC) && (event->canceled == RV_FALSE) &&
           (callbackresult == RV_TRUE) && (tqueue->stopped == RV_FALSE)) {
            /* Reschedule the event */
            event->state = RV_TIMER_EVENTSTATE_QUEUED;
            event->triggertime += event->triggerlength;
            if(RvPQueuePut(&tqueue->pqueue, event) == NULL) {
                /* We can't reschedule, so just clean up the event. */
                event->state = RV_TIMER_EVENTSTATE_NOTINUSE;
                RvObjPoolReleaseItem(&tqueue->pool, event);
                result = RvTimerErrorCode(RV_TIMER_ERROR_QUEUEFULL);
            }
        } else {
            /* Deal with events that are not to be rescheduled. */
            if(event->waitcount > 0) {
                /* Tasks are waiting to cancel this event, notify them. */
                /* They'll have to clean up the event. */
                for(i = 0; i < event->waitcount; i++)
                    RvSemaphorePost(&event->wait);
            } else {
                /* No one waiting so we have to clean up the event. */
                event->state = RV_TIMER_EVENTSTATE_NOTINUSE;
                RvObjPoolReleaseItem(&tqueue->pool, event);

                /* If the timer queue is stopped and we are the last callback, */
                /* wake up the task that might be waiting for us. */
                if((tqueue->stopped == RV_TRUE) && (tqueue->callcount == 0))
                    RvSemaphorePost(&tqueue->wait);
            }
        }

    } while((result == RV_OK) && (tqueue->stopped == RV_FALSE) &&
            ((maxevents == 0) || (*eventcount < maxevents))); /* Do more events? */

    RvLockRelease(&tqueue->lock);
    return result;
}

#if defined(RV_TEST_CODE)
#include "rv64ascii.h"
#include "rvthread.h"
#include "rvstdio.h"
#include <stdlib.h>

#define RvTimerPrintError(_r) RvPrintf("Error %d/%d/%d\n",  RvErrorGetLib((_r)), RvErrorGetModule((_r)), RvErrorGetCode((_r)))

static volatile RvBool exitthread;

static RvBool RvTimerTestCallback(void *userdata)
{
    RvInt64 curtime;
    RvChar timestr[RV_64TOASCII_BUFSIZE];

    curtime = RvTimestampGet();
    Rv64toA(timestr, curtime);
    RvPrintf("Timer Callback at %s, userdata = %p\n", timestr, userdata);
    return RV_TRUE;
}

static RvBool RvTimerTestCallback2(void *userdata)
{
    RvInt64 curtime;
    RvChar timestr[RV_64TOASCII_BUFSIZE];

    curtime = RvTimestampGet();
    Rv64toA(timestr, curtime);
    RvPrintf("Timer Callback at %s, userdata = %p: Delay...\n", timestr, userdata);
    RvThreadNanosleep( (RvInt64)Rv64Multiply(RV_TIME64_NSECPERSEC, RvInt64Const(10)) );
    RvPrintf("Timer Callback complete.\n");
    return RV_TRUE;
}

static void RvTimerTestServiceThread(RvThread *th, void *data)
{
    RvTimerQueue *tqueue;
    RvStatus result;
    RvSize_t  numevents, totalevents;

    result = RV_OK;
    totalevents = 0;
    RvPrintf("Timer Queue Service Task (%p) starting.\n", th);
    tqueue = (RvTimerQueue *)data;
    while((exitthread != RV_TRUE) && (result == RV_OK)){
        result = RvTimerQueueService(tqueue, 0, &numevents);
        if(result != RV_OK) {
            RvPrintf("Thread %p RvTimerQueueService: ", th);
            RvTimerPrintError(result);
        } else totalevents += numevents;
        RvThreadNanosleep( (RvInt64)Rv64Multiply(RV_TIME64_NSECPERMSEC, RvInt64Const(100)) );
    }
    RvPrintf("Timer Queue Sevice Task (%p) Exiting. Total Events = %u\n", th, totalevents);
}

#define RV_TIMER_TEST_NUMTIMERS 25
void RvTimerTest(void)
{
    RvStatus result;
    RvTimerQueue tqueue;
    RvTimer timer1, timer2, *timerarray;
    RvInt64 delay, eventtime;
    RvChar timestr[RV_64TOASCII_BUFSIZE];
    RvSize_t numevents, i, resultsize;
    RvThread th1, th2;
    RvBool bresult;

    RvCCoreInit();

    RvPrintf("RvTimerInit: ");
    result = RvTimerInit();
    if(result != RV_OK) {
        RvTimerPrintError(result);
    } else RvPrintf("OK\n");
    delay = RvTimerResolution();
    Rv64toA(timestr, delay);
    RvPrintf("RvTimerResolution = %s\n", timestr);

    /* Basic tests */
    RvPrintf("RvTimerQueueConstruct(FIXED, 100, 0, 0, 0, 40): ");
    result = RvTimerQueueConstruct(&tqueue, RV_TIMER_QTYPE_FIXED, 100, 0, 0, 0, 40, NULL);
    if(result != RV_OK) {
        RvTimerPrintError(result);
    } else RvPrintf("OK\n");
    RvPrintf("RvTimerQueueNumEvents = %u.\n", RvTimerQueueNumEvents(&tqueue));
    RvPrintf("RvTimerQueueNextEvent = ");
    result = RvTimerQueueNextEvent(&tqueue, &eventtime);
    if(RvErrorGetCode(result) != RV_TIMER_WARNING_QUEUEEMPTY) {
        if(result == RV_OK) {
            Rv64toA(timestr, eventtime);
            RvPrintf("ERROR, returned %s\n", timestr);
        } else RvTimerPrintError(result);
    } else RvPrintf("EMPTY. Correct.\n");
    RvPrintf("size=%u, max=%u, min=%u, freelevel=%u\n", RvTimerQueueGetSize(&tqueue), RvTimerQueueGetMaxtimers(&tqueue), RvTimerQueueGetMintimers(&tqueue), RvTimerQueueGetFreelevel(&tqueue));

    delay = RV_TIME64_NSECPERSEC;
    Rv64toA(timestr, delay);
    RvPrintf("RvTimerStart(ONESHOT, %s): ", timestr);
    result = RvTimerStart(&timer1, &tqueue, RV_TIMER_TYPE_ONESHOT, delay, RvTimerTestCallback, (void *)&timer1);
    if(result == RV_OK) {
        RvPrintf("OK\n");
        Rv64toA(timestr, timer1.starttime);
        RvPrintf("  Timer1: id = %u, starttime  = %s\n", timer1.id, timestr);
    } else RvTimerPrintError(result);

    delay *= RvInt64Const(2);
    Rv64toA(timestr, delay);
    RvPrintf("RvTimerStart(ONESHOT, %s): ", timestr);
    result = RvTimerStart(&timer2, &tqueue, RV_TIMER_TYPE_ONESHOT, delay, RvTimerTestCallback, (void *)&timer2);
    if(result == RV_OK) {
        RvPrintf("OK\n");
        Rv64toA(timestr, timer2.starttime);
        RvPrintf("  Timer2: id = %u, starttime  = %s\n", timer2.id, timestr);
    } else RvTimerPrintError(result);
    RvPrintf("RvTimerQueueNumEvents = %u.\n", RvTimerQueueNumEvents(&tqueue));

    RvPrintf("RvTimerQueueService(0): ");
    result = RvTimerQueueService(&tqueue, 0, &numevents);
    if(result == RV_OK) {
        RvPrintf("OK, numevents = %u\n", numevents);
    } else  RvTimerPrintError(result);

    RvPrintf("RvTimerCancel Timer1 (blocking): ");
    result = RvTimerCancel(&timer1, RV_TIMER_CANCEL_BLOCKING);
    if(result != RV_OK) {
        RvTimerPrintError(result);
    } else RvPrintf("OK\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -