File:  [Public] / libwww / Library / src / HTNet.c
Revision 2.7: download - view: text, annotated - select for diffs
Tue Mar 21 17:45:57 1995 UTC (29 years, 2 months ago) by frystyk
Branches: MAIN
CVS tags: v3/0, WindowsNT, HEAD
Getting Library back on main branch

/*								     HTThread.c
**	MULTIPLE THREAD SOCKET MANAGEMENT
**
**	(c) COPYRIGHT CERN 1994.
**	Please first read the full copyright statement in the file COPYRIGH.
**
**	This is the implementation of the internal library multithreading
**	functions. This includes an interrupt handler and a event loop.
**	
** History:
**  	12 June 94	Written by Henrik Frystyk, frystyk@dxcern.cern.ch
*/

/* Library include files */
#include "tcp.h"
#include "HTUtils.h"
#include "HTAccess.h"
#include "HTError.h"
#include "HTThread.h"					 /* Implemented here */

/* Type definitions and global variables etc. local to this module */
PRIVATE fd_set	HTfd_read;	      /* Bit array of sockets ready for read */
PRIVATE fd_set	HTfd_write;	     /* Bit array of sockets ready for write */
PRIVATE int 	HTMaxfdpl = 0;			/* Max number of sockets + 1 */

PRIVATE fd_set	HTfd_intr;	        /* All sockets currently interrupted */
PRIVATE fd_set	HTfd_set;	         /* All sockets currently registered */

PRIVATE HTList *HTThreads = NULL;      	 /* List of the HTNetInfo structures */

/* ------------------------------------------------------------------------- */

/*								   HTThreadInit
**
**	Initiates the thread socket registers. It is very important that
**	this function is called. It is currently done inside HTAccess in the
**	HTAccessInit function.
*/
PUBLIC BOOL HTThreadInit NOARGS
{
    static BOOL done=NO;

    if (done) {
	if (THD_TRACE)
	    fprintf(TDEST, "ThreadInit.. Already done\n");
	return NO;
    }
    done = YES;

    /* Initialize the other internal bit arrays */
    FD_ZERO(&HTfd_write);
    FD_ZERO(&HTfd_set);
    FD_ZERO(&HTfd_intr);
    return YES;
}


/*							      HTThreadGetFDInfo
**
**	Returns the maximum bit width and the read and write bit array.
*/
PUBLIC int HTThreadGetFDInfo ARGS2(fd_set *, read, fd_set *, write)
{
    *read = HTfd_read;
    *write = HTfd_write;
    return HTMaxfdpl;
}


/*								  HTThreadState
**
**	This function registers a socket as waiting for the action given
**	(read or write etc.).
*/
PUBLIC void HTThreadState ARGS2(SOCKFD, sockfd, HTThreadAction, action)
{
    if (THD_TRACE) {
	static char *actionmsg[] = {
	    "SET WRITE",
	    "CLEAR WRITE",
	    "SET READ",
	    "CLEAR READ",
	    "SET INTERRUPT",
	    "CLEAR INTERRUPT",
	    "CLOSE"
	    };
	fprintf(TDEST,
		"Thread...... Register socket number %d for action %s\n",
		sockfd, *(actionmsg+action));
    }
    switch (action) {
      case THD_SET_WRITE:
	FD_CLR(sockfd, &HTfd_read);
	FD_SET(sockfd, &HTfd_write);
	FD_SET(sockfd, &HTfd_set);
	break;

      case THD_CLR_WRITE:
	FD_CLR(sockfd, &HTfd_read);
	FD_CLR(sockfd, &HTfd_write);
	FD_CLR(sockfd, &HTfd_set);
	break;

      case THD_SET_READ:
	FD_SET(sockfd, &HTfd_read);
	FD_CLR(sockfd, &HTfd_write);
	FD_SET(sockfd, &HTfd_set);
	break;

      case THD_CLR_READ:
	FD_CLR(sockfd, &HTfd_read);
	FD_CLR(sockfd, &HTfd_write);
	FD_CLR(sockfd, &HTfd_set);
	break;

      case THD_CLOSE:
	FD_CLR(sockfd, &HTfd_read);
	FD_CLR(sockfd, &HTfd_write);
	FD_CLR(sockfd, &HTfd_intr);
	FD_CLR(sockfd, &HTfd_set);
	break;

      case THD_SET_INTR:
	FD_CLR(sockfd, &HTfd_read);
	FD_CLR(sockfd, &HTfd_write);
	FD_SET(sockfd, &HTfd_intr);
	break;

      case THD_CLR_INTR:
	FD_CLR(sockfd, &HTfd_intr);
	break;

      default:
	if (THD_TRACE)
	    fprintf(TDEST, "Thread...... Illigal socket action\n");
    }

    /* Update max bit width. The method used ignores any other default
       opened file descriptors between 0 and the actual set of file
       descriptors used. However, they are not registered anyway */
    if (action == THD_CLOSE) {
	if (sockfd+1 >= HTMaxfdpl) {
	    while (HTMaxfdpl > 0 && !FD_ISSET(HTMaxfdpl-1, &HTfd_set))
		HTMaxfdpl--;
	}
    } else {
	if (sockfd+1 > HTMaxfdpl)
	    HTMaxfdpl = sockfd+1;
    }
    if (THD_TRACE)
	fprintf(TDEST, "Thread...... Max bitwidth is %d\n", HTMaxfdpl);
}


/*								   HTThreadIntr
**
**	This function returns YES or NO to the question
*/
PUBLIC BOOL HTThreadIntr ARGS1(SOCKFD, sockfd)
{
    return FD_ISSET(sockfd, &HTfd_intr) ? YES : NO;
}


/*							    HTThreadMarkIntrAll
**
**	Marks all Library sockets as interrupted. User sockets can not be
**	interrupted
*/
PUBLIC void HTThreadMarkIntrAll ARGS1(CONST fd_set *,	fd_user)
{
    int cnt;
    if (THD_TRACE)
	fprintf(TDEST, "Thread...... Mark ALL Library sockfd INTERRUPTED\n");
    for (cnt=0; cnt<HTMaxfdpl; cnt++) {
	if (FD_ISSET(cnt, &HTfd_set) && !FD_ISSET(cnt, fd_user))
	    FD_SET(cnt, &HTfd_intr);
    }
}


/*								 HTThreadActive
**
**	Returns yes as long as a socket other than stdin is registered in 
**	the total set of sockets.
*/
PUBLIC BOOL HTThreadActive NOARGS
{
    int cnt;
    for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++)
	if (FD_ISSET(cnt, &HTfd_set))
	    return YES;
    return NO;
}


/*							     	   HTThread_new
**
**	Register the HTNetInfo structure in a list so that we can find the 
**	request which corresponds to a socket descriptor
*/
PUBLIC void HTThread_new ARGS1(HTNetInfo *, new_net)
{
    if (!HTThreads)
	HTThreads = HTList_new();
    HTList_addObject(HTThreads, (void *) new_net);
}


/*							         HTThread_clear
**
**	Remove the HTNetInfo from the list of acrive threads.
*/
PUBLIC int HTThread_clear ARGS1(HTNetInfo *, old_net)
{
    if (HTThreads)
	return HTList_removeObject(HTThreads, (void *) old_net);
    return NO;
}


/*							   HTThread_getCallBack
**
**	Finds a socket and makes it the active thread. READ has a higher
**	priority than WRITE as it might influence (stop) the WRITE process.
**	Returns the request structure of the active thread, NULL on error.
**	A interrupted socket has the highest priority
*/
PUBLIC HTRequest *HTThread_getRequest ARGS2(CONST fd_set *,	fd_read,
					    CONST fd_set *, 	fd_write)
{
    HTList *cur = HTThreads;
    HTNetInfo *pres;
    SOCKFD cnt;
    BOOL found = NO;
    for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) {		/* INTERRUPT */
	if (FD_ISSET(cnt, &HTfd_intr)) {
	    if (THD_TRACE)
		fprintf(TDEST, "GetSocket... Socket %d INTERRUPTED\n", cnt);
	    found = YES;
	    break;
	}
    }
    if (!found) {
	for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) {	     /* READ */
	    if (FD_ISSET(cnt, fd_read)) {
		if (THD_TRACE)
		    fprintf(TDEST, "GetSocket... Socket %d for READ\n", cnt);
		found = YES;
		break;
	    }
	}
    }
    if (!found) {
	for (cnt=STDIN_FILENO+1; cnt<HTMaxfdpl; cnt++) {   	    /* WRITE */
	    if (FD_ISSET(cnt, fd_write)) {
		if (THD_TRACE)
		    fprintf(TDEST, "GetSocket... Socket %d for WRITE\n", cnt);
		found = YES;
		break;
	    }
	}
    }
    if (!found || cur == NULL)
	return NULL;

    /* Find the corresponding HTNetInfo structure */
    while ((pres = (HTNetInfo *) HTList_nextObject(cur)) != NULL) {
	if (pres->sockfd == cnt) {
	    return pres->request;
	}
    }
    return NULL;
}

Webmaster