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

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

Webmaster