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