Annotation of libwww/Library/src/HTEvtLst.c, revision 1.1.2.1
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.
! 6: ** @(#) $Id: HTEvntrg.c,v 2.46 1996/09/16 21:33:45 eric Exp $
! 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 */
! 37: PRIVATE fd_set FdArray[3];
! 38: PRIVATE fd_set all_fds ; /* any descriptor at all */
! 39:
! 40: PRIVATE int HTEndLoop = 0; /* If !0 then exit event loop */
! 41:
! 42: PRIVATE const int SecondsToWait = 5 ;
! 43:
! 44: PRIVATE void __DumpFDSet( fd_set *, const char *);
! 45:
! 46: /*
! 47: ** our internal structure to hold a socket, it's request
! 48: ** and our action. For version 1, we allow one action per socket
! 49: */
! 50:
! 51: /*
! 52: ** an action consists of a request, a set of requested operations
! 53: ** a HTEventCallback function
! 54: */
! 55:
! 56: typedef struct rq_t RQ;
! 57:
! 58: struct rq_t {
! 59: RQ * next ;
! 60: SOCKET s ; /* our socket */
! 61: BOOL unregister; /* notify app when completely unregistered */
! 62: HTEvent * events[3];
! 63: };
! 64:
! 65: #define PRIME_TABLE_SIZE 67
! 66:
! 67: #define HASH(s) ((s) % PRIME_TABLE_SIZE)
! 68:
! 69: /*
! 70: ** our internal table of requests,
! 71: ** indexed by socket
! 72: */
! 73: PRIVATE RQ * table[PRIME_TABLE_SIZE];
! 74: PRIVATE SOCKET max_sock = 0 ; /* max socket value in use */
! 75:
! 76: /* Select Timeout handling */
! 77: typedef struct _HTTimeout {
! 78: HTEventTimeout * tcbf;
! 79: HTRequest * request;
! 80: struct timeval tv;
! 81: BOOL always;
! 82: } HTTimeout;
! 83:
! 84: PRIVATE HTTimeout seltime;
! 85: PRIVATE struct timeval *tvptr = NULL;
! 86:
! 87: /*
! 88: ** Local functions
! 89: */
! 90: typedef enum {RQ_mayCreate, RQ_find} RQ_action;
! 91: PRIVATE RQ * RQ_get(SOCKET s, RQ_action action)
! 92: {
! 93: RQ * rqp;
! 94: RQ * last = NULL;
! 95: long v = HASH(s);
! 96: for (rqp = table[v]; rqp; rqp = rqp->next) {
! 97: if (rqp->s == s) {
! 98: return rqp;
! 99: }
! 100: last = rqp; /* to set next pointer when creating new */
! 101: }
! 102: if (action == RQ_mayCreate) {
! 103: if ((rqp = (RQ *) HT_CALLOC(1, sizeof(RQ))) == NULL)
! 104: HT_OUTOFMEM("HTEventList_register");
! 105: if (last) last->next = rqp;
! 106: else table[v] = rqp;
! 107: rqp->s = s;
! 108: return rqp;
! 109: }
! 110: return NULL;
! 111: }
! 112:
! 113: /* ------------------------------------------------------------------------- */
! 114:
! 115: /* HTEventList_registerTimeout
! 116: ** -----------------------
! 117: ** Set the timeout for sockets. This does only works on NON windows
! 118: ** platforms as we need to poll for the console on windows
! 119: ** The default is no timeout. If the tp points to a zero'ed structure
! 120: ** then the select is basically polling. If always is YES then
! 121: ** the callback is called at all times, if NO then only when Library
! 122: ** sockets are active.
! 123: ** Returns YES if OK else NO
! 124: */
! 125: PUBLIC BOOL HTEventList_registerTimeout (struct timeval *tp, HTRequest * request,
! 126: HTEventTimeout *tcbf, BOOL always)
! 127: {
! 128: if (tp) {
! 129: #ifdef WWW_WIN_ASYNC
! 130: /* same window process WWW_WIN_ASYNC stuff and TIMEOUT */
! 131: SetTimer(HTSocketWin, TIMEOUT, tp->tv_usec/1000 + tp->tv_sec*1000, 0);
! 132: #else
! 133: tvptr = &seltime.tv;
! 134: tvptr->tv_sec = tp->tv_sec;
! 135: tvptr->tv_usec = tp->tv_usec;
! 136: #endif
! 137: seltime.tcbf = tcbf;
! 138: seltime.request = request;
! 139: seltime.always = always;
! 140: if (THD_TRACE)
! 141: HTTrace("Timeout cbf. %p %s (req=%p, sec=%d, usec=%d)\n",
! 142: tcbf, always ? "always" : "active",
! 143: request, (int) tp->tv_sec, (int) tp->tv_usec);
! 144: }
! 145: return YES;
! 146: }
! 147:
! 148: /* HTEventList_unregisterTimeout
! 149: ** -------------------------
! 150: ** Disables the callback function.
! 151: ** Returns YES if OK else NO
! 152: */
! 153: PUBLIC BOOL HTEventList_unregisterTimeout(void)
! 154: {
! 155: #ifdef WWW_WIN_ASYNC
! 156: /* Same window process WWW_WIN_ASYNC stuff and TIMEOUT */
! 157: KillTimer(HTSocketWin, TIMEOUT);
! 158: #else
! 159: tvptr = NULL;
! 160: #endif
! 161: return YES;
! 162: }
! 163:
! 164: /*
! 165: ** HTEventList_register
! 166: ** for a given socket, reqister a request structure, a set of operations,
! 167: ** a HTEventCallback function, and a priority. For this implementation,
! 168: ** we allow only a single HTEventCallback function for all operations.
! 169: ** and the priority field is ignored.
! 170: */
! 171: PUBLIC int HTEventList_register (SOCKET s, HTEvent_type type, HTEvent * event)
! 172: {
! 173: RQ * rqp;
! 174: if (THD_TRACE)
! 175: HTTrace("Register.... socket %d, request %p HTEventCallback %p type %x at priority %d\n",
! 176: s, (void *)event->request, (void *)event->cbf, (unsigned) type, (unsigned) event->priority) ;
! 177:
! 178: if (s==INVSOC) return 0;
! 179: rqp = RQ_get(s, RQ_mayCreate);
! 180: rqp->s = s;
! 181: rqp->events[HTEvent_INDEX(type)] = event;
! 182:
! 183: /* insert socket into appropriate file descriptor set */
! 184:
! 185: if (THD_TRACE)
! 186: HTTrace("Register.... Registering socket for %d\n", type);
! 187: FD_SET(s, FdArray+HTEvent_INDEX(type));
! 188: if (!FD_ISSET(s, &all_fds))
! 189: FD_SET(s, &all_fds);
! 190:
! 191: if (s > max_sock)
! 192: max_sock = s ;
! 193:
! 194: return HT_OK;
! 195: }
! 196:
! 197: /*
! 198: ** HTEventList_unregister
! 199: ** remove the registered information for the specified socket for the actions
! 200: ** specified in ops. if no actions remain after the unregister, the registered
! 201: ** info is deleted, and, if the socket has been registered for notification,
! 202: ** the HTEventCallback will be invoked.
! 203: */
! 204: PUBLIC int HTEventList_unregister(SOCKET s, HTEvent_type type)
! 205: {
! 206: RQ * rqp;
! 207: RQ * last = NULL;
! 208: long v = HASH(s);
! 209: for (rqp = table[v]; rqp; rqp = rqp->next) {
! 210: if (rqp->s == s) {
! 211: rqp->events[HTEvent_INDEX(type)] = 0;
! 212: FD_CLR(s, FdArray+HTEvent_INDEX(type));
! 213: if (rqp->events[HTEvent_INDEX(HTEvent_READ)] == NULL &&
! 214: rqp->events[HTEvent_INDEX(HTEvent_WRITE)] == NULL &&
! 215: rqp->events[HTEvent_INDEX(HTEvent_OOB)] == NULL) {
! 216: HTTrace("UnRegister.. no more events registered for socket %d\n", s);
! 217: if (last) last->next = rqp->next;
! 218: else table[v] = rqp->next;
! 219: HT_FREE(rqp);
! 220: FD_CLR(s, &all_fds);
! 221: }
! 222: if (THD_TRACE)
! 223: HTTrace("UnRegister.. socket %d unregisterd for %x\n", s, type);
! 224: return HT_OK;
! 225: }
! 226: last = rqp; /* to set next pointer when creating new */
! 227: }
! 228: HTTrace("Unregister.. couldn't find socket %d.\n", s);
! 229: return HT_ERROR;
! 230: }
! 231:
! 232: /*
! 233: ** HTEventList_unregisterAll
! 234: ** unregister all sockets
! 235: ** N.B. we just remove them for our internal data structures: it is up to the
! 236: ** application to actually close the socket.
! 237: */
! 238: PUBLIC int HTEventList_unregisterAll( void )
! 239: {
! 240: int i;
! 241: register RQ * rqp, * next ;
! 242:
! 243: /* begin */
! 244: if (THD_TRACE)
! 245: HTTrace("Unregister.. all sockets\n");
! 246:
! 247: for (i = 0 ; i < PRIME_TABLE_SIZE; i++) {
! 248: for (rqp = table[i]; rqp != 0; rqp = next) {
! 249: next = rqp->next;
! 250: HT_FREE(rqp);
! 251: }
! 252: table[i] = NULL;
! 253: }
! 254:
! 255: max_sock = 0 ;
! 256: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_READ));
! 257: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_WRITE));
! 258: FD_ZERO(FdArray+HTEvent_INDEX(HTEvent_OOB));
! 259: FD_ZERO(&all_fds);
! 260:
! 261: return 0;
! 262: }
! 263:
! 264:
! 265: /* HTEventList_stopLoop
! 266: ** ----------------
! 267: ** Stops the (select based) event loop. The function does not guarantee
! 268: ** that all requests have terminated. This is for the app to do
! 269: */
! 270: PUBLIC void HTEventList_stopLoop (void)
! 271: {
! 272: HTEndLoop = 1;
! 273: }
! 274:
! 275: /* HTEventList_loop
! 276: ** ------------
! 277: ** event loop: that is, we wait for activity from one of our registered
! 278: ** channels, and dispatch on that.
! 279: **
! 280: ** There are now two versions of the event loop. The first is if you want
! 281: ** to use async I/O on windows, and the other is if you want to use normal
! 282: ** Unix setup with sockets
! 283: */
! 284: PUBLIC int HTEventList_loop( HTRequest * theRequest )
! 285: {
! 286: fd_set treadset, twriteset, texceptset;
! 287: int active_sockets;
! 288: int maxfds;
! 289: SOCKET s;
! 290: int status = 0;
! 291: struct timeval tvsave;
! 292:
! 293:
! 294: HTEndLoop = 0;
! 295: /* Don't leave this loop until we the application */
! 296: do {
! 297: treadset = FdArray[HTEvent_INDEX(HTEvent_READ)];
! 298: twriteset = FdArray[HTEvent_INDEX(HTEvent_WRITE)];
! 299: texceptset = FdArray[HTEvent_INDEX(HTEvent_OOB)];
! 300: maxfds = max_sock;
! 301:
! 302: if (THD_TRACE)
! 303: HTTrace("Event Loop.. calling select: maxfds is %d\n", maxfds);
! 304: /*
! 305: * timeval struct copy needed for linux, as it set the value to the remaining
! 306: * timeout while exiting the select. (and perhaps for other OS).
! 307: */
! 308: tvsave.tv_sec = tvptr->tv_sec;
! 309: tvsave.tv_usec = tvptr->tv_usec;
! 310:
! 311: #ifdef __hpux
! 312: active_sockets = select(maxfds+1, (int *)&treadset, (int *)&twriteset,
! 313: (int *)&texceptset, (struct timeval *) &tvsave);
! 314: #else
! 315: active_sockets = select(maxfds+1, &treadset, &twriteset, &texceptset,
! 316: (struct timeval *) &tvsave);
! 317: #endif
! 318: if (THD_TRACE)
! 319: HTTrace("Event Loop.. select returns %d\n",active_sockets);
! 320:
! 321: if (active_sockets == -1) {
! 322: HTRequest_addSystemError( theRequest, ERR_FATAL, socerrno, NO, "select");
! 323: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_READ), "Read");
! 324: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_WRITE), "Write") ;
! 325: __DumpFDSet(FdArray+HTEvent_INDEX(HTEvent_OOB), "Exceptions");
! 326: return HT_ERROR;
! 327: }
! 328:
! 329: /* If timeout then see if we should call callback function */
! 330: if (active_sockets == 0) {
! 331: if (seltime.tcbf && (seltime.always || HTNet_isIdle())) {
! 332: #if 0
! 333: /* This drives you crazy! */
! 334: if (THD_TRACE) HTTrace("Event Loop.. select timeout\n");
! 335: #endif
! 336: if ((status = (*(seltime.tcbf))(seltime.request)) != HT_OK)
! 337: return status;
! 338: } else
! 339: continue;
! 340: }
! 341:
! 342: /*
! 343: * there were active sockets. Determine which fd sets they were in
! 344: */
! 345:
! 346: for (s = 0 ; s <= maxfds ; s++) {
! 347: {
! 348: if (FD_ISSET(s, &texceptset))
! 349: if ((status = HTEventList_dispatch(s, HTEvent_OOB)) != HT_OK)
! 350: return status;
! 351: if (FD_ISSET(s, &twriteset))
! 352: if ((status = HTEventList_dispatch(s, HTEvent_WRITE)) != HT_OK)
! 353: return status;
! 354: if (FD_ISSET(s, &treadset))
! 355: if ((status = HTEventList_dispatch(s, HTEvent_READ)) != HT_OK)
! 356: return status;
! 357: }
! 358: }
! 359:
! 360: } while (!HTEndLoop);
! 361: return HT_OK;
! 362: }
! 363:
! 364: /*
! 365: ** HTEventList_dispatch( SOCKET, SockOps )
! 366: **
! 367: ** a little function that just invokes the HTEventCallback routine associated
! 368: ** with the given socket.
! 369: **
! 370: */
! 371: PUBLIC int HTEventList_dispatch (SOCKET s, HTEvent_type type)
! 372: {
! 373: RQ * rqp = NULL;
! 374: if ((rqp = RQ_get(s, RQ_find)) == NULL ||
! 375: rqp->events[HTEvent_INDEX(type)]->priority == HT_PRIORITY_OFF) {
! 376: if (THD_TRACE) HTTrace("Callback.... No callback found\n");
! 377: return (0);
! 378: }
! 379: return (*rqp->events[HTEvent_INDEX(type)]->cbf)(s, rqp->events[HTEvent_INDEX(type)]->param, type);
! 380: }
! 381:
! 382: PRIVATE void __DumpFDSet( fd_set * fdp, const char * str)
! 383: {
! 384: SOCKET s ;
! 385: #ifdef _WINSOCKAPI_
! 386: unsigned ui ;
! 387: #endif
! 388: if (THD_TRACE) {
! 389: HTTrace("Dumping..... %s file descriptor set\n", str );
! 390: #ifdef _WINSOCKAPI_
! 391: for (ui = 0 ; ui < fdp->fd_count; ui++) {
! 392: s = all_fds.fd_array[ui] ;
! 393: #else
! 394: for (s = 0 ; s <= max_sock; s++) {
! 395: if (FD_ISSET(s, fdp))
! 396: #endif
! 397: {
! 398: HTTrace("%4d\n", s);
! 399: }
! 400: } /* for */
! 401: } /* if */
! 402: return ;
! 403: }
! 404:
! 405: /* REGISTER DEFULT EVENT MANAGER
! 406: ** -----------------------------
! 407: ** Not done automaticly - may be done by application!
! 408: */
! 409: PUBLIC BOOL HTEventInit (void)
! 410: {
! 411: HTEvent_setRegisterCallback(HTEventList_register);
! 412: HTEvent_setUnregisterCallback(HTEventList_unregister);
! 413: return YES;
! 414: }
! 415:
! 416: PUBLIC BOOL HTEventTerminate (void)
! 417: {
! 418: return YES;
! 419: }
! 420:
Webmaster