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