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