Annotation of libwww/Library/src/HTTimer.c, revision 2.15
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.15 ! frystyk 6: ** @(#) $Id: HTTimer.c,v 2.14 1997年01月29日 16:54:55 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 */
20: #include "sysdep.h"
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;
30: void * param; /* Client supplied context */
31: HTTimerCallback * cbf;
32: };
33:
2.3 eric 34: PRIVATE HTList * Timers = NULL; /* List of timers */
2.1 frystyk 35:
2.9 frystyk 36: PRIVATE HTTimerSetCallback * SetPlatformTimer = NULL;
37: PRIVATE HTTimerSetCallback * DeletePlatformTimer = NULL;
38:
2.7 eric 39: #if 1 /* WATCH_RECURSION */
40:
41: PRIVATE HTTimer * InTimer = NULL;
42: #define CHECKME(timer) if (InTimer != NULL) HTDebugBreak(); InTimer = timer;
43: #define CLEARME(timer) if (InTimer != timer) HTDebugBreak(); InTimer = NULL;
44: #define SETME(timer) InTimer = timer;
45:
46: #else /* WATCH_RECURSION */
47:
48: #define CHECKME(timer)
49: #define CLEARME(timer)
50: #define SETME(timer)
51:
52: #endif /* !WATCH_RECURSION */
2.1 frystyk 53: /* ------------------------------------------------------------------------- */
54:
2.9 frystyk 55: PUBLIC BOOL HTTimer_registerSetTimerCallback (HTTimerSetCallback * cbf)
2.4 eric 56: {
2.9 frystyk 57: if (CORE_TRACE) HTTrace("Timer....... registering %p as timer set cbf\n", cbf);
58: if (cbf) {
59: SetPlatformTimer = cbf;
60: return YES;
61: }
62: return NO;
2.4 eric 63: }
64:
2.9 frystyk 65: PUBLIC BOOL HTTimer_registerDeleteTimerCallback (HTTimerSetCallback * cbf)
2.4 eric 66: {
2.9 frystyk 67: if (CORE_TRACE) HTTrace("Timer....... registering %p as timer delete cbf\n", cbf);
68: if (cbf) {
69: DeletePlatformTimer = cbf;
70: return YES;
71: }
72: return NO;
2.10 eric 73: }
74:
75: PUBLIC ms_t HTTimer_getTime(HTTimer * timer)
76: {
77: if (timer)
78: return timer->millis;
79: return 0;
2.4 eric 80: }
81:
2.1 frystyk 82: PUBLIC BOOL HTTimer_delete (HTTimer * timer)
83: {
2.3 eric 84: HTList * last;
85: HTList * cur;
2.7 eric 86: CHECKME(timer);
87: if ((cur = HTList_elementOf(Timers, (void *)timer, &last)) == NULL) {
2.15 ! frystyk 88: #if 0
! 89: /*
! 90: ** It is not necessarily a bug to not find the timer. If it was
! 91: ** registered with timeout 0 then it was never put into the list
! 92: */
2.7 eric 93: HTDebugBreak();
2.15 ! frystyk 94: #endif
2.7 eric 95: CLEARME(timer);
2.3 eric 96: return NO;
2.7 eric 97: }
2.11 frystyk 98: if (HTList_quickRemoveElement(cur, last))
99: if (THD_TRACE) HTTrace("Timer....... Deleted timer %p\n", timer);
100: else
101: if (THD_TRACE) HTTrace("Timer....... Could not delete timer %p\n", timer);
2.9 frystyk 102:
103: /*
104: ** Call any platform specific timer handler
105: */
106: if (DeletePlatformTimer) DeletePlatformTimer(timer);
107:
2.7 eric 108: CLEARME(timer);
2.3 eric 109: HT_FREE(timer);
110: return YES;
2.1 frystyk 111: }
112:
113: PUBLIC HTTimer * HTTimer_new (HTTimer * timer, HTTimerCallback * cbf,
2.2 frystyk 114: void * param, ms_t millis, BOOL relative)
2.1 frystyk 115: {
2.7 eric 116: HTList * last;
117: HTList * cur;
2.2 frystyk 118: ms_t now = HTGetTimeInMillis();
2.3 eric 119: ms_t expires;
2.7 eric 120: HTTimer * pres;
2.3 eric 121:
2.7 eric 122: CHECKME(timer);
2.3 eric 123: expires = millis;
124: if (relative) expires += now;
125:
126: if (Timers == NULL)
127: Timers = HTList_new();
128:
129: if (timer) {
130:
131: /* if a timer is specified, it should already exist
132: */
2.7 eric 133: if ((cur = HTList_elementOf(Timers, (void *)timer, &last)) == NULL) {
134: HTDebugBreak();
135: CLEARME(timer);
2.3 eric 136: return NULL;
2.7 eric 137: }
138: HTList_quickRemoveElement(cur, last);
2.11 frystyk 139: if (THD_TRACE)
140: HTTrace("Timer....... Found timer %p with callback %p, context %p, and %s timeout %d\n",
141: timer, cbf, param, relative ? "relative" : "absolute", millis);
2.7 eric 142: /* could optimize by sorting from last when ((HTList *)(last->object))->expires < expires (most common case) */
2.3 eric 143: } else {
144:
145: /* create a new timer
146: */
2.1 frystyk 147: if ((timer = (HTTimer *) HT_CALLOC(1, sizeof(HTTimer))) == NULL)
2.2 frystyk 148: HT_OUTOFMEM("HTTimer_new");
2.7 eric 149: last = Timers;
2.11 frystyk 150: if (THD_TRACE)
151: HTTrace("Timer....... Created timer %p with callback %p, context %p, and %s timeout %d\n",
152: timer, cbf, param, relative ? "relative" : "absolute", millis);
2.1 frystyk 153: }
2.7 eric 154: /* sort new element into list
155: */
156: for (cur = last;
157: (pres = (HTTimer *) HTList_nextObject(cur)) != NULL && pres->expires < expires;
158: last = cur);
2.14 frystyk 159: if (!millis) {
160: if (THD_TRACE) HTTrace("Timer....... Timeout is 0 - returning\n");
161: return timer;
162: }
2.3 eric 163: timer->expires = expires;
2.1 frystyk 164: timer->cbf = cbf;
165: timer->param = param;
166: timer->millis = millis;
167: timer->relative = relative;
2.7 eric 168: SETME(timer);
2.3 eric 169: /* may already be obsolete
170: */
2.1 frystyk 171: if (timer->expires <= now) {
172: int status;
2.7 eric 173: if ((status = (*timer->cbf)(timer, timer->param, HTEvent_TIMEOUT)) != HT_OK) {
2.3 eric 174: if (cur)
175: HTList_quickRemoveElement(cur, last);
176: HT_FREE(timer);
2.7 eric 177: CLEARME(timer);
2.1 frystyk 178: return NULL;
179: }
180: }
2.3 eric 181:
182: /*
183: ** add to list if timer is new
184: */
2.7 eric 185: HTList_addObject(last, (void *)timer);
2.9 frystyk 186:
187: /*
188: ** Call any platform specific timer handler
189: */
190: if (SetPlatformTimer) SetPlatformTimer(timer);
191:
2.7 eric 192: CLEARME(timer);
2.1 frystyk 193: return timer;
194: }
195:
196:
2.7 eric 197: PUBLIC BOOL HTTimer_refresh (HTTimer * timer, ms_t now)
198: {
199: if (timer == NULL || timer->relative == NO)
200: return NO;
201: if (HTTimer_new(timer, timer->cbf, timer->param, timer->millis, YES) == NULL)
202: return NO;
203: return YES;
204: }
205:
2.1 frystyk 206: PUBLIC BOOL HTTimer_deleteAll (void)
207: {
2.3 eric 208: HTList * cur = Timers;
209: HTTimer * pres;
210: if (Timers) {
211: while ((pres = (HTTimer *) HTList_nextObject(cur))) {
2.9 frystyk 212:
213: /*
214: ** Call any platform specific timer handler
215: */
216: if (DeletePlatformTimer) DeletePlatformTimer(pres);
2.3 eric 217: HT_FREE(pres);
2.1 frystyk 218: }
2.3 eric 219: HTList_delete(Timers);
220: Timers = NULL;
2.1 frystyk 221: return YES;
222: }
223: return NO;
224: }
225:
226: /*
227: ** When a timer has expired, we dispatch the event handler and re-register the
228: ** timer with the next expiration time.
229: */
2.3 eric 230: PRIVATE int Timer_dispatch (HTList * cur, HTList * last, int now)
2.1 frystyk 231: {
2.3 eric 232: HTTimer * timer;
233: int ret;
234:
235: timer = (HTTimer *)HTList_objectOf(cur);
2.7 eric 236: if (timer == NULL) {
237: HTDebugBreak();
238: CLEARME(timer);
2.3 eric 239: return HT_ERROR;
2.7 eric 240: }
2.1 frystyk 241: if (timer->relative)
242: HTTimer_new(timer, timer->cbf, timer->param, timer->millis, YES);
2.3 eric 243: else
244: HTList_quickRemoveElement(cur, last);
2.1 frystyk 245: if (THD_TRACE) HTTrace("Timer....... Dispatch timer %p\n", timer);
2.7 eric 246: /* CHECKME(timer); all entries to this function are now re-entry save */
247: ret = (*timer->cbf) (timer, timer->param, HTEvent_TIMEOUT);
248: /* CLEARME(timer); */
2.3 eric 249: if (!timer->relative)
250: HT_FREE(timer);
251: return ret;
252: }
253:
254: PUBLIC int HTTimer_dispatch (HTTimer * timer)
255: {
256: HTList * cur;
257: HTList * last = Timers;
258: ms_t now = HTGetTimeInMillis();
259:
260: cur = HTList_elementOf(Timers, (void *)timer, &last);
261: return Timer_dispatch(cur, last, now);
2.1 frystyk 262: }
263:
2.7 eric 264: PUBLIC int HTTimer_next (ms_t * pSoonest)
2.1 frystyk 265: {
2.7 eric 266: HTList * cur;
267: HTList * last;
268: HTTimer * pres;
2.3 eric 269: ms_t now = HTGetTimeInMillis();
2.7 eric 270: int ret = HT_OK;
271: HTList * head;
2.3 eric 272:
273: if (Timers == NULL)
2.7 eric 274: return HT_OK;
2.3 eric 275:
2.7 eric 276: /* The Timers list may be modified during a dispatch
277: ** so we have to build an intermediate list
278: */
279: head = last = HTList_new();
280: cur = Timers;
2.3 eric 281: while ((pres = (HTTimer *) HTList_nextObject(cur)) && pres->expires <= now) {
2.7 eric 282: HTList_addObject(last, (void *)pres);
283: last = HTList_nextObject(last);
284: }
285:
286: /*
287: ** Now dispatch the intermediate list
288: */
289: cur = last = head;
290: while ((pres = (HTTimer *) HTList_nextObject(cur)) && ret == HT_OK) {
291: ret = Timer_dispatch(cur, last, now);
2.3 eric 292: last = cur;
2.2 frystyk 293: }
2.3 eric 294:
2.7 eric 295: if (pSoonest) {
296: /*
297: ** First element in Timers is the next to expire.
2.3 eric 298: */
2.8 frystyk 299: HTList * cur = Timers; /* for now */
300: pres = (HTTimer *) HTList_nextObject(cur);
2.7 eric 301: *pSoonest = pres ? pres->expires - now : 0;
2.1 frystyk 302: }
2.7 eric 303: HTList_delete(head);
304: return ret;
2.1 frystyk 305: }
2.12 eric 306:
2.13 frystyk 307: #ifdef WATCH_RECURSION
2.12 eric 308: extern void CheckSockEvent(HTTimer * timer, HTTimerCallback * cbf, void * param);
2.13 frystyk 309: PRIVATE void CheckTimers(void)
2.12 eric 310: {
311: HTList * cur = Timers;
312: HTTimer * pres;
313: while ((pres = (HTTimer *) HTList_nextObject(cur))) {
314: CheckSockEvent(pres, pres->cbf, pres->param);
315: }
316: }
2.13 frystyk 317: #endif
Webmaster