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

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.1       frystyk    12: */
                     13: 
2.9       frystyk    14: /* Implemention dependent include files */
                     15: #include "tcp.h"
                     16: 
2.1       frystyk    17: /* Library include files */
                     18: #include "HTUtils.h"
                     19: #include "HTAccess.h"
                     20: #include "HTError.h"
                     21: #include "HTThread.h"                                   /* Implemented here */
                     22: 
2.9       frystyk    23: #ifdef WIN32
                     24: #include <io.h>
                     25: #endif
                     26: 
2.1       frystyk    27: /* Type definitions and global variables etc. local to this module */
                     28: PRIVATE fd_set HTfd_read;            /* Bit array of sockets ready for read */
                     29: PRIVATE fd_set HTfd_write;          /* Bit array of sockets ready for write */
                     30: PRIVATE int    HTMaxfdpl = 0;                  /* Max number of sockets + 1 */
                     31: 
                     32: PRIVATE fd_set HTfd_intr;              /* All sockets currently interrupted */
                     33: PRIVATE fd_set HTfd_set;                /* All sockets currently registered */
                     34: 
2.9       frystyk    35: 
2.1       frystyk    36: PRIVATE HTList *HTThreads = NULL;               /* List of the HTNetInfo structures */
                     37: 
                     38: /* ------------------------------------------------------------------------- */
                     39: 
                     40: /*                                                                HTThreadInit
                     41: **
                     42: **     Initiates the thread socket registers. It is very important that
                     43: **     this function is called. It is currently done inside HTAccess in the
                     44: **     HTAccessInit function.
                     45: */
                     46: PUBLIC BOOL HTThreadInit NOARGS
                     47: {
                     48:     static BOOL done=NO;
                     49: 
                     50:     if (done) {
                     51:        if (THD_TRACE)
2.7       frystyk    52:            fprintf(TDEST, "ThreadInit.. Already done\n");
2.1       frystyk    53:        return NO;
                     54:     }
                     55:     done = YES;
                     56: 
                     57:     /* Initialize the other internal bit arrays */
                     58:     FD_ZERO(&HTfd_write);
                     59:     FD_ZERO(&HTfd_set);
                     60:     FD_ZERO(&HTfd_intr);
2.9       frystyk    61:        FD_ZERO(&HTfd_read) ;
                     62: 
2.1       frystyk    63:     return YES;
                     64: }
                     65: 
                     66: 
                     67: /*                                                           HTThreadGetFDInfo
                     68: **
                     69: **     Returns the maximum bit width and the read and write bit array.
                     70: */
                     71: PUBLIC int HTThreadGetFDInfo ARGS2(fd_set *, read, fd_set *, write)
                     72: {
                     73:     *read = HTfd_read;
                     74:     *write = HTfd_write;
                     75:     return HTMaxfdpl;
                     76: }
                     77: 
                     78: 
                     79: /*                                                               HTThreadState
                     80: **
                     81: **     This function registers a socket as waiting for the action given
                     82: **     (read or write etc.).
                     83: */
2.7       frystyk    84: PUBLIC void HTThreadState ARGS2(SOCKFD, sockfd, HTThreadAction, action)
2.1       frystyk    85: {
2.9       frystyk    86: #ifdef _WIN32
2.12      frystyk    87:     if (sockfd <= 2)
                     88:        sockfd = _get_osfhandle(sockfd);
2.9       frystyk    89: #endif
                     90:   
2.1       frystyk    91:     if (THD_TRACE) {
                     92:        static char *actionmsg[] = {
                     93:            "SET WRITE",
                     94:            "CLEAR WRITE",
                     95:            "SET READ",
                     96:            "CLEAR READ",
2.4       frystyk    97:            "SET INTERRUPT",
                     98:            "CLEAR INTERRUPT",
2.1       frystyk    99:            "CLOSE"
                    100:            };
2.7       frystyk   101:        fprintf(TDEST,
2.1       frystyk   102:                "Thread...... Register socket number %d for action %s\n",
                    103:                sockfd, *(actionmsg+action));
                    104:     }
                    105:     switch (action) {
                    106:       case THD_SET_WRITE:
                    107:        FD_CLR(sockfd, &HTfd_read);
2.12      frystyk   108:        if (!FD_ISSET(sockfd, &HTfd_write))
                    109:            FD_SET(sockfd, &HTfd_write);
                    110:        if (!FD_ISSET(sockfd, &HTfd_set))
                    111:            FD_SET(sockfd, &HTfd_set);
2.1       frystyk   112:        break;
                    113: 
                    114:       case THD_CLR_WRITE:
                    115:        FD_CLR(sockfd, &HTfd_read);
                    116:        FD_CLR(sockfd, &HTfd_write);
                    117:        FD_CLR(sockfd, &HTfd_set);
                    118:        break;
                    119: 
                    120:       case THD_SET_READ:
2.12      frystyk   121:        if (!FD_ISSET(sockfd, &HTfd_read))
                    122:            FD_SET(sockfd, &HTfd_read);
2.1       frystyk   123:        FD_CLR(sockfd, &HTfd_write);
2.12      frystyk   124:        if (!FD_ISSET(sockfd, &HTfd_set))
                    125:            FD_SET(sockfd, &HTfd_set);
2.1       frystyk   126:        break;
                    127: 
                    128:       case THD_CLR_READ:
                    129:        FD_CLR(sockfd, &HTfd_read);
                    130:        FD_CLR(sockfd, &HTfd_write);
                    131:        FD_CLR(sockfd, &HTfd_set);
                    132:        break;
                    133: 
                    134:       case THD_CLOSE:
                    135:        FD_CLR(sockfd, &HTfd_read);
                    136:        FD_CLR(sockfd, &HTfd_write);
                    137:        FD_CLR(sockfd, &HTfd_intr);
                    138:        FD_CLR(sockfd, &HTfd_set);
                    139:        break;
                    140: 
2.2       frystyk   141:       case THD_SET_INTR:
2.1       frystyk   142:        FD_CLR(sockfd, &HTfd_read);
                    143:        FD_CLR(sockfd, &HTfd_write);
2.12      frystyk   144:        if (!FD_ISSET(sockfd, &HTfd_intr))
                    145:            FD_SET(sockfd, &HTfd_intr);
2.1       frystyk   146:        break;
                    147: 
2.2       frystyk   148:       case THD_CLR_INTR:
                    149:        FD_CLR(sockfd, &HTfd_intr);
                    150:        break;
                    151: 
2.1       frystyk   152:       default:
                    153:        if (THD_TRACE)
2.7       frystyk   154:            fprintf(TDEST, "Thread...... Illigal socket action\n");
2.1       frystyk   155:     }
                    156: 
                    157:     /* Update max bit width. The method used ignores any other default
2.2       frystyk   158:        opened file descriptors between 0 and the actual set of file
                    159:        descriptors used. However, they are not registered anyway */
2.9       frystyk   160: 
2.1       frystyk   161:     if (action == THD_CLOSE) {
2.9       frystyk   162: #ifdef _WINSOCKAPI_
                    163:        HTMaxfdpl = HTfd_set.fd_count ;
                    164: #else 
2.1       frystyk   165:        if (sockfd+1 >= HTMaxfdpl) {
2.2       frystyk   166:            while (HTMaxfdpl > 0 && !FD_ISSET(HTMaxfdpl-1, &HTfd_set))
2.1       frystyk   167:                HTMaxfdpl--;
                    168:        }
2.9       frystyk   169: #endif
2.1       frystyk   170:     } else {
2.9       frystyk   171: #ifdef _WINSOCKAPI_
                    172:        HTMaxfdpl = HTfd_set.fd_count;
                    173: #else
2.1       frystyk   174:        if (sockfd+1 > HTMaxfdpl)
                    175:            HTMaxfdpl = sockfd+1;
2.9       frystyk   176: #endif 
2.1       frystyk   177:     }
                    178:     if (THD_TRACE)
2.7       frystyk   179:        fprintf(TDEST, "Thread...... Max bitwidth is %d\n", HTMaxfdpl);
2.1       frystyk   180: }
                    181: 
                    182: 
                    183: /*                                                                HTThreadIntr
                    184: **
                    185: **     This function returns YES or NO to the question
                    186: */
2.7       frystyk   187: PUBLIC BOOL HTThreadIntr ARGS1(SOCKFD, sockfd)
2.1       frystyk   188: {
                    189:     return FD_ISSET(sockfd, &HTfd_intr) ? YES : NO;
                    190: }
                    191: 
                    192: 
                    193: /*                                                         HTThreadMarkIntrAll
                    194: **
2.2       frystyk   195: **     Marks all Library sockets as interrupted. User sockets can not be
2.12      frystyk   196: **     interrupted.
2.1       frystyk   197: */
2.12      frystyk   198: PUBLIC BOOL HTThreadMarkIntrAll ARGS1(CONST fd_set *, fd_user)
2.1       frystyk   199: {
2.12      frystyk   200:     HTNetInfo *pres;
                    201:     if (HTThreads) {
                    202:        while ((pres = (HTNetInfo *) HTList_lastObject(HTThreads)) != NULL)
                    203:            HTThread_kill(pres);
                    204:        return YES;
                    205:     }
                    206:     return NO;
                    207: 
                    208: #if 0
                    209:     /*
                    210:     ** Use the HTThread list instead of the bit arrays. This makes it easier
                    211:     ** to execute a kill thread right away
                    212:     */
2.1       frystyk   213:     int cnt;
2.9       frystyk   214: #ifdef _WINSOCKAPI_
                    215:     int i;
                    216: #endif
2.1       frystyk   217:     if (THD_TRACE)
2.7       frystyk   218:        fprintf(TDEST, "Thread...... Mark ALL Library sockfd INTERRUPTED\n");
2.9       frystyk   219: #ifdef _WINSOCKAPI_
                    220:     for (i = 0 ; i < HTfd_set.fd_count; i++) {
                    221:        cnt = HTfd_set.fd_array[i];
                    222:        if (!FD_ISSET(cnt, fd_user))
                    223: #else
2.2       frystyk   224:     for (cnt=0; cnt<HTMaxfdpl; cnt++) {
2.4       frystyk   225:        if (FD_ISSET(cnt, &HTfd_set) && !FD_ISSET(cnt, fd_user))
2.9       frystyk   226: #endif
2.4       frystyk   227:            FD_SET(cnt, &HTfd_intr);
2.2       frystyk   228:     }
2.12      frystyk   229: #endif
2.1       frystyk   230: }
                    231: 
                    232: 
                    233: /*                                                              HTThreadActive
                    234: **
                    235: **     Returns yes as long as a socket other than stdin is registered in 
                    236: **     the total set of sockets.
                    237: */
                    238: PUBLIC BOOL HTThreadActive NOARGS
                    239: {
                    240:     int cnt;
2.9       frystyk   241: #ifdef _WINSOCKAPI_
                    242:     if (HTfd_set.fd_count > 0)
                    243:        return YES;
                    244: #else
2.1       frystyk   245:     for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++)
                    246:        if (FD_ISSET(cnt, &HTfd_set))
                    247:            return YES;
2.9       frystyk   248: #endif
2.1       frystyk   249:     return NO;
                    250: }
                    251: 
                    252: 
                    253: /*                                                                HTThread_new
                    254: **
                    255: **     Register the HTNetInfo structure in a list so that we can find the 
2.12      frystyk   256: **     request which corresponds to a socket descriptor.
                    257: **     Returns YES on success, NO on error
2.1       frystyk   258: */
2.12      frystyk   259: PUBLIC BOOL HTThread_new ARGS1(HTNetInfo *, new_net)
2.1       frystyk   260: {
                    261:     if (!HTThreads)
                    262:        HTThreads = HTList_new();
2.12      frystyk   263:     return HTList_addObject(HTThreads, (void *) new_net);
2.1       frystyk   264: }
                    265: 
                    266: 
                    267: /*                                                              HTThread_clear
                    268: **
2.12      frystyk   269: **     Remove the HTNetInfo from the list of active threads.
                    270: **     Returns YES on success, NO on error
2.1       frystyk   271: */
2.12      frystyk   272: PUBLIC BOOL HTThread_clear ARGS1(HTNetInfo *, old_net)
2.1       frystyk   273: {
                    274:     if (HTThreads)
                    275:        return HTList_removeObject(HTThreads, (void *) old_net);
                    276:     return NO;
                    277: }
                    278: 
                    279: 
2.12      frystyk   280: /*                                                              HTThread_kill
                    281: **
                    282: **     Kill the thread and remove the HTNetInfo from the list of active
                    283: **     threads.
                    284: **     Returns YES on success, NO on error
                    285: **
                    286: **     BUG: We do not take ANSI C file descriptors into account
                    287: */
                    288: PUBLIC BOOL HTThread_kill ARGS1(HTNetInfo *, kill_net)
                    289: {
2.13      frystyk   290:     if (kill_net && HTThreads) {
2.12      frystyk   291:        HTList *cur = HTThreads;
                    292:        HTNetInfo *pres;
                    293: 
                    294:        /* Find the corresponding HTRequest structure */
                    295:        while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
                    296:            if (pres == kill_net) break;
                    297:        }
                    298: 
                    299:        /*
                    300:        **  Now see if a socket is active (or an ANSI C file descriptor).
                    301:        **  If so then mark the thread as interrupted and call the load
                    302:        **  function.
                    303:        */
                    304:        if (pres) {
                    305:            if (kill_net->sockfd != INVSOC) {     /* @@@ ANSI C FIlE DES @@@ */
                    306:                HTProtocol *prot = (HTProtocol *)
                    307:                    HTAnchor_protocol(kill_net->request->anchor);
                    308:                HTThreadState(kill_net->sockfd, THD_SET_INTR);
                    309:                (*(prot->load))(kill_net->request);
                    310:            }
                    311:            return HTThread_clear(kill_net);
                    312:        }
                    313:     }
2.13      frystyk   314:     if (THD_TRACE)
                    315:        fprintf(TDEST, "Kill Thread. Thread is not registered\n");
2.12      frystyk   316:     return NO;
2.13      frystyk   317: }
                    318: 
                    319: 
                    320: /*                                                           HTThread_isAlive
                    321: **
                    322: **     Checks whether a thread is still registered and if so returns the 
                    323: **     corresponding HTRequest structure, else return NULL.
                    324: */
                    325: PUBLIC HTRequest *HTThread_isAlive ARGS1(HTNetInfo *, net)
                    326: {
                    327:     HTList *cur = HTThreads;
                    328:     HTNetInfo *pres;
                    329:     if (cur && net) {
                    330:        while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
                    331:            if (pres == net) return pres->request;
                    332:        }
                    333:     }
                    334:     if (THD_TRACE)
                    335:        fprintf(TDEST, "Thread...... Thread is not alive\n");
                    336:     return NULL;
2.12      frystyk   337: }
                    338: 
                    339: 
2.1       frystyk   340: /*                                                        HTThread_getCallBack
                    341: **
                    342: **     Finds a socket and makes it the active thread. READ has a higher
                    343: **     priority than WRITE as it might influence (stop) the WRITE process.
                    344: **     Returns the request structure of the active thread, NULL on error.
                    345: **     A interrupted socket has the highest priority
                    346: */
                    347: PUBLIC HTRequest *HTThread_getRequest ARGS2(CONST fd_set *,    fd_read,
                    348:                                            CONST fd_set *,     fd_write)
                    349: {
2.7       frystyk   350:     SOCKFD cnt;
2.8       frystyk   351:     SocAction found = SOC_INVALID;
2.9       frystyk   352: 
                    353: #ifdef _WINSOCKAPI_
                    354:     int ic = 0;
                    355: #endif
                    356: 
2.12      frystyk   357: #if 0
                    358: 
                    359: /* Should not be necessary after we have HTThread_kill() */
2.9       frystyk   360: #ifdef _WINSOCKAPI_
2.12      frystyk   361:     for (ic = 0; ic < HTfd_set.fd_count; ic++) {
                    362:        cnt = HTfd_set.fd_array[ic];
2.9       frystyk   363: #else
2.1       frystyk   364:     for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) {           /* INTERRUPT */
2.9       frystyk   365: #endif
2.1       frystyk   366:        if (FD_ISSET(cnt, &HTfd_intr)) {
                    367:            if (THD_TRACE)
2.7       frystyk   368:                fprintf(TDEST, "GetSocket... Socket %d INTERRUPTED\n", cnt);
2.8       frystyk   369:            found = SOC_INTERRUPT;
2.1       frystyk   370:            break;
                    371:        }
                    372:     }
2.9       frystyk   373: 
2.12      frystyk   374: #endif
                    375: 
2.8       frystyk   376:     if (found == SOC_INVALID) {
2.9       frystyk   377: #ifdef _WINSOCKAPI_
                    378:        for (ic = 0; ic < HTfd_set.fd_count; ic++) {
                    379:            cnt = HTfd_set.fd_array[ic]; 
                    380: #else
2.1       frystyk   381:        for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) {             /* READ */
2.9       frystyk   382: #endif
2.1       frystyk   383:            if (FD_ISSET(cnt, fd_read)) {
                    384:                if (THD_TRACE)
2.7       frystyk   385:                    fprintf(TDEST, "GetSocket... Socket %d for READ\n", cnt);
2.8       frystyk   386:                found = SOC_READ;
2.1       frystyk   387:                break;
                    388:            }
                    389:        }
                    390:     }
2.9       frystyk   391: 
2.8       frystyk   392:     if (found == SOC_INVALID) {
2.9       frystyk   393: #ifdef _WINSOCKAPI_
                    394:        for (ic = 0; ic < HTfd_set.fd_count; ic++) {
                    395:            cnt = HTfd_set.fd_array[ic]; 
                    396: #else
                    397:         for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) {           /* WRITE */
                    398: #endif
2.1       frystyk   399:            if (FD_ISSET(cnt, fd_write)) {
                    400:                if (THD_TRACE)
2.7       frystyk   401:                    fprintf(TDEST, "GetSocket... Socket %d for WRITE\n", cnt);
2.8       frystyk   402:                found = SOC_WRITE;
2.1       frystyk   403:                break;
                    404:            }
                    405:        }
                    406:     }
2.9       frystyk   407: 
2.12      frystyk   408:     if (found == SOC_INVALID)
2.1       frystyk   409:        return NULL;
                    410: 
2.8       frystyk   411:     /* Find the corresponding HTNetInfo and HTRequest structure */
2.12      frystyk   412:     {
                    413:        HTList *cur = HTThreads;
                    414:        HTNetInfo *pres;
                    415:        if (cur) {
                    416:            while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
                    417:                if (pres->sockfd == cnt) {
                    418:                    pres->action = found;
                    419:                    return pres->request;
                    420:                }
                    421:            }
2.1       frystyk   422:        }
                    423:     }
                    424:     return NULL;
                    425: }
2.9       frystyk   426: 

Webmaster