Annotation of libwww/Library/src/HTEvtLst.c, revision 1.1.2.5
1.1.2.1 eric 1: /* HTEvntrg.c
2: ** EVENT MANAGER
3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1.2.5 ! frystyk 6: ** @(#) $Id: HTEvtLst.c,v 1.1.2.4 1996/11/08 19:49:27 eric Exp $
1.1.2.1 eric 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: ** HFN Henrik Frystyk <frystyk@w3.org>
15: ** CLB Charlie Brooks <cbrooks@osf.org>
16: ** Bugs
17: **
18: */
19:
20: /* WSAAsyncSelect and windows app stuff need the following definitions:
21: * WWW_WIN_ASYNC - enable WSAAsyncSelect instead of select
22: * _WIN23 - win32 libararies - may be window or console app
23: * _WINSOCKAPI_ - using WINSOCK.DLL - not necessarily the async routines.
24: * _CONSOLE - the console app for NT
25: *
26: * first pass: EGP - 10/26/95
27: */
28:
29: /* Implementation dependent include files */
30: #include "sysdep.h"
31: #include "WWWUtil.h"
32: #include "WWWCore.h"
33: #include "HTReqMan.h"
34: #include "HTEvtLst.h" /* Implemented here */
35:
36: /* Type definitions and global variables etc. local to this module */
1.1.2.5 ! frystyk 37: #define PRIME_TABLE_SIZE 67
! 38: #define MILLI_PER_SECOND 1000
! 39: #define HASH(s) ((s) % PRIME_TABLE_SIZE)
1.1.2.1 eric 40:
1.1.2.5 ! frystyk 41: typedef struct _HTTimer HTTimer;
! 42: struct _HTTimer {
! 43: HTTimer * next; /* The next guy in line */
! 44: int expires; /* Abs value in millis */
! 45: HTEvent * event; /* What to do */
! 46: SOCKET s; /* @@@ why do we need socket? */
! 47: };
1.1.2.1 eric 48:
49: typedef struct rq_t RQ;
1.1.2.5 ! frystyk 50: struct rq_t {
! 51: RQ * next ;
! 52: SOCKET s ; /* our socket */
! 53: BOOL unregister; /* notify app when completely unregistered */
! 54: HTEvent * events[3]; /* event parameters for read, write, oob */
! 55: HTTimer * timeouts[3]; /* timeout for each of the events */
1.1.2.1 eric 56: };
57:
1.1.2.5 ! frystyk 58: typedef enum _RQ_action {
! 59: RQ_mayCreate,
! 60: RQ_find
! 61: } RQ_action;
1.1.2.1 eric 62:
63: PRIVATE RQ * table[PRIME_TABLE_SIZE];
1.1.2.5 ! frystyk 64: PRIVATE SOCKET max_sock = 0 ; /* max socket value in use */
1.1.2.1 eric 65:
1.1.2.5 ! frystyk 66: PRIVATE fd_set FdArray[HTEvent_TYPES];
! 67: PRIVATE fd_set all_fds ; /* any descriptor at all */
1.1.2.1 eric 68:
1.1.2.5 ! frystyk 69: PRIVATE HTTimer * timers = NULL; /* List of timers */
! 70:
! 71: PRIVATE int HTEndLoop = 0; /* If !0 then exit event loop */
! 72:
! 73: /* ------------------------------------------------------------------------- */
1.1.2.1 eric 74:
75: PRIVATE RQ * RQ_get(SOCKET s, RQ_action action)
76: {
77: RQ * rqp;
78: RQ * last = NULL;
79: long v = HASH(s);
80: for (rqp = table[v]; rqp; rqp = rqp->next) {
81: if (rqp->s == s) {
82: return rqp;
83: }
84: last = rqp; /* to set next pointer when creating new */
85: }
86: if (action == RQ_mayCreate) {
87: if ((rqp = (RQ *) HT_CALLOC(1, sizeof(RQ))) == NULL)
88: HT_OUTOFMEM("HTEventList_register");
89: if (last) last->next = rqp;
90: else table[v] = rqp;
91: rqp->s = s;
92: return rqp;
93: }
94: return NULL;
95: }
96:
1.1.2.5 ! frystyk 97: /*
! 98: ** A simple debug function that dumps all the socket arrays
! 99: ** as trace messages
1.1.2.1 eric 100: */
1.1.2.5 ! frystyk 101: PRIVATE void __DumpFDSet( fd_set * fdp, const char * str)
1.1.2.1 eric 102: {
1.1.2.5 ! frystyk 103: SOCKET s ;
! 104: #ifdef _WINSOCKAPI_
! 105: unsigned ui ;
1.1.2.1 eric 106: #endif
1.1.2.5 ! frystyk 107: if (THD_TRACE) {
! 108: HTTrace("Event....... Dumping %s file descriptor set\n", str);
! 109: #ifdef _WINSOCKAPI_
! 110: for (ui = 0 ; ui < fdp->fd_count; ui++) {
! 111: s = all_fds.fd_array[ui] ;
! 112: #else
! 113: for (s = 0 ; s <= max_sock; s++) {
! 114: if (FD_ISSET(s, fdp))
! 115: #endif
! 116: {
! 117: HTTrace("%4d\n", s);
! 118: }
! 119: } /* for */
! 120: } /* if */
! 121: return ;
! 122: }
! 123:
! 124: /* ------------------------------------------------------------------------- */
! 125:
! 126: PRIVATE BOOL HTTimer_delete (HTTimer * timer)
! 127: {
! 128: if (timer && timers) {
! 129: HTTimer ** prev;
! 130: for (prev = &timers; *prev; prev = &(*prev)->next) {
! 131: if (*prev == timer) {
! 132: *prev = timer->next;
! 133: break;
! 134: }
! 135: }
! 136: if (THD_TRACE) HTTrace("Timer....... Deleted timer %p\n", timer);
! 137: HT_FREE(timer);
! 138: return YES;
1.1.2.1 eric 139: }
1.1.2.5 ! frystyk 140: return NO;
1.1.2.1 eric 141: }
142:
1.1.2.5 ! frystyk 143: PRIVATE HTTimer * HTTimer_new (HTTimer * timer, HTEvent * event,
! 144: SOCKET s, int millis, BOOL relative)
! 145: {
! 146: if (event) {
! 147: HTTimer ** prev;
! 148: int now = HTGetTimeInMillis();
! 149: if (!timer) {
! 150: if ((timer = (HTTimer *) HT_CALLOC(1, sizeof(HTTimer))) == NULL)
! 151: HT_OUTOFMEM("HTTimer_set");
! 152: if (THD_TRACE) HTTrace("Timer....... Created timer %p\n", timer);
! 153: } else {
! 154: for (prev = &timers; *prev; prev = &(*prev)->next) {
! 155: if (*prev == timer) {
! 156: *prev = timer->next;
! 157: break;
! 158: }
! 159: }
! 160: }
! 161: if (!millis) return timer;
! 162: if (relative) millis += now;
! 163: timer->expires = millis;
! 164: timer->event = event;
! 165: timer->s = s;
! 166: if (millis <= now) {
! 167: int status;
! 168: timer->next = NULL;
! 169: if ((status = (*timer->event->cbf)(timer->s, timer->event->param,
! 170: HTEvent_TIMEOUT)) != HT_OK) {
! 171: HTTimer_delete(timer);
! 172: return NULL;
! 173: }
! 174: }
! 175: for (prev = &timers;
! 176: *prev && millis > (*prev)->expires;
! 177: prev = &(*prev)->next);
! 178: timer->next = *prev;
! 179: *prev = timer;
! 180: return timer;
! 181: }
! 182: return NULL;
! 183: }
! 184:
! 185: PRIVATE BOOL HTTimer_deleteAll (void)
! 186: {
! 187: if (timers) {
! 188: HTTimer * timer = NULL;
! 189: while ((timer = timers)) {
! 190: timers = timers->next;
! 191: HT_FREE(timer);
! 192: }
! 193: return YES;
! 194: }
! 195: return NO;
! 196: }
! 197:
! 198: /*
! 199: ** When a timer has expired, we dispatch the event handler and re-register the
! 200: ** timer with the next expiration time.
1.1.2.1 eric 201: */
1.1.2.5 ! frystyk 202: PRIVATE int HTTimer_dispatch (HTTimer * timer, int now, HTTimer ** prev)
1.1.2.1 eric 203: {
1.1.2.5 ! frystyk 204: int newTime;
! 205: *prev = timer->next;
! 206: timer->next = NULL;
! 207: newTime = timer->event->millis;
! 208: HTTimer_new(timer, timer->event, timer->s, newTime, YES);
! 209: if (THD_TRACE) HTTrace("Timer....... Dispatch timer %p\n", timer);
! 210: return (*timer->event->cbf) (timer->s, timer->event->param, HTEvent_TIMEOUT);
1.1.2.1 eric 211: }
212:
1.1.2.5 ! frystyk 213: /* ------------------------------------------------------------------------- */
! 214:
1.1.2.1 eric 215: /*
1.1.2.5 ! frystyk 216: ** For a given socket, reqister a request structure, a set of operations,
1.1.2.1 eric 217: ** a HTEventCallback function, and a priority. For this implementation,
218: ** we allow only a single HTEventCallback function for all operations.
219: ** and the priority field is ignored.
220: */
1.1.2.2 eric 221: PUBLIC int HTEventList_register (SOCKET s, HTEventType type, HTEvent * event)
1.1.2.1 eric 222: {
223: RQ * rqp;
224: if (THD_TRACE)
1.1.2.5 ! frystyk 225: HTTrace("Event....... Register socket %d, request %p handler %p type %x at priority %d\n",
! 226: s, (void *) event->request,
! 227: (void *) event->cbf, (unsigned) type,
! 228: (unsigned) event->priority);
1.1.2.1 eric 229: if (s==INVSOC) return 0;
230: rqp = RQ_get(s, RQ_mayCreate);
231: rqp->s = s;
232: rqp->events[HTEvent_INDEX(type)] = event;
233:
1.1.2.5 ! frystyk 234: /*
! 235: ** Insert socket into appropriate file descriptor set. We also make sure
! 236: ** that it is registered in the global set.
! 237: */
! 238: if (THD_TRACE) HTTrace("Event....... Registering socket for %d\n", type);
1.1.2.1 eric 239: FD_SET(s, FdArray+HTEvent_INDEX(type));
240:
1.1.2.5 ! frystyk 241: /*
! 242: ** If the timeout has been set (relative in millis) then we register
! 243: ** a new timeout for this event
! 244: */
! 245: if (event->millis >= 0) {
! 246: rqp->timeouts[HTEvent_INDEX(type)] =
! 247: HTTimer_new(NULL, event, s, event->millis, YES);
! 248: }
! 249:
! 250: FD_SET(s, &all_fds);
! 251: if (s > max_sock) max_sock = s ;
1.1.2.1 eric 252: return HT_OK;
253: }
254:
255: /*
1.1.2.5 ! frystyk 256: ** Remove the registered information for the specified socket for the actions
1.1.2.1 eric 257: ** specified in ops. if no actions remain after the unregister, the registered
258: ** info is deleted, and, if the socket has been registered for notification,
259: ** the HTEventCallback will be invoked.
260: */
1.1.2.2 eric 261: PUBLIC int HTEventList_unregister(SOCKET s, HTEventType type)
1.1.2.1 eric 262: {
263: RQ * rqp;
264: RQ * last = NULL;
265: long v = HASH(s);
266: for (rqp = table[v]; rqp; rqp = rqp->next) {
267: if (rqp->s == s) {
1.1.2.5 ! frystyk 268:
! 269: /*
! 270: ** Unregister the event from this action
! 271: */
! 272: rqp->events[HTEvent_INDEX(type)] = NULL;
1.1.2.1 eric 273: FD_CLR(s, FdArray+HTEvent_INDEX(type));
1.1.2.5 ! frystyk 274:
! 275: /*
! 276: ** Check to see of there was a timeout connected with the event.
! 277: ** If so then delete the timeout as well.
! 278: */
! 279: {
! 280: HTTimer * timer = rqp->timeouts[HTEvent_INDEX(type)];
! 281: if (timer) HTTimer_delete(timer);
! 282: }
! 283:
! 284: /*
! 285: ** Check to see if we can delete the action completely. We do this
! 286: ** if there are no more events registered.
! 287: */
1.1.2.1 eric 288: if (rqp->events[HTEvent_INDEX(HTEvent_READ)] == NULL &&
289: rqp->events[HTEvent_INDEX(HTEvent_WRITE)] == NULL &&
290: rqp->events[HTEvent_INDEX(HTEvent_OOB)] == NULL) {
1.1.2.5 ! frystyk 291: if (THD_TRACE)
! 292: HTTrace("Event....... No more events registered for socket %d\n", s);
1.1.2.1 eric 293: if (last) last->next = rqp->next;
294: else table[v] = rqp->next;
295: HT_FREE(rqp);
296: FD_CLR(s, &all_fds);
297: }
298: if (THD_TRACE)
1.1.2.5 ! frystyk 299: HTTrace("Event....... Socket %d unregisterd for %x\n", s, type);
1.1.2.1 eric 300: return HT_OK;
301: }
302: last = rqp; /* to set next pointer when creating new */
303: }
1.1.2.5 ! frystyk 304: if (THD_TRACE) HTTrace("Event....... Couldn't find socket %d.\n", s);
1.1.2.1 eric 305: return HT_ERROR;
306: }
307:
308: /*
1.1.2.5 ! frystyk 309: ** Unregister all sockets
1.1.2.1 eric 310: ** N.B. we just remove them for our internal data structures: it is up to the
311: ** application to actually close the socket.
312: */
313: PUBLIC int HTEventList_unregisterAll( void )
314: {
315: int i;
316: register RQ * rqp, * next ;
1.1.2.5 ! frystyk 317: if (THD_TRACE) HTTrace("Unregister.. all sockets\n");
1.1.2.1 eric 318: for (i = 0 ; i < PRIME_TABLE_SIZE; i++) {
319: for (rqp = table[i]; rqp != 0; rqp = next) {
320: next = rqp->next;
321: HT_FREE(rqp);
322: }
323: table[i] = NULL;
324: }
325: max_sock = 0 ;
326: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_READ));
327: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_WRITE));
328: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_OOB));
329: FD_ZERO(&all_fds);
330: return 0;
331: }
332:
1.1.2.5 ! frystyk 333: /*
! 334: ** Stops the (select based) event loop. The function does not guarantee
! 335: ** that all requests have terminated. This is for the app to do
1.1.2.1 eric 336: */
337: PUBLIC void HTEventList_stopLoop (void)
338: {
339: HTEndLoop = 1;
340: }
341:
1.1.2.5 ! frystyk 342: /*
! 343: ** We wait for activity from one of our registered
1.1.2.1 eric 344: ** channels, and dispatch on that.
345: **
346: ** There are now two versions of the event loop. The first is if you want
347: ** to use async I/O on windows, and the other is if you want to use normal
348: ** Unix setup with sockets
349: */
1.1.2.5 ! frystyk 350: PUBLIC int HTEventList_loop (HTRequest * theRequest)
1.1.2.1 eric 351: {
352: fd_set treadset, twriteset, texceptset;
1.1.2.5 ! frystyk 353: struct timeval waittime, * wt;
1.1.2.1 eric 354: int active_sockets;
355: int maxfds;
1.1.2.5 ! frystyk 356: int timeout, now;
1.1.2.1 eric 357: SOCKET s;
358: int status = 0;
359: HTEndLoop = 0;
1.1.2.5 ! frystyk 360:
! 361: /* Don't leave this loop until we leave the application */
! 362: do {
1.1.2.1 eric 363: treadset = FdArray[HTEvent_INDEX(HTEvent_READ)];
364: twriteset = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
365: texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];
366: maxfds = max_sock;
367:
1.1.2.5 ! frystyk 368: if (THD_TRACE) HTTrace("Event Loop.. calling select: maxfds is %d\n", maxfds);
! 369:
! 370: /*
! 371: ** Timeval struct copy needed for linux, as it set the value to the
! 372: ** remaining timeout while exiting the select. (and perhaps for
! 373: ** other OS). Code borrowed from X server.
! 374: */
! 375: wt = NULL;
! 376: if (timers) {
! 377: now = HTGetTimeInMillis();
! 378: while (timers && timers->expires <= now)
! 379: HTTimer_dispatch(timers, now, &timers);
! 380: if (timers) {
! 381: timeout = timers->expires - now;
! 382: waittime.tv_sec = timeout / MILLI_PER_SECOND;
! 383: waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
! 384: (1000000 / MILLI_PER_SECOND);
! 385: wt = &waittime;
! 386: }
! 387: }
1.1.2.1 eric 388:
389: #ifdef __hpux
390: active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset,
1.1.2.5 ! frystyk 391: (int *)&texceptset, wt);
1.1.2.1 eric 392: #else
1.1.2.5 ! frystyk 393: active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset, wt);
1.1.2.1 eric 394: #endif
1.1.2.5 ! frystyk 395:
! 396: if (THD_TRACE) HTTrace("Event Loop.. select returns %d\n", active_sockets);
1.1.2.1 eric 397:
398: if (active_sockets == -1) {
399: HTRequest_addSystemError( theRequest, ERR_FATAL, socerrno, NO, "select");
400: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_READ), "Read");
401: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_WRITE), "Write") ;
402: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_OOB), "Exceptions");
403: return HT_ERROR;
404: }
405:
1.1.2.5 ! frystyk 406: /*
! 407: ** We had a timeout so now we check and see if we have a timeout
! 408: ** handler to call
! 409: */
1.1.2.1 eric 410: if (active_sockets == 0) {
1.1.2.5 ! frystyk 411: if (timers) {
! 412: now = HTGetTimeInMillis();
! 413: while (timers && timers->expires <= now)
! 414: HTTimer_dispatch(timers, now, &timers);
! 415: }
! 416: continue;
1.1.2.1 eric 417: }
418:
419: /*
1.1.2.5 ! frystyk 420: ** There were active sockets. Determine which fd sets they were in
! 421: */
1.1.2.1 eric 422: for (s = 0 ; s <= maxfds ; s++) {
1.1.2.5 ! frystyk 423: if (FD_ISSET(s, &texceptset))
! 424: if ((status = HTEventList_dispatch(s, HTEvent_OOB)) != HT_OK)
! 425: return status;
! 426: if (FD_ISSET(s, &twriteset))
! 427: if ((status = HTEventList_dispatch(s, HTEvent_WRITE)) != HT_OK)
! 428: return status;
! 429: if (FD_ISSET(s, &treadset))
! 430: if ((status = HTEventList_dispatch(s, HTEvent_READ)) != HT_OK)
! 431: return status;
1.1.2.1 eric 432: }
433: } while (!HTEndLoop);
1.1.2.5 ! frystyk 434:
1.1.2.1 eric 435: return HT_OK;
436: }
437:
438: /*
1.1.2.5 ! frystyk 439: ** Dispatch the event to the appropriate event handler.
! 440: ** If no event handler is found then just return.
1.1.2.1 eric 441: */
1.1.2.2 eric 442: PUBLIC int HTEventList_dispatch (SOCKET s, HTEventType type)
1.1.2.1 eric 443: {
1.1.2.5 ! frystyk 444: RQ * rqp = RQ_get(s, RQ_find);
! 445: if (rqp) {
! 446: HTEvent * event = rqp->events[HTEvent_INDEX(type)];
! 447:
! 448: /*
! 449: ** If we have found an event object for this event then see
! 450: ** is we should call it.
! 451: */
! 452: if (event && event->priority!=HT_PRIORITY_OFF)
! 453: return (*event->cbf) (s, event->param, type);
! 454: if (THD_TRACE) HTTrace("Dispatch.... Handler %p NOT called\n", rqp);
! 455: return HT_OK;
1.1.2.1 eric 456: }
1.1.2.5 ! frystyk 457: if (THD_TRACE) HTTrace("Dispatch.... Bad socket %d\n", s);
! 458: return NO;
1.1.2.3 eric 459: }
460:
461: PUBLIC HTEvent * HTEventList_lookup (SOCKET s, HTEventType type)
462: {
463: RQ * rqp = NULL;
464: if ((rqp = RQ_get(s, RQ_find)) == NULL)
465: return NULL;
466: return rqp->events[HTEvent_INDEX(type)];
1.1.2.1 eric 467: }
468:
469: /* REGISTER DEFULT EVENT MANAGER
470: ** -----------------------------
471: ** Not done automaticly - may be done by application!
472: */
473: PUBLIC BOOL HTEventInit (void)
474: {
475: HTEvent_setRegisterCallback(HTEventList_register);
476: HTEvent_setUnregisterCallback(HTEventList_unregister);
477: return YES;
478: }
479:
480: PUBLIC BOOL HTEventTerminate (void)
481: {
482: return YES;
483: }
Webmaster