Annotation of libwww/Library/src/HTEvtLst.c, revision 1.1.2.4

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

Webmaster