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

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

Webmaster