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

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

Webmaster