Annotation of libwww/Library/src/HTTimer.c, revision 2.25
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.25 ! kahan 6: ** @(#) $Id: HTTimer.c,v 2.24 1999年02月16日 13:16:55 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.19 frystyk 41: #define CHECKME(timer) if (InTimer != NULL) HTDebugBreak(__FILE__, __LINE__, "\n"); InTimer = timer;
42: #define CLEARME(timer) if (InTimer != timer) HTDebugBreak(__FILE, __LINE__, "\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
100: HTDebugBreak(__FILE__, __LINE__, "Timer dispatch couldn't find a timer\n");
101: #endif
102: CLEARME(timer);
103: return HT_ERROR;
104: }
105: if (timer->repetitive)
106: HTTimer_new(timer, timer->cbf, timer->param, timer->millis, YES, YES);
107: else
108: HTList_quickRemoveElement(cur, last);
109: if (THD_TRACE) HTTrace("Timer....... Dispatch timer %p\n", timer);
110: ret = (*timer->cbf) (timer, timer->param, HTEvent_TIMEOUT);
111: return ret;
112: }
113:
2.9 frystyk 114: PUBLIC BOOL HTTimer_registerSetTimerCallback (HTTimerSetCallback * cbf)
2.4 eric 115: {
2.9 frystyk 116: if (CORE_TRACE) HTTrace("Timer....... registering %p as timer set cbf\n", cbf);
117: if (cbf) {
118: SetPlatformTimer = cbf;
119: return YES;
120: }
121: return NO;
2.4 eric 122: }
123:
2.9 frystyk 124: PUBLIC BOOL HTTimer_registerDeleteTimerCallback (HTTimerSetCallback * cbf)
2.4 eric 125: {
2.9 frystyk 126: if (CORE_TRACE) HTTrace("Timer....... registering %p as timer delete cbf\n", cbf);
127: if (cbf) {
128: DeletePlatformTimer = cbf;
129: return YES;
130: }
131: return NO;
2.10 eric 132: }
133:
2.24 frystyk 134: PUBLIC ms_t HTTimer_expiresRelative (HTTimer * timer)
135: {
136: return timer ? timer->millis : 0;
137: }
138:
139: PUBLIC ms_t HTTimer_expiresAbsolute (HTTimer * timer)
140: {
141: return timer ? timer->expires : 0;
142: }
143:
144: PUBLIC HTTimerCallback * HTTimer_callback (HTTimer * timer)
145: {
146: return timer ? timer->cbf : NULL;
147: }
148:
149: PUBLIC BOOL HTTimer_isRelative (HTTimer * timer)
2.10 eric 150: {
2.24 frystyk 151: return timer ? timer->relative : NO;
2.4 eric 152: }
153:
2.1 frystyk 154: PUBLIC BOOL HTTimer_delete (HTTimer * timer)
155: {
2.3 eric 156: HTList * last;
157: HTList * cur;
2.7 eric 158: CHECKME(timer);
2.23 frystyk 159: if ((cur = HTList_elementOf(Timers, (void *)timer, &last)) == NULL) CLEARME(timer);
2.18 frystyk 160: if (HTList_quickRemoveElement(cur, last)) {
2.23 frystyk 161: if (THD_TRACE) HTTrace("Timer....... Deleted active timer %p\n", timer);
2.18 frystyk 162: } else {
2.23 frystyk 163: if (THD_TRACE) HTTrace("Timer....... Deleted expired timer %p\n", timer);
2.18 frystyk 164: }
2.9 frystyk 165:
166: /*
167: ** Call any platform specific timer handler
168: */
169: if (DeletePlatformTimer) DeletePlatformTimer(timer);
170:
2.7 eric 171: CLEARME(timer);
2.3 eric 172: HT_FREE(timer);
173: return YES;
2.1 frystyk 174: }
175:
176: PUBLIC HTTimer * HTTimer_new (HTTimer * timer, HTTimerCallback * cbf,
2.21 frystyk 177: void * param, ms_t millis, BOOL relative,
178: BOOL repetitive)
2.1 frystyk 179: {
2.7 eric 180: HTList * last;
181: HTList * cur;
2.2 frystyk 182: ms_t now = HTGetTimeInMillis();
2.3 eric 183: ms_t expires;
2.7 eric 184: HTTimer * pres;
2.3 eric 185:
2.7 eric 186: CHECKME(timer);
2.3 eric 187: expires = millis;
2.17 frystyk 188: if (relative)
189: expires += now;
190: else
191: millis = expires-now;
2.3 eric 192:
193: if (Timers == NULL)
194: Timers = HTList_new();
195:
196: if (timer) {
197:
198: /* if a timer is specified, it should already exist
199: */
2.7 eric 200: if ((cur = HTList_elementOf(Timers, (void *)timer, &last)) == NULL) {
2.19 frystyk 201: HTDebugBreak(__FILE__, __LINE__, "Timer %p not found\n", timer);
2.7 eric 202: CLEARME(timer);
2.3 eric 203: return NULL;
2.7 eric 204: }
205: HTList_quickRemoveElement(cur, last);
2.11 frystyk 206: if (THD_TRACE)
207: HTTrace("Timer....... Found timer %p with callback %p, context %p, and %s timeout %d\n",
208: timer, cbf, param, relative ? "relative" : "absolute", millis);
2.7 eric 209: /* could optimize by sorting from last when ((HTList *)(last->object))->expires < expires (most common case) */
2.3 eric 210: } else {
211:
212: /* create a new timer
213: */
2.1 frystyk 214: if ((timer = (HTTimer *) HT_CALLOC(1, sizeof(HTTimer))) == NULL)
2.2 frystyk 215: HT_OUTOFMEM("HTTimer_new");
2.7 eric 216: last = Timers;
2.11 frystyk 217: if (THD_TRACE)
2.21 frystyk 218: HTTrace("Timer....... Created %s timer %p with callback %p, context %p, and %s timeout %d\n",
219: repetitive ? "repetitive" : "one shot",
220: timer, cbf, param,
221: relative ? "relative" : "absolute", millis);
2.1 frystyk 222: }
2.16 frystyk 223:
224: /*
225: ** Sort new element into list
226: */
2.7 eric 227: for (cur = last;
228: (pres = (HTTimer *) HTList_nextObject(cur)) != NULL && pres->expires < expires;
229: last = cur);
2.16 frystyk 230:
231: /*
232: ** If the expiration is 0 then we still register it but dispatch it immediately.
233: */
234: if (!millis) if (THD_TRACE) HTTrace("Timer....... Timeout is 0 - expires NOW\n");
235:
2.3 eric 236: timer->expires = expires;
2.1 frystyk 237: timer->cbf = cbf;
238: timer->param = param;
239: timer->millis = millis;
240: timer->relative = relative;
2.21 frystyk 241: timer->repetitive = repetitive;
2.7 eric 242: SETME(timer);
2.3 eric 243:
244: /*
245: ** add to list if timer is new
246: */
2.7 eric 247: HTList_addObject(last, (void *)timer);
2.9 frystyk 248:
249: /*
250: ** Call any platform specific timer handler
251: */
252: if (SetPlatformTimer) SetPlatformTimer(timer);
253:
2.23 frystyk 254: /* Check if the timer object has already expired. If so then dispatch */
255: if (timer->expires <= now) Timer_dispatch(cur, last);
2.16 frystyk 256:
2.7 eric 257: CLEARME(timer);
2.1 frystyk 258: return timer;
259: }
260:
261:
2.7 eric 262: PUBLIC BOOL HTTimer_refresh (HTTimer * timer, ms_t now)
263: {
2.21 frystyk 264: if (timer == NULL || timer->repetitive == NO)
2.7 eric 265: return NO;
2.21 frystyk 266: if (HTTimer_new(timer, timer->cbf, timer->param, timer->millis, YES, YES) == NULL)
2.7 eric 267: return NO;
268: return YES;
269: }
270:
2.1 frystyk 271: PUBLIC BOOL HTTimer_deleteAll (void)
272: {
2.3 eric 273: HTList * cur = Timers;
274: HTTimer * pres;
275: if (Timers) {
276: while ((pres = (HTTimer *) HTList_nextObject(cur))) {
2.9 frystyk 277:
278: /*
279: ** Call any platform specific timer handler
280: */
281: if (DeletePlatformTimer) DeletePlatformTimer(pres);
2.3 eric 282: HT_FREE(pres);
2.1 frystyk 283: }
2.3 eric 284: HTList_delete(Timers);
285: Timers = NULL;
2.1 frystyk 286: return YES;
287: }
288: return NO;
289: }
290:
2.3 eric 291: PUBLIC int HTTimer_dispatch (HTTimer * timer)
292: {
293: HTList * cur;
294: HTList * last = Timers;
295: cur = HTList_elementOf(Timers, (void *)timer, &last);
2.23 frystyk 296: return Timer_dispatch(cur, last);
2.21 frystyk 297: }
298:
299: /*
300: ** Check if the timer object has already expired
301: */
302: PUBLIC BOOL HTTimer_hasTimerExpired (HTTimer * timer)
303: {
304: return (timer && timer->expires <= HTGetTimeInMillis());
2.1 frystyk 305: }
306:
2.7 eric 307: PUBLIC int HTTimer_next (ms_t * pSoonest)
2.1 frystyk 308: {
2.17 frystyk 309: HTList * cur = Timers;
310: HTList * last = Timers;
2.7 eric 311: HTTimer * pres;
2.3 eric 312: ms_t now = HTGetTimeInMillis();
2.7 eric 313: int ret = HT_OK;
2.3 eric 314:
2.17 frystyk 315: /*
316: ** Dispatch all timers that have expired
317: */
318: while (Timers && (pres = (HTTimer *) HTList_nextObject(cur))) {
319: if (pres->expires <= now) {
2.23 frystyk 320: if ((ret = Timer_dispatch(cur, last)) != HT_OK) break;
2.17 frystyk 321: cur = last = Timers;
322: } else {
323: last = cur;
324: }
325: }
2.3 eric 326:
2.7 eric 327: if (pSoonest) {
328: /*
329: ** First element in Timers is the next to expire.
2.3 eric 330: */
2.8 frystyk 331: HTList * cur = Timers; /* for now */
332: pres = (HTTimer *) HTList_nextObject(cur);
2.7 eric 333: *pSoonest = pres ? pres->expires - now : 0;
2.1 frystyk 334: }
2.7 eric 335: return ret;
2.1 frystyk 336: }
2.12 eric 337:
2.13 frystyk 338: #ifdef WATCH_RECURSION
2.12 eric 339: extern void CheckSockEvent(HTTimer * timer, HTTimerCallback * cbf, void * param);
2.13 frystyk 340: PRIVATE void CheckTimers(void)
2.12 eric 341: {
342: HTList * cur = Timers;
343: HTTimer * pres;
344: while ((pres = (HTTimer *) HTList_nextObject(cur))) {
345: CheckSockEvent(pres, pres->cbf, pres->param);
346: }
347: }
2.13 frystyk 348: #endif
2.25 ! kahan 349:
! 350:
Webmaster