Annotation of libwww/Library/src/HTEvtLst.c, revision 2.2
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.2 ! eric 6: ** @(#) $Id: HTEvtLst.c,v 2.1 1996/12/01 00:26:35 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: ** 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 "HTTimer.h"
35: #include "HTEvtLst.h" /* Implemented here */
36:
37: /* Type definitions and global variables etc. local to this module */
38: #define PRIME_TABLE_SIZE 67
39: #define MILLI_PER_SECOND 1000
40: #define HASH(s) ((s) % PRIME_TABLE_SIZE)
2.2 ! eric 41: #define HT_EVENT_ORDER /* use event ordering code */
! 42: #define EVENTS_TO_EXECUTE 5 /* how many to execute in one select loop */
2.1 frystyk 43:
44: typedef struct rq_t RQ;
45: struct rq_t {
46: SOCKET s ; /* our socket */
47: BOOL unregister; /* notify app when completely unregistered */
48: HTEvent * events[3]; /* event parameters for read, write, oob */
49: HTTimer * timeouts[3]; /* timeout for each of the events */
50: };
51:
52: typedef enum _RQ_action {
53: RQ_mayCreate,
54: RQ_find
55: } RQ_action;
56:
2.2 ! eric 57: HTList * HashTable[PRIME_TABLE_SIZE];
2.1 frystyk 58: PRIVATE SOCKET max_sock = 0 ; /* max socket value in use */
59:
60: PRIVATE fd_set FdArray[HTEvent_TYPES];
61: PRIVATE fd_set all_fds ; /* any descriptor at all */
62:
63: PRIVATE int HTEndLoop = 0; /* If !0 then exit event loop */
64:
65: /* ------------------------------------------------------------------------- */
66:
2.2 ! eric 67: PRIVATE RQ * RQ_get (SOCKET s, RQ_action action)
2.1 frystyk 68: {
69: long v = HASH(s);
2.2 ! eric 70: HTList* cur;
! 71: RQ * pres;
! 72:
! 73: if (HashTable[v] == NULL)
! 74: HashTable[v] = HTList_new();
! 75: cur = HashTable[v];
! 76: while ((pres = (RQ *) HTList_nextObject(cur)))
! 77: if (pres->s == s)
! 78: return pres;
! 79:
2.1 frystyk 80: if (action == RQ_mayCreate) {
2.2 ! eric 81: if ((pres = (RQ *) HT_CALLOC(1, sizeof(RQ))) == NULL)
2.1 frystyk 82: HT_OUTOFMEM("HTEventList_register");
2.2 ! eric 83: pres->s = s;
! 84: HTList_addObject(HashTable[v], (void *)pres);
! 85: return pres;
2.1 frystyk 86: }
87: return NULL;
88: }
89:
90: /*
91: ** A simple debug function that dumps all the socket arrays
92: ** as trace messages
93: */
2.2 ! eric 94: PRIVATE void __DumpFDSet (fd_set * fdp, const char * str)
2.1 frystyk 95: {
96: SOCKET s ;
97: #ifdef _WINSOCKAPI_
98: unsigned ui ;
99: #endif
100: if (THD_TRACE) {
101: HTTrace("Event....... Dumping %s file descriptor set\n", str);
102: #ifdef _WINSOCKAPI_
103: for (ui = 0 ; ui < fdp->fd_count; ui++) {
104: s = all_fds.fd_array[ui] ;
105: #else
106: for (s = 0 ; s <= max_sock; s++) {
107: if (FD_ISSET(s, fdp))
108: #endif
109: {
110: HTTrace("%4d\n", s);
111: }
112: } /* for */
113: } /* if */
114: return ;
115: }
116:
117: /* ------------------------------------------------------------------------- */
2.2 ! eric 118: /* E V E N T O R D E R I N G S T U F F */
! 119: #ifdef HT_EVENT_ORDER
! 120: typedef struct {
! 121: HTEvent * event;
! 122: SOCKET s;
! 123: HTEventType type;
! 124: HTPriority skipped;
! 125: } EventOrder;
2.1 frystyk 126:
2.2 ! eric 127: HTList * EventOrderList = NULL;
! 128: #if 0
! 129: /*
! 130: ** return -1 if a should be after b
! 131: */
! 132: int EventOrderComparer (const void * a, const void * b)
! 133: {
! 134: EventOrder * placeMe = (EventOrder *)a;
! 135: EventOrder * maybeHere = (EventOrder *)b;
! 136: if (placeMe->event->priority+placeMe->skipped >= maybeHere->event->priority+maybeHere->skipped)
! 137: return 1;
! 138: return -1;
! 139: }
! 140: #endif
! 141:
! 142: int EventOrder_add (SOCKET s, HTEventType type)
! 143: {
! 144: EventOrder * pres;
! 145: HTList * cur = EventOrderList;
! 146: HTList * insertAfter = cur;
! 147: HTEvent * event = HTEventList_lookup(s, type);
! 148:
! 149: if (event == NULL) {
! 150: HTTrace("EventOrder.. no event found for socket %d, type %x.\n", s, type);
! 151: return HT_ERROR;
! 152: }
! 153:
! 154: /*
! 155: ** Look to see if it's already here from before
! 156: */
! 157: while ((pres = (EventOrder *) HTList_nextObject(cur))) {
! 158: if (pres->s == s && pres->event == event && pres->type == type) {
! 159: pres->skipped++;
! 160: return HT_OK;
! 161: }
! 162: if (pres->event->priority+pres->skipped > event->priority)
! 163: insertAfter = cur;
! 164: }
! 165:
! 166: /*
! 167: ** No, so create a new element
! 168: */
! 169: if ((pres = (EventOrder *) HT_CALLOC(1, sizeof(EventOrder))) == NULL)
! 170: HT_OUTOFMEM("EventOrder_add");
! 171: pres->event = event;
! 172: pres->s = s;
! 173: pres->type = type;
! 174: HTList_addObject(insertAfter, (void *)pres);
! 175: return HT_OK;
! 176: }
! 177:
! 178: PUBLIC int EventOrder_executeAndDelete (void)
! 179: {
! 180: HTList * cur;
! 181: EventOrder * pres;
! 182: int i = 0;
! 183:
! 184: if (cur == NULL)
! 185: return NO;
! 186: #if 0
! 187: HTList_insertionSort(EventOrderList, EventOrderComparer);
! 188: #endif
! 189: cur = EventOrderList;
! 190: if (THD_TRACE) HTTrace("EventOrder.. execute ordered events\n");
! 191: while ((pres = (EventOrder *) HTList_removeLastObject(cur)) && i < EVENTS_TO_EXECUTE) {
! 192: int ret = (*pres->event->cbf)(pres->s, pres->event->param, pres->type);
! 193: HT_FREE(pres);
! 194: if (ret != HT_OK)
! 195: return ret;
! 196: i++;
! 197: }
! 198: return HT_OK;
! 199: }
! 200:
! 201: PUBLIC BOOL EventOrder_deleteAll (void)
! 202: {
! 203: HTList * cur = EventOrderList;
! 204: EventOrder * pres;
! 205:
! 206: if (cur == NULL)
! 207: return NO;
! 208: if (THD_TRACE) HTTrace("EventOrder.. all ordered events\n");
! 209: while ((pres = (EventOrder *) HTList_nextObject(cur)))
! 210: HT_FREE(pres);
! 211: HTList_delete(EventOrderList);
! 212: EventOrderList = NULL;
! 213: return YES;
! 214: }
! 215: #endif /* HT_EVENT_ORDER */
! 216:
! 217: /* ------------------------------------------------------------------------- */
! 218: /* T I M E O U T H A N D L E R */
2.1 frystyk 219: PRIVATE int EventListTimerHandler (HTTimer * timer, void * param)
220: {
221: RQ * rqp = (RQ *)param;
222: HTEvent * event;
223: if (rqp->timeouts[HTEvent_INDEX(HTEvent_READ)] == timer) {
224: event = rqp->events[HTEvent_INDEX(HTEvent_READ)];
225: if (THD_TRACE) HTTrace("Event....... READ timed out on %d.\n", rqp->s);
226: return (*event->cbf) (rqp->s, event->param, HTEvent_TIMEOUT);
227: }
228: if (rqp->timeouts[HTEvent_INDEX(HTEvent_WRITE)] == timer) {
229: event = rqp->events[HTEvent_INDEX(HTEvent_WRITE)];
230: if (THD_TRACE) HTTrace("Event....... WRITE timed out on %d.\n", rqp->s);
231: return (*event->cbf) (rqp->s, event->param, HTEvent_TIMEOUT);
232: }
233: if (rqp->timeouts[HTEvent_INDEX(HTEvent_OOB)] == timer) {
234: event = rqp->events[HTEvent_INDEX(HTEvent_OOB)];
235: if (THD_TRACE) HTTrace("Event....... OOB timed out on %d.\n", rqp->s);
236: return (*event->cbf) (rqp->s, event->param, HTEvent_TIMEOUT);
237: }
238: HTTrace("Event....... can't find event for timer %p.\n", timer);
239: return HT_ERROR;
240: }
241:
242: /* ------------------------------------------------------------------------- */
243:
244: /*
245: ** For a given socket, reqister a request structure, a set of operations,
246: ** a HTEventCallback function, and a priority. For this implementation,
247: ** we allow only a single HTEventCallback function for all operations.
248: ** and the priority field is ignored.
249: */
250: PUBLIC int HTEventList_register (SOCKET s, HTEventType type, HTEvent * event)
251: {
252: RQ * rqp;
253: if (THD_TRACE)
254: HTTrace("Event....... Register socket %d, request %p handler %p type %x at priority %d\n",
255: s, (void *) event->request,
256: (void *) event->cbf, (unsigned) type,
257: (unsigned) event->priority);
258: if (s==INVSOC || HTEvent_INDEX(type) > 2)
259: return 0;
260: #if 0
261: /*
262: ** Don't write down TIMEOUT events in the RQ list or the fd sets.
263: ** They just manifest in the HTTimer
264: */
265: if (type == HTEvent_TIMEOUT)
266: return HT_OK;
267: #endif /* 0 */
268:
269: /*
270: ** Insert socket into appropriate file descriptor set. We also make sure
271: ** that it is registered in the global set.
272: */
273: if (THD_TRACE) HTTrace("Event....... Registering socket for %d\n", type);
274: rqp = RQ_get(s, RQ_mayCreate);
275: rqp->s = s;
276: rqp->events[HTEvent_INDEX(type)] = event;
277: FD_SET(s, FdArray+HTEvent_INDEX(type));
278: FD_SET(s, &all_fds);
279:
280: /*
281: ** If the timeout has been set (relative in millis) then we register
282: ** a new timeout for this event
283: */
284: if (event->millis >= 0) {
285: rqp->timeouts[HTEvent_INDEX(type)] = HTTimer_new(NULL, EventListTimerHandler, rqp, event->millis, YES);
286: }
287:
288: if (s > max_sock) max_sock = s ;
289: return HT_OK;
290: }
291:
292: /*
293: ** Remove the registered information for the specified socket for the actions
294: ** specified in ops. if no actions remain after the unregister, the registered
295: ** info is deleted, and, if the socket has been registered for notification,
296: ** the HTEventCallback will be invoked.
297: */
298: PUBLIC int HTEventList_unregister(SOCKET s, HTEventType type)
299: {
300: long v = HASH(s);
2.2 ! eric 301: HTList * cur = HashTable[v];
! 302: HTList * last = cur;
! 303: RQ * pres;
! 304:
! 305: while ((pres = (RQ *) HTList_nextObject(cur))) {
! 306: if (pres->s == s) {
2.1 frystyk 307:
308: /*
309: ** Unregister the event from this action
310: */
2.2 ! eric 311: pres->events[HTEvent_INDEX(type)] = NULL;
2.1 frystyk 312: FD_CLR(s, FdArray+HTEvent_INDEX(type));
313:
314: /*
315: ** Check to see of there was a timeout connected with the event.
316: ** If so then delete the timeout as well.
317: */
318: {
2.2 ! eric 319: HTTimer * timer = pres->timeouts[HTEvent_INDEX(type)];
2.1 frystyk 320: if (timer) HTTimer_delete(timer);
321: }
322:
323: /*
324: ** Check to see if we can delete the action completely. We do this
325: ** if there are no more events registered.
326: */
2.2 ! eric 327: if (pres->events[HTEvent_INDEX(HTEvent_READ)] == NULL &&
! 328: pres->events[HTEvent_INDEX(HTEvent_WRITE)] == NULL &&
! 329: pres->events[HTEvent_INDEX(HTEvent_OOB)] == NULL) {
2.1 frystyk 330: if (THD_TRACE)
331: HTTrace("Event....... No more events registered for socket %d\n", s);
2.2 ! eric 332: HT_FREE(pres);
2.1 frystyk 333: FD_CLR(s, &all_fds);
2.2 ! eric 334: HTList_quickRemoveObject(cur, last);
! 335: } else
! 336: last = cur; /* to set next pointer when creating new */
2.1 frystyk 337: if (THD_TRACE)
338: HTTrace("Event....... Socket %d unregisterd for %x\n", s, type);
339: return HT_OK;
340: }
341: }
342: if (THD_TRACE) HTTrace("Event....... Couldn't find socket %d.\n", s);
343: return HT_ERROR;
344: }
345:
346: /*
347: ** Unregister all sockets
348: ** N.B. we just remove them for our internal data structures: it is up to the
349: ** application to actually close the socket.
350: */
2.2 ! eric 351: PUBLIC int HTEventList_unregisterAll (void)
2.1 frystyk 352: {
353: int i;
354: if (THD_TRACE) HTTrace("Unregister.. all sockets\n");
355: for (i = 0 ; i < PRIME_TABLE_SIZE; i++) {
2.2 ! eric 356: HTList * cur = HashTable[i];
! 357: RQ * pres;
! 358: while ((pres = (RQ *) HTList_nextObject(cur)))
! 359: HT_FREE(pres);
! 360: HTList_delete(HashTable[i]);
! 361: HashTable[i] = NULL;
2.1 frystyk 362: }
363: max_sock = 0 ;
364: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_READ));
365: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_WRITE));
366: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_OOB));
367: FD_ZERO(&all_fds);
2.2 ! eric 368: #ifdef HT_EVENT_ORDER
! 369: EventOrder_deleteAll();
! 370: #endif /* HT_EVENT_ORDER */
2.1 frystyk 371: return 0;
372: }
373:
374: /*
375: ** Dispatch the event to the appropriate event handler.
376: ** If no event handler is found then just return.
377: */
378: PUBLIC int HTEventList_dispatch (SOCKET s, HTEventType type)
379: {
380: RQ * rqp = RQ_get(s, RQ_find);
381: if (rqp) {
382: HTEvent * event = rqp->events[HTEvent_INDEX(type)];
383:
384: /*
385: ** If we have found an event object for this event then see
386: ** is we should call it.
387: */
388: if (event && event->priority!=HT_PRIORITY_OFF)
389: return (*event->cbf) (s, event->param, type);
390: if (THD_TRACE) HTTrace("Dispatch.... Handler %p NOT called\n", rqp);
391: return HT_OK;
392: }
393: if (THD_TRACE) HTTrace("Dispatch.... Bad socket %d\n", s);
394: return NO;
395: }
396:
397: /*
398: ** Stops the (select based) event loop. The function does not guarantee
399: ** that all requests have terminated. This is for the app to do
400: */
401: PUBLIC void HTEventList_stopLoop (void)
402: {
403: HTEndLoop = 1;
404: }
405:
406: /*
407: ** We wait for activity from one of our registered
408: ** channels, and dispatch on that.
409: **
410: ** There are now two versions of the event loop. The first is if you want
411: ** to use async I/O on windows, and the other is if you want to use normal
412: ** Unix setup with sockets
413: */
414: PUBLIC int HTEventList_loop (HTRequest * theRequest)
415: {
416: fd_set treadset, twriteset, texceptset;
417: struct timeval waittime, * wt;
418: int active_sockets;
419: int maxfds;
420: int timeout;
421: SOCKET s;
422: int status = 0;
423: HTEndLoop = 0;
424:
2.2 ! eric 425: EventOrderList = HTList_new(); /* is kept around until EventOrder_deleteAll */
! 426:
2.1 frystyk 427: /* Don't leave this loop until we leave the application */
428: do {
429: treadset = FdArray[HTEvent_INDEX(HTEvent_READ)];
430: twriteset = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
431: texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];
432: maxfds = max_sock;
433:
434: if (THD_TRACE) HTTrace("Event Loop.. calling select: maxfds is %d\n", maxfds);
435:
436: /*
437: ** Timeval struct copy needed for linux, as it set the value to the
438: ** remaining timeout while exiting the select. (and perhaps for
439: ** other OS). Code borrowed from X server.
440: */
441: wt = NULL;
442: if ((timeout = HTTimer_soonest())) {
443: waittime.tv_sec = timeout / MILLI_PER_SECOND;
444: waittime.tv_usec = (timeout % MILLI_PER_SECOND) *
445: (1000000 / MILLI_PER_SECOND);
446: wt = &waittime;
447: }
448:
2.2 ! eric 449: HTTraceData((char*)&treadset, maxfds/8 + 1, "HTEventList_loop pre treadset: (maxfd:%d)", maxfds);
! 450: HTTraceData((char*)&twriteset, maxfds/8 + 1, "HTEventList_loop pre twriteset:");
! 451: HTTraceData((char*)&texceptset, maxfds/8 + 1, "HTEventList_loop pre texceptset:");
! 452:
2.1 frystyk 453: #ifdef __hpux
454: active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset,
455: (int *)&texceptset, wt);
456: #else
457: active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset, wt);
458: #endif
2.2 ! eric 459:
! 460: HTTraceData((char*)&treadset, maxfds/8 + 1, "HTEventList_loop post treadset: (active_sockets:%d)", active_sockets);
! 461: HTTraceData((char*)&twriteset, maxfds/8 + 1, "HTEventList_loop post twriteset: (errno:%d)", errno);
! 462: HTTraceData((char*)&texceptset, maxfds/8 + 1, "HTEventList_loop post texceptset:");
! 463:
2.1 frystyk 464: if (THD_TRACE) HTTrace("Event Loop.. select returns %d\n", active_sockets);
465:
466: if (active_sockets == -1) {
467: HTRequest_addSystemError( theRequest, ERR_FATAL, socerrno, NO, "select");
468: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_READ), "Read");
469: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_WRITE), "Write") ;
470: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_OOB), "Exceptions");
471: return HT_ERROR;
472: }
473:
474: /*
475: ** We had a timeout so now we check and see if we have a timeout
476: ** handler to call
477: */
478: if (active_sockets == 0) {
479: HTTimer_dispatchAll();
480: continue;
481: }
482:
483: /*
484: ** There were active sockets. Determine which fd sets they were in
485: */
2.2 ! eric 486: #ifdef HT_EVENT_ORDER
! 487: #define DISPATCH(socket, type) EventOrder_add(socket, type)
! 488: #else /* HT_EVENT_ORDER */
! 489: #define DISPATCH(socket, type) HTEventList_dispatch(socket, type)
! 490: #endif /* !HT_EVENT_ORDER */
2.1 frystyk 491: for (s = 0 ; s <= maxfds ; s++) {
492: if (FD_ISSET(s, &texceptset))
2.2 ! eric 493: if ((status = DISPATCH(s, HTEvent_OOB)) != HT_OK)
2.1 frystyk 494: return status;
495: if (FD_ISSET(s, &twriteset))
2.2 ! eric 496: if ((status = DISPATCH(s, HTEvent_WRITE)) != HT_OK)
2.1 frystyk 497: return status;
498: if (FD_ISSET(s, &treadset))
2.2 ! eric 499: if ((status = DISPATCH(s, HTEvent_READ)) != HT_OK)
2.1 frystyk 500: return status;
501: }
2.2 ! eric 502: #ifdef HT_EVENT_ORDER
! 503: if ((status = EventOrder_executeAndDelete()) != HT_OK)
! 504: return status;
! 505: #endif /* HT_EVENT_ORDER */
2.1 frystyk 506: } while (!HTEndLoop);
507:
508: return HT_OK;
509: }
510:
511: PUBLIC HTEvent * HTEventList_lookup (SOCKET s, HTEventType type)
512: {
513: RQ * rqp = NULL;
514: if ((rqp = RQ_get(s, RQ_find)) == NULL)
515: return NULL;
516: return rqp->events[HTEvent_INDEX(type)];
517: }
518:
519: /* REGISTER DEFULT EVENT MANAGER
520: ** -----------------------------
521: ** Not done automaticly - may be done by application!
522: */
523: PUBLIC BOOL HTEventInit (void)
524: {
525: HTEvent_setRegisterCallback(HTEventList_register);
526: HTEvent_setUnregisterCallback(HTEventList_unregister);
527: return YES;
528: }
529:
530: PUBLIC BOOL HTEventTerminate (void)
531: {
532: return YES;
533: }
Webmaster