Annotation of libwww/Library/src/HTTimer.c, revision 2.22

2.1       frystyk     1: /*                                                                  HTEvntrg.c
                      2: **     EVENT MANAGER
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.22    ! frystyk     6: **     @(#) $Id: HTTimer.c,v 2.21 1998/05/19 16:49:43 frystyk Exp $
2.1       frystyk     7: **
                      8: **     Updated HTEvent module 
                      9: **     This new module combines the functions of the old HTEvent module and 
                     10: **     the HTThread module. We retain the old HTThread module, but it
                     11: **     consists of calls to the HTEvent interfaces
                     12: **
                     13: ** Authors:
                     14: **     EGP     Eric Prud'hommeaux (eric@w3.org)
                     15: ** Bugs
                     16: **
                     17: */
                     18: 
                     19: /* Implementation dependent include files */
2.20      frystyk    20: #include "wwwsys.h"
2.1       frystyk    21: #include "WWWUtil.h"
                     22: #include "WWWCore.h"
                     23: #include "HTReqMan.h"
                     24: #include "HTTimer.h"                                    /* Implemented here */
                     25: 
                     26: struct _HTTimer {
2.2       frystyk    27:     ms_t       millis;         /* Relative value in millis */
                     28:     ms_t       expires;        /* Absolute value in millis */
2.1       frystyk    29:     BOOL       relative;
2.21      frystyk    30:     BOOL       repetitive;
2.1       frystyk    31:     void *     param;          /* Client supplied context */
                     32:     HTTimerCallback * cbf;
                     33: };
                     34: 
2.3       eric       35: PRIVATE HTList * Timers = NULL;                           /* List of timers */
2.1       frystyk    36: 
2.9       frystyk    37: PRIVATE HTTimerSetCallback * SetPlatformTimer = NULL;
                     38: PRIVATE HTTimerSetCallback * DeletePlatformTimer = NULL;
                     39: 
2.17      frystyk    40: #if 0 /* WATCH_RECURSION */
2.7       eric       41: 
                     42: PRIVATE HTTimer * InTimer = NULL;
2.19      frystyk    43: #define CHECKME(timer) if (InTimer != NULL) HTDebugBreak(__FILE__, __LINE__, "\n"); InTimer = timer;
                     44: #define CLEARME(timer) if (InTimer != timer) HTDebugBreak(__FILE, __LINE__, "\n"); InTimer = NULL;
2.7       eric       45: #define SETME(timer) InTimer = timer;
                     46: 
                     47: #else /* WATCH_RECURSION */
                     48: 
                     49: #define CHECKME(timer)
                     50: #define CLEARME(timer)
                     51: #define SETME(timer)
                     52: 
                     53: #endif /* !WATCH_RECURSION */
2.1       frystyk    54: /* ------------------------------------------------------------------------- */
                     55: 
2.9       frystyk    56: PUBLIC BOOL HTTimer_registerSetTimerCallback (HTTimerSetCallback * cbf)
2.4       eric       57: {
2.9       frystyk    58:     if (CORE_TRACE) HTTrace("Timer....... registering %p as timer set cbf\n", cbf);
                     59:     if (cbf) {
                     60:        SetPlatformTimer = cbf;
                     61:        return YES;
                     62:     }
                     63:     return NO;
2.4       eric       64: }
                     65: 
2.9       frystyk    66: PUBLIC BOOL HTTimer_registerDeleteTimerCallback (HTTimerSetCallback * cbf)
2.4       eric       67: {
2.9       frystyk    68:     if (CORE_TRACE) HTTrace("Timer....... registering %p as timer delete cbf\n", cbf);
                     69:     if (cbf) {
                     70:        DeletePlatformTimer = cbf;
                     71:        return YES;
                     72:     }
                     73:     return NO;
2.10      eric       74: }
                     75: 
                     76: PUBLIC ms_t HTTimer_getTime(HTTimer * timer)
                     77: {
                     78:     if (timer)
                     79:        return timer->millis;
                     80:     return 0;
2.4       eric       81: }
                     82: 
2.1       frystyk    83: PUBLIC BOOL HTTimer_delete (HTTimer * timer)
                     84: {
2.3       eric       85:     HTList * last;
                     86:     HTList * cur;
2.7       eric       87:     CHECKME(timer);
                     88:     if ((cur = HTList_elementOf(Timers, (void *)timer, &last)) == NULL) {
                     89:        CLEARME(timer);
2.3       eric       90:        return NO;
2.7       eric       91:     }
2.18      frystyk    92:     if (HTList_quickRemoveElement(cur, last)) {
2.11      frystyk    93:        if (THD_TRACE) HTTrace("Timer....... Deleted timer %p\n", timer);
2.18      frystyk    94:     } else { 
2.11      frystyk    95:        if (THD_TRACE) HTTrace("Timer....... Could not delete timer %p\n", timer);
2.18      frystyk    96:     }
2.9       frystyk    97: 
                     98:     /*
                     99:     **  Call any platform specific timer handler
                    100:     */
                    101:     if (DeletePlatformTimer) DeletePlatformTimer(timer);
                    102: 
2.7       eric      103:     CLEARME(timer);
2.3       eric      104:     HT_FREE(timer);
                    105:     return YES;
2.1       frystyk   106: }
                    107: 
                    108: PUBLIC HTTimer * HTTimer_new (HTTimer * timer, HTTimerCallback * cbf,
2.21      frystyk   109:                              void * param, ms_t millis, BOOL relative,
                    110:                              BOOL repetitive)
2.1       frystyk   111: {
2.7       eric      112:     HTList * last;
                    113:     HTList * cur;
2.2       frystyk   114:     ms_t now = HTGetTimeInMillis();
2.3       eric      115:     ms_t expires;
2.7       eric      116:     HTTimer * pres;
2.3       eric      117: 
2.7       eric      118:     CHECKME(timer);
2.3       eric      119:     expires = millis;
2.17      frystyk   120:     if (relative)
                    121:        expires += now;
                    122:     else
                    123:        millis = expires-now;
2.3       eric      124: 
                    125:     if (Timers == NULL)
                    126:        Timers = HTList_new();
                    127: 
                    128:     if (timer) {
                    129: 
                    130:        /*      if a timer is specified, it should already exist
                    131:         */
2.7       eric      132:        if ((cur = HTList_elementOf(Timers, (void *)timer, &last)) == NULL) {
2.19      frystyk   133:            HTDebugBreak(__FILE__, __LINE__, "Timer %p not found\n", timer);
2.7       eric      134:            CLEARME(timer);
2.3       eric      135:            return NULL;
2.7       eric      136:        }
                    137:        HTList_quickRemoveElement(cur, last);
2.11      frystyk   138:        if (THD_TRACE)
                    139:            HTTrace("Timer....... Found timer %p with callback %p, context %p, and %s timeout %d\n",
                    140:                    timer, cbf, param, relative ? "relative" : "absolute", millis);
2.7       eric      141:        /* could optimize by sorting from last when ((HTList *)(last->object))->expires < expires (most common case) */
2.3       eric      142:     } else {
                    143: 
                    144:        /*      create a new timer
                    145:         */
2.1       frystyk   146:        if ((timer = (HTTimer *) HT_CALLOC(1, sizeof(HTTimer))) == NULL)
2.2       frystyk   147:            HT_OUTOFMEM("HTTimer_new");
2.7       eric      148:        last = Timers;
2.11      frystyk   149:        if (THD_TRACE)
2.21      frystyk   150:            HTTrace("Timer....... Created %s timer %p with callback %p, context %p, and %s timeout %d\n",
                    151:                    repetitive ? "repetitive" : "one shot",
                    152:                    timer, cbf, param,
                    153:                    relative ? "relative" : "absolute", millis);
2.1       frystyk   154:     }
2.16      frystyk   155: 
                    156:     /*
                    157:     **  Sort new element into list
                    158:     */
2.7       eric      159:     for (cur = last; 
                    160:         (pres = (HTTimer *) HTList_nextObject(cur)) != NULL && pres->expires < expires; 
                    161:         last = cur);
2.16      frystyk   162: 
                    163:     /*
                    164:     **  If the expiration is 0 then we still register it but dispatch it immediately.
                    165:     */
                    166:     if (!millis) if (THD_TRACE) HTTrace("Timer....... Timeout is 0 - expires NOW\n");
                    167: 
2.3       eric      168:     timer->expires = expires;
2.1       frystyk   169:     timer->cbf = cbf;
                    170:     timer->param = param;
                    171:     timer->millis = millis;
                    172:     timer->relative = relative;
2.21      frystyk   173:     timer->repetitive = repetitive;
2.7       eric      174:     SETME(timer);
2.3       eric      175: 
                    176:     /*
                    177:     ** add to list if timer is new
                    178:     */
2.7       eric      179:     HTList_addObject(last, (void *)timer);
2.9       frystyk   180: 
                    181:     /*
                    182:     **  Call any platform specific timer handler
                    183:     */
                    184:     if (SetPlatformTimer) SetPlatformTimer(timer);
                    185: 
2.16      frystyk   186:     /*
                    187:     **  Check if the timer object has already expired
                    188:     */
                    189:     if (timer->expires <= now) {
                    190:        int status;
                    191:        if ((status = (*timer->cbf)(timer, timer->param, HTEvent_TIMEOUT)) != HT_OK) {
                    192:            if (cur) HTList_quickRemoveElement(cur, last);
                    193:            CLEARME(timer);
                    194:            HT_FREE(timer);
                    195:            return NULL;
                    196:        }
                    197:     }
                    198: 
2.7       eric      199:     CLEARME(timer);
2.1       frystyk   200:     return timer;
                    201: }
                    202: 
                    203: 
2.7       eric      204: PUBLIC BOOL HTTimer_refresh (HTTimer * timer, ms_t now)
                    205: {
2.21      frystyk   206:     if (timer == NULL || timer->repetitive == NO)
2.7       eric      207:        return NO;
2.21      frystyk   208:     if (HTTimer_new(timer, timer->cbf, timer->param, timer->millis, YES, YES) == NULL)
2.7       eric      209:        return NO;
                    210:     return YES;
                    211: }
                    212: 
2.1       frystyk   213: PUBLIC BOOL HTTimer_deleteAll (void)
                    214: {
2.3       eric      215:     HTList * cur = Timers;
                    216:     HTTimer * pres;
                    217:     if (Timers) {
                    218:        while ((pres = (HTTimer *) HTList_nextObject(cur))) {
2.9       frystyk   219: 
                    220:            /*
                    221:            **  Call any platform specific timer handler
                    222:            */
                    223:            if (DeletePlatformTimer) DeletePlatformTimer(pres);
2.3       eric      224:            HT_FREE(pres);
2.1       frystyk   225:        }
2.3       eric      226:        HTList_delete(Timers);
                    227:        Timers = NULL;
2.1       frystyk   228:        return YES;
                    229:     }
                    230:     return NO;
                    231: }
                    232: 
                    233: /*
                    234: **  When a timer has expired, we dispatch the event handler and re-register the
                    235: **  timer with the next expiration time.
                    236: */
2.3       eric      237: PRIVATE int Timer_dispatch (HTList * cur, HTList * last, int now)
2.1       frystyk   238: {
2.3       eric      239:     HTTimer * timer;
2.21      frystyk   240:     int ret = HT_ERROR;
2.3       eric      241: 
                    242:     timer = (HTTimer *)HTList_objectOf(cur);
2.7       eric      243:     if (timer == NULL) {
2.22    ! frystyk   244: #if 0
        !           245:         HTDebugBreak(__FILE__, __LINE__, "Timer dispatch couldn't find a timer\n");
        !           246: #endif
        !           247:         CLEARME(timer);
2.3       eric      248:        return HT_ERROR;
2.7       eric      249:     }
2.21      frystyk   250:     if (timer->repetitive)
                    251:        HTTimer_new(timer, timer->cbf, timer->param, timer->millis, YES, YES);
2.3       eric      252:     else
                    253:        HTList_quickRemoveElement(cur, last);
2.1       frystyk   254:     if (THD_TRACE) HTTrace("Timer....... Dispatch timer %p\n", timer);
2.7       eric      255:     ret = (*timer->cbf) (timer, timer->param, HTEvent_TIMEOUT);
2.17      frystyk   256: 
2.21      frystyk   257:     /*
                    258:     ** If not repetitive then call any platform specific timer handler
                    259:     ** and delete the timer
                    260:     */
                    261:     if (!timer->repetitive) {
2.17      frystyk   262:        if (DeletePlatformTimer) DeletePlatformTimer(timer);
2.3       eric      263:        HT_FREE(timer);
2.17      frystyk   264:     }
2.3       eric      265:     return ret;
                    266: }
                    267: 
                    268: PUBLIC int HTTimer_dispatch (HTTimer * timer)
                    269: {
                    270:     HTList * cur;
                    271:     HTList * last = Timers;
                    272:     ms_t now = HTGetTimeInMillis();
                    273: 
                    274:     cur = HTList_elementOf(Timers, (void *)timer, &last);
                    275:     return Timer_dispatch(cur, last, now);
2.21      frystyk   276: }
                    277: 
                    278: /*
                    279: **  Check if the timer object has already expired
                    280: */
                    281: PUBLIC BOOL HTTimer_hasTimerExpired (HTTimer * timer)
                    282: {
                    283:     return (timer && timer->expires <= HTGetTimeInMillis());
2.1       frystyk   284: }
                    285: 
2.7       eric      286: PUBLIC int HTTimer_next (ms_t * pSoonest)
2.1       frystyk   287: {
2.17      frystyk   288:     HTList * cur = Timers;
                    289:     HTList * last = Timers;
2.7       eric      290:     HTTimer * pres;
2.3       eric      291:     ms_t now = HTGetTimeInMillis();
2.7       eric      292:     int ret = HT_OK;
2.3       eric      293: 
2.17      frystyk   294: #if 0
                    295:     if (Timers == NULL) return HT_OK;
2.7       eric      296:     /* The Timers list may be modified during a dispatch
                    297:     ** so we have to build an intermediate list
                    298:     */
                    299:     head = last = HTList_new();
                    300:     cur = Timers;
2.3       eric      301:     while ((pres = (HTTimer *) HTList_nextObject(cur)) && pres->expires <= now) {
2.7       eric      302:        HTList_addObject(last, (void *)pres);
                    303:        last = HTList_nextObject(last);
                    304:     }
                    305: 
                    306:     /*
                    307:     ** Now dispatch the intermediate list
                    308:     */
                    309:     cur = last = head;
                    310:     while ((pres = (HTTimer *) HTList_nextObject(cur)) && ret == HT_OK) {
                    311:        ret = Timer_dispatch(cur, last, now);
2.3       eric      312:        last = cur;
2.2       frystyk   313:     }
2.17      frystyk   314: #else
                    315:     /*
                    316:     **  Dispatch all timers that have expired
                    317:     */
                    318:     while (Timers && (pres = (HTTimer *) HTList_nextObject(cur))) {
                    319:        if (pres->expires <= now) {
                    320:            if ((ret = Timer_dispatch(cur, last, now)) != HT_OK) break;
                    321:            cur = last = Timers;
                    322:        } else {
                    323:            last = cur;
                    324:        }       
                    325:     }
                    326: #endif
2.3       eric      327: 
2.7       eric      328:     if (pSoonest) {
                    329:        /*
                    330:        **      First element in Timers is the next to expire.
2.3       eric      331:        */
2.8       frystyk   332:        HTList * cur = Timers;  /* for now */
                    333:        pres = (HTTimer *) HTList_nextObject(cur);
2.7       eric      334:        *pSoonest = pres ? pres->expires - now : 0;
2.1       frystyk   335:     }
2.7       eric      336:     return ret;
2.1       frystyk   337: }
2.12      eric      338: 
2.13      frystyk   339: #ifdef WATCH_RECURSION
2.12      eric      340: extern void CheckSockEvent(HTTimer * timer, HTTimerCallback * cbf, void * param);
2.13      frystyk   341: PRIVATE void CheckTimers(void)
2.12      eric      342: {
                    343:     HTList * cur = Timers;
                    344:     HTTimer * pres;
                    345:     while ((pres = (HTTimer *) HTList_nextObject(cur))) {
                    346:        CheckSockEvent(pres, pres->cbf, pres->param);
                    347:     }
                    348: }
2.13      frystyk   349: #endif

Webmaster