Annotation of libwww/Library/src/HTNet.c, revision 2.18

2.4       frystyk     1: /*                                                                  HTThread.c
                      2: **     MULTIPLE THREAD SOCKET MANAGEMENT
2.1       frystyk     3: **
2.10      frystyk     4: **     (c) COPYRIGHT MIT 1995.
2.4       frystyk     5: **     Please first read the full copyright statement in the file COPYRIGH.
                      6: **
                      7: **     This is the implementation of the internal library multithreading
2.1       frystyk     8: **     functions. This includes an interrupt handler and a event loop.
                      9: **     
                     10: ** History:
2.14      frystyk    11: **     12 June 94      Written by Henrik Frystyk, frystyk@w3.org
2.17      frystyk    12: **      31 May  95      Charlie Brooks cbrooks@osf.org
                     13: **
2.1       frystyk    14: */
                     15: 
2.9       frystyk    16: /* Implemention dependent include files */
                     17: #include "tcp.h"
                     18: 
2.1       frystyk    19: /* Library include files */
                     20: #include "HTUtils.h"
                     21: #include "HTAccess.h"
2.16      frystyk    22: #include "HTProt.h"
2.1       frystyk    23: #include "HTError.h"
                     24: #include "HTThread.h"                                   /* Implemented here */
2.17      frystyk    25: #include "HTEvntrg.h"
2.1       frystyk    26: 
2.9       frystyk    27: #ifdef WIN32
                     28: #include <io.h>
                     29: #endif
                     30: 
2.1       frystyk    31: 
2.17      frystyk    32: PRIVATE HTList *HTThreads = NULL;               /* List of the HTNetInfo structures */
                     33: PRIVATE fd_set nullSet ;
                     34: PRIVATE fd_set HTfd_intr;
                     35: PRIVATE fd_set HTfd_libs ;
                     36: PRIVATE SOCKET libMaxSock = 0 ;
2.1       frystyk    37: 
2.9       frystyk    38: 
2.17      frystyk    39: int LibraryCallback( SOCKET, HTRequest *, SockOps) ;
2.1       frystyk    40: 
                     41: /* ------------------------------------------------------------------------- */
                     42: 
                     43: /*                                                                HTThreadInit
                     44: **
                     45: **     Initiates the thread socket registers. It is very important that
                     46: **     this function is called. It is currently done inside HTAccess in the
                     47: **     HTAccessInit function.
                     48: */
                     49: PUBLIC BOOL HTThreadInit NOARGS
                     50: {
                     51:     static BOOL done=NO;
                     52: 
                     53:     if (done) {
                     54:        if (THD_TRACE)
2.7       frystyk    55:            fprintf(TDEST, "ThreadInit.. Already done\n");
2.1       frystyk    56:        return NO;
                     57:     }
                     58:     done = YES;
2.17      frystyk    59:     FD_ZERO( &HTfd_intr) ;
2.1       frystyk    60:     return YES;
                     61: }
                     62: 
                     63: 
                     64: /*                                                           HTThreadGetFDInfo
                     65: **
                     66: **     Returns the maximum bit width and the read and write bit array.
2.17      frystyk    67: **     N.B. Only used by old HTEvent.c module
2.1       frystyk    68: */
2.17      frystyk    69: 
2.1       frystyk    70: PUBLIC int HTThreadGetFDInfo ARGS2(fd_set *, read, fd_set *, write)
                     71: {
2.17      frystyk    72:     *read = nullSet;
                     73:     *write = nullSet;
                     74:     return libMaxSock;
2.1       frystyk    75: }
                     76: 
2.15      frystyk    77: /*                                                      HTThreadStateByRequest
                     78: **
                     79: **     This function registers a socket as waiting for the action given
                     80: **     (read or write etc.). It uses the request structure to find the socket
                     81: */
                     82: PUBLIC void HTThreadStateByRequest ARGS2(HTRequest *, request,
                     83:                                         HTThreadAction, action)
                     84: {
                     85:     if (request && request->net_info && request->net_info->sockfd != INVSOC)
                     86:        HTThreadState(request->net_info->sockfd, action);
                     87: }
                     88: 
2.17      frystyk    89: 
                     90: 
2.1       frystyk    91: /*                                                               HTThreadState
                     92: **
                     93: **     This function registers a socket as waiting for the action given
                     94: **     (read or write etc.).
2.17      frystyk    95: **
                     96: **     Charlie Brooks - we handle the interrupt thread state internally to this module 
                     97: **      setting the interrupt on a socket disables it from read/write.
2.1       frystyk    98: */
2.7       frystyk    99: PUBLIC void HTThreadState ARGS2(SOCKFD, sockfd, HTThreadAction, action)
2.1       frystyk   100: {
2.17      frystyk   101:     register HTNetInfo * pres ;
                    102:     HTList * cur = HTThreads ;
                    103:     int found = 0 ;
                    104:     HTRequest * reqst ;
                    105: 
2.9       frystyk   106: #ifdef _WIN32
2.17      frystyk   107:        if (sockfd <= 2) 
                    108:                sockfd = _get_osfhandle(sockfd) ;
2.9       frystyk   109: #endif
                    110:   
2.1       frystyk   111:     if (THD_TRACE) {
                    112:        static char *actionmsg[] = {
                    113:            "SET WRITE",
                    114:            "CLEAR WRITE",
                    115:            "SET READ",
                    116:            "CLEAR READ",
2.4       frystyk   117:            "SET INTERRUPT",
                    118:            "CLEAR INTERRUPT",
2.17      frystyk   119:            "CLOSE",
                    120:            "SET CONNECT",
                    121:            "CLEAR CONNECT"
2.1       frystyk   122:            };
2.7       frystyk   123:        fprintf(TDEST,
2.17      frystyk   124:                "Thread...... Registering socket number %d for action %s\n",
2.1       frystyk   125:                sockfd, *(actionmsg+action));
2.17      frystyk   126:     }   /* if */
                    127: 
                    128:     FD_SET( sockfd, &HTfd_libs) ;
                    129:     if (libMaxSock < sockfd)
                    130:        libMaxSock = sockfd ;
                    131: 
                    132: 
                    133:     while ((pres = (HTNetInfo *)HTList_nextObject(cur) ) != 0) { 
                    134:         if (pres->sockfd == sockfd) {
                    135:             found = 1 ;
                    136:             break ;
                    137:         }   /* if */
                    138:     }       /* while */
                    139: 
                    140:     if (! found)    /* how'd you get here? */
                    141:         return ;
                    142: 
                    143:     reqst = pres->request ;
2.1       frystyk   144:     switch (action) {
                    145:       case THD_SET_WRITE:
2.17      frystyk   146:       case THD_SET_CONNECT: 
                    147:         HTEvent_Register( sockfd, reqst, action == THD_SET_WRITE ? (SockOps)FD_WRITE : (SockOps)FD_CONNECT , 
                    148:                LibraryCallback, 0);
2.1       frystyk   149:        break;
                    150: 
                    151:       case THD_CLR_WRITE:
2.17      frystyk   152:       case THD_CLR_CONNECT: 
                    153:         HTEvent_UnRegister( sockfd, action == THD_CLR_WRITE ? (SockOps)FD_WRITE : (SockOps)FD_CONNECT) ;
2.1       frystyk   154:        break;
                    155: 
                    156:       case THD_SET_READ:
2.17      frystyk   157:         HTEvent_Register( sockfd, reqst, (SockOps)FD_READ, LibraryCallback, 0);  
2.1       frystyk   158:        break;
                    159: 
                    160:       case THD_CLR_READ:
2.17      frystyk   161:         HTEvent_UnRegister( sockfd, FD_WRITE) ;
2.1       frystyk   162:        break;
                    163: 
                    164:       case THD_CLOSE:
2.17      frystyk   165:         HTEvent_UnRegister( sockfd, FD_ALL) ;
                    166:        FD_CLR( sockfd, &HTfd_libs);
                    167:        FD_CLR( sockfd, &HTfd_intr);
                    168:        libMaxSock = 0 ;
                    169:        while ((pres = (HTNetInfo *)HTList_nextObject(cur) ) != 0) { 
                    170:            if (pres->sockfd > libMaxSock) {
                    171:                libMaxSock = sockfd ;
                    172:            }   /* if */
                    173:        }       /* while */
                    174: 
2.1       frystyk   175:        break;
                    176: 
2.17      frystyk   177: /*
                    178:  * we handle interrupts locally ... only library sockets can 
                    179:  * be interrupted? 
                    180:  */
                    181: 
2.2       frystyk   182:       case THD_SET_INTR:
2.17      frystyk   183:         HTEvent_UnRegister( sockfd, (SockOps)(FD_READ | FD_WRITE) );
                    184:         FD_SET( sockfd, &HTfd_intr) ;
2.1       frystyk   185:        break;
                    186: 
2.2       frystyk   187:       case THD_CLR_INTR:
2.17      frystyk   188:         FD_CLR( sockfd, &HTfd_intr) ;
                    189:        HTEvent_UnRegister(sockfd, FD_ALL) ;  /* no sin to unregister and unregistered socket */
2.2       frystyk   190:        break;
                    191: 
2.1       frystyk   192:       default:
                    193:        if (THD_TRACE)
2.17      frystyk   194:            fprintf(TDEST, "Thread...... Illegal socket action (%d)\n", (int)action);
2.1       frystyk   195:     }
2.17      frystyk   196:     return ;
2.1       frystyk   197: }
                    198: 
                    199: 
                    200: /*                                                                HTThreadIntr
                    201: **
                    202: **     This function returns YES or NO to the question
                    203: */
2.7       frystyk   204: PUBLIC BOOL HTThreadIntr ARGS1(SOCKFD, sockfd)
2.1       frystyk   205: {
                    206:     return FD_ISSET(sockfd, &HTfd_intr) ? YES : NO;
                    207: }
                    208: 
                    209: 
                    210: /*                                                         HTThreadMarkIntrAll
                    211: **
2.2       frystyk   212: **     Marks all Library sockets as interrupted. User sockets can not be
2.17      frystyk   213: **     interrupted
2.1       frystyk   214: */
2.17      frystyk   215: PUBLIC BOOL HTThreadMarkIntrAll( CONST fd_set * fd_user )
2.1       frystyk   216: {
2.12      frystyk   217:     HTNetInfo *pres;
                    218:     if (HTThreads) {
                    219:        while ((pres = (HTNetInfo *) HTList_lastObject(HTThreads)) != NULL)
                    220:            HTThread_kill(pres);
                    221:        return YES;
                    222:     }
                    223:     return NO;
                    224: 
2.1       frystyk   225: }
                    226: 
                    227: 
                    228: /*                                                              HTThreadActive
                    229: **
                    230: **     Returns yes as long as a socket other than stdin is registered in 
                    231: **     the total set of sockets.
                    232: */
                    233: PUBLIC BOOL HTThreadActive NOARGS
                    234: {
2.17      frystyk   235:     if (libMaxSock > 0)
                    236:        return YES; 
                    237:     else 
                    238:        return NO;
2.1       frystyk   239: }
                    240: 
                    241: 
                    242: /*                                                                HTThread_new
                    243: **
                    244: **     Register the HTNetInfo structure in a list so that we can find the 
2.17      frystyk   245: **     request which corresponds to a socket descriptor
2.1       frystyk   246: */
2.12      frystyk   247: PUBLIC BOOL HTThread_new ARGS1(HTNetInfo *, new_net)
2.1       frystyk   248: {
                    249:     if (!HTThreads)
2.17      frystyk   250:                HTThreads = HTList_new();
2.12      frystyk   251:     return HTList_addObject(HTThreads, (void *) new_net);
2.1       frystyk   252: }
                    253: 
                    254: 
                    255: /*                                                              HTThread_clear
                    256: **
2.17      frystyk   257: **     Remove the HTNetInfo from the list of acrive threads.
2.1       frystyk   258: */
2.12      frystyk   259: PUBLIC BOOL HTThread_clear ARGS1(HTNetInfo *, old_net)
2.1       frystyk   260: {
                    261:     if (HTThreads)
                    262:        return HTList_removeObject(HTThreads, (void *) old_net);
                    263:     return NO;
                    264: }
                    265: 
2.17      frystyk   266: /*                                                           HTThread_isAlive
                    267: **
                    268: **     Checks whether a thread is still registered and if so returns the 
                    269: **     corresponding HTRequest structure, else return NULL.
                    270: */
                    271: PUBLIC HTRequest *HTThread_isAlive ARGS1(HTNetInfo *, net)
                    272: {
                    273:     HTList *cur = HTThreads;
                    274:     HTNetInfo *pres;
                    275:     if (cur && net) {
                    276:        while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
                    277:            if (pres == net) return pres->request;
                    278:        }
                    279:     }
                    280:     if (THD_TRACE)
                    281:        fprintf(TDEST, "Thread...... Thread is not alive\n");
                    282:     return NULL;
                    283: }
                    284: 
                    285: 
                    286: /*
                    287:  *   LibraryCallback - "glue" between 3.0 thread code and new callback functions
                    288:  *   map return codes into a simple yes/no model. 
                    289:  */
                    290: 
                    291: int LibraryCallback( SOCKET s, HTRequest * rq, SockOps f)
                    292: {
                    293:     int status = 0 ;
                    294:     HTEventState state ;
                    295:     HTProtocol * proto = (HTProtocol *)
                    296:             HTAnchor_protocol( rq -> anchor) ;
                    297: 
                    298:     /* begin */    
                    299: 
                    300:     if (proto == 0)    /* Whoa! No protocol! */
                    301:        return -1;
                    302:     status = proto->load( rq ) ;
                    303:     if (status != HT_WOULD_BLOCK) {   /* completed - good or bad... */
                    304:         if (THD_TRACE) 
                    305:             fprintf(TDEST, "LibCallBack. Calling Terminate...\n");
                    306: 
                    307:         HTLoadTerminate( rq, status ) ;
2.18    ! frystyk   308:        if (status != HT_OK) {
        !           309:            state = HTEventRequestTerminate( rq, status) ;
        !           310:            /* if the state isn't EVENT_QUIT */
        !           311:            if (! HTEventCheckState( rq, state ))
2.17      frystyk   312:                return HT_OK;  /* treat as failure */
2.18    ! frystyk   313:        }
2.17      frystyk   314:     }  /* if status */
                    315:     return HT_WOULD_BLOCK;
                    316: }
2.1       frystyk   317: 
2.12      frystyk   318: /*                                                              HTThread_kill
                    319: **
                    320: **     Kill the thread and remove the HTNetInfo from the list of active
                    321: **     threads.
                    322: **     Returns YES on success, NO on error
                    323: **
                    324: **     BUG: We do not take ANSI C file descriptors into account
                    325: */
2.17      frystyk   326: 
2.12      frystyk   327: PUBLIC BOOL HTThread_kill ARGS1(HTNetInfo *, kill_net)
                    328: {
2.17      frystyk   329:     if (HTThreads) {
2.12      frystyk   330:        HTList *cur = HTThreads;
                    331:        HTNetInfo *pres;
                    332: 
                    333:        /* Find the corresponding HTRequest structure */
                    334:        while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
                    335:            if (pres == kill_net) break;
                    336:        }
                    337: 
                    338:        /*
                    339:        **  Now see if a socket is active (or an ANSI C file descriptor).
                    340:        **  If so then mark the thread as interrupted and call the load
                    341:        **  function.
                    342:        */
                    343:        if (pres) {
                    344:            if (kill_net->sockfd != INVSOC) {     /* @@@ ANSI C FIlE DES @@@ */
                    345:                HTProtocol *prot = (HTProtocol *)
                    346:                    HTAnchor_protocol(kill_net->request->anchor);
                    347:                HTThreadState(kill_net->sockfd, THD_SET_INTR);
                    348:                (*(prot->load))(kill_net->request);
                    349:            }
                    350:            return HTThread_clear(kill_net);
2.17      frystyk   351:        } else {
                    352:            if (THD_TRACE)
                    353:                fprintf(TDEST, "Kill Thread. Thread is not registered\n");
                    354:            return NO;
2.12      frystyk   355:        }
                    356:     }
                    357:     return NO;
2.13      frystyk   358: }

Webmaster