No longer using a threading model; so these files have been replaced by
the child.c/child.h files (which use a pre-forked model.)
This commit is contained in:
		
							parent
							
								
									1fda8899b1
								
							
						
					
					
						commit
						c35e56ae66
					
				
							
								
								
									
										400
									
								
								src/thread.c
									
									
									
									
									
								
							
							
						
						
									
										400
									
								
								src/thread.c
									
									
									
									
									
								
							@ -1,400 +0,0 @@
 | 
			
		||||
/* $Id: thread.c,v 1.31 2002-05-24 04:45:32 rjkaes Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * Handles the creation/destruction of the various threads required for
 | 
			
		||||
 * processing incoming connections.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2000 Robert James Kaes (rjkaes@flarenet.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any
 | 
			
		||||
 * later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "tinyproxy.h"
 | 
			
		||||
 | 
			
		||||
#include "heap.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "reqs.h"
 | 
			
		||||
#include "sock.h"
 | 
			
		||||
#include "thread.h"
 | 
			
		||||
#include "utils.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is the stack frame size used by all the threads. We'll start by
 | 
			
		||||
 * setting it to 32 KB.
 | 
			
		||||
 */
 | 
			
		||||
#define THREAD_STACK_SIZE (1024 * 32)
 | 
			
		||||
 | 
			
		||||
static int listenfd;
 | 
			
		||||
static socklen_t addrlen;
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Stores the internal data needed for each thread (connection)
 | 
			
		||||
 */
 | 
			
		||||
struct thread_s {
 | 
			
		||||
	pthread_t tid;
 | 
			
		||||
	enum { T_EMPTY, T_WAITING, T_CONNECTED } status;
 | 
			
		||||
	unsigned int connects;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * A pointer to an array of threads. A certain number of threads are
 | 
			
		||||
 * created when the program is started.
 | 
			
		||||
 */
 | 
			
		||||
static struct thread_s *thread_ptr;
 | 
			
		||||
static pthread_mutex_t mlock;
 | 
			
		||||
 | 
			
		||||
#define ACCEPT_LOCK() do { \
 | 
			
		||||
int accept_lock_ret = pthread_mutex_lock(&mlock); \
 | 
			
		||||
assert(accept_lock_ret == 0); \
 | 
			
		||||
} while (0)
 | 
			
		||||
#define ACCEPT_UNLOCK() do { \
 | 
			
		||||
int accept_lock_ret = pthread_mutex_unlock(&mlock); \
 | 
			
		||||
assert(accept_lock_ret == 0); \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/* Used to override the default stack size. */
 | 
			
		||||
static pthread_attr_t thread_attr;
 | 
			
		||||
 | 
			
		||||
static struct thread_config_s {
 | 
			
		||||
	unsigned int maxclients, maxrequestsperchild;
 | 
			
		||||
	unsigned int maxspareservers, minspareservers, startservers;
 | 
			
		||||
} thread_config;
 | 
			
		||||
 | 
			
		||||
static int servers_waiting = 0;	/* servers waiting for a connection */
 | 
			
		||||
static pthread_mutex_t servers_mutex;
 | 
			
		||||
 | 
			
		||||
#define SERVER_COUNT_LOCK()   do { \
 | 
			
		||||
int servers_mutex_ret = pthread_mutex_lock(&servers_mutex); \
 | 
			
		||||
assert(servers_mutex_ret == 0); \
 | 
			
		||||
} while (0)
 | 
			
		||||
#define SERVER_COUNT_UNLOCK() do { \
 | 
			
		||||
int servers_mutex_ret = pthread_mutex_unlock(&servers_mutex); \
 | 
			
		||||
assert(servers_mutex_ret == 0); \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define SERVER_INC() do { \
 | 
			
		||||
    SERVER_COUNT_LOCK(); \
 | 
			
		||||
    ++servers_waiting; \
 | 
			
		||||
    DEBUG2("INC: servers_waiting: %d", servers_waiting); \
 | 
			
		||||
    SERVER_COUNT_UNLOCK(); \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
#define SERVER_DEC() do { \
 | 
			
		||||
    SERVER_COUNT_LOCK(); \
 | 
			
		||||
    --servers_waiting; \
 | 
			
		||||
    DEBUG2("DEC: servers_waiting: %d", servers_waiting); \
 | 
			
		||||
    SERVER_COUNT_UNLOCK(); \
 | 
			
		||||
} while (0)
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Set the configuration values for the various thread related settings.
 | 
			
		||||
 */
 | 
			
		||||
short int
 | 
			
		||||
thread_configure(thread_config_t type, unsigned int val)
 | 
			
		||||
{
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case THREAD_MAXCLIENTS:
 | 
			
		||||
		thread_config.maxclients = val;
 | 
			
		||||
		break;
 | 
			
		||||
	case THREAD_MAXSPARESERVERS:
 | 
			
		||||
		thread_config.maxspareservers = val;
 | 
			
		||||
		break;
 | 
			
		||||
	case THREAD_MINSPARESERVERS:
 | 
			
		||||
		thread_config.minspareservers = val;
 | 
			
		||||
		break;
 | 
			
		||||
	case THREAD_STARTSERVERS:
 | 
			
		||||
		thread_config.startservers = val;
 | 
			
		||||
		break;
 | 
			
		||||
	case THREAD_MAXREQUESTSPERCHILD:
 | 
			
		||||
		thread_config.maxrequestsperchild = val;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		DEBUG2("Invalid type (%d)", type);
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * This is the main (per thread) loop.
 | 
			
		||||
 */
 | 
			
		||||
static void *
 | 
			
		||||
thread_main(void *arg)
 | 
			
		||||
{
 | 
			
		||||
	int connfd;
 | 
			
		||||
	struct sockaddr *cliaddr;
 | 
			
		||||
	socklen_t clilen;
 | 
			
		||||
	struct thread_s *ptr;
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_PTHREAD_CANCEL
 | 
			
		||||
	/* Set the cancellation type to immediate. */
 | 
			
		||||
	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	ptr = (struct thread_s *) arg;
 | 
			
		||||
 | 
			
		||||
	cliaddr = safemalloc(addrlen);
 | 
			
		||||
	if (!cliaddr)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	ptr->connects = 0;
 | 
			
		||||
 | 
			
		||||
	while (!config.quit) {
 | 
			
		||||
		ptr->status = T_WAITING;
 | 
			
		||||
 | 
			
		||||
		clilen = addrlen;
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Check to see if the program is shutting down.
 | 
			
		||||
		 */
 | 
			
		||||
		if (config.quit)
 | 
			
		||||
			break;
 | 
			
		||||
		
 | 
			
		||||
		ACCEPT_LOCK();
 | 
			
		||||
		connfd = accept(listenfd, cliaddr, &clilen);
 | 
			
		||||
		ACCEPT_UNLOCK();
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
		 * Make sure no error occurred...
 | 
			
		||||
		 */
 | 
			
		||||
		if (connfd < 0) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * Accept could return an "error" if it was
 | 
			
		||||
			 * interrupted by a signal (like when the program
 | 
			
		||||
			 * should be killed. :)
 | 
			
		||||
			 */
 | 
			
		||||
			if (config.quit)
 | 
			
		||||
				break;
 | 
			
		||||
 | 
			
		||||
			log_message(LOG_ERR, "Accept returned an error (%s) ... retrying.", strerror(errno));
 | 
			
		||||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ptr->status = T_CONNECTED;
 | 
			
		||||
 | 
			
		||||
		SERVER_DEC();
 | 
			
		||||
 | 
			
		||||
		handle_connection(connfd);
 | 
			
		||||
 | 
			
		||||
		if (thread_config.maxrequestsperchild != 0) {
 | 
			
		||||
			ptr->connects++;
 | 
			
		||||
 | 
			
		||||
			DEBUG2("%u connections so far...", ptr->connects);
 | 
			
		||||
 | 
			
		||||
			if (ptr->connects >= thread_config.maxrequestsperchild) {
 | 
			
		||||
				log_message(LOG_NOTICE,
 | 
			
		||||
					    "Thread has reached MaxRequestsPerChild (%u > %u). Killing thread.",
 | 
			
		||||
					    ptr->connects,
 | 
			
		||||
					    thread_config.maxrequestsperchild);
 | 
			
		||||
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SERVER_COUNT_LOCK();
 | 
			
		||||
		if (servers_waiting > thread_config.maxspareservers) {
 | 
			
		||||
			/*
 | 
			
		||||
			 * There are too many spare threads, kill ourself
 | 
			
		||||
			 * off.
 | 
			
		||||
			 */
 | 
			
		||||
			log_message(LOG_NOTICE,
 | 
			
		||||
				    "Waiting servers (%d) exceeds MaxSpareServers (%d). Killing thread.",
 | 
			
		||||
				    servers_waiting, thread_config.maxspareservers);
 | 
			
		||||
			SERVER_COUNT_UNLOCK();
 | 
			
		||||
 | 
			
		||||
			break;
 | 
			
		||||
		} else {
 | 
			
		||||
			SERVER_COUNT_UNLOCK();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		SERVER_INC();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ptr->status = T_EMPTY;
 | 
			
		||||
 | 
			
		||||
	safefree(cliaddr);
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Create the initial pool of threads.
 | 
			
		||||
 */
 | 
			
		||||
short int
 | 
			
		||||
thread_pool_create(void)
 | 
			
		||||
{
 | 
			
		||||
	unsigned int i;
 | 
			
		||||
	int pthread_ret;
 | 
			
		||||
#if 0
 | 
			
		||||
	pthread_mutexattr_t mutexattr;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * Initialize thread_attr to contain a non-default stack size
 | 
			
		||||
	 * because the default on some OS's is too small. Also, make sure
 | 
			
		||||
	 * we're using a detached creation method so all resources are
 | 
			
		||||
	 * reclaimed when the thread exits.
 | 
			
		||||
	 */
 | 
			
		||||
	pthread_attr_init(&thread_attr);
 | 
			
		||||
	pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED);
 | 
			
		||||
	pthread_attr_setstacksize(&thread_attr, THREAD_STACK_SIZE);
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
	pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
 | 
			
		||||
#endif
 | 
			
		||||
	pthread_mutex_init(&mlock, NULL);
 | 
			
		||||
	pthread_mutex_init(&servers_mutex, NULL);
 | 
			
		||||
 | 
			
		||||
	if (thread_config.maxclients == 0) {
 | 
			
		||||
		log_message(LOG_ERR,
 | 
			
		||||
			    "thread_pool_create: \"MaxClients\" must be greater than zero.");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
	if (thread_config.startservers == 0) {
 | 
			
		||||
		log_message(LOG_ERR,
 | 
			
		||||
			    "thread_pool_create: \"StartServers\" must be greater than zero.");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	thread_ptr = safecalloc((size_t) thread_config.maxclients,
 | 
			
		||||
				sizeof(struct thread_s));
 | 
			
		||||
	if (!thread_ptr) {
 | 
			
		||||
		log_message(LOG_ERR, "Could not allocate memory for threads.");
 | 
			
		||||
		return -1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (thread_config.startservers > thread_config.maxclients) {
 | 
			
		||||
		log_message(LOG_WARNING,
 | 
			
		||||
			    "Can not start more than \"MaxClients\" servers. Starting %u servers instead.",
 | 
			
		||||
			    thread_config.maxclients);
 | 
			
		||||
		thread_config.startservers = thread_config.maxclients;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < thread_config.maxclients; i++) {
 | 
			
		||||
		thread_ptr[i].status = T_EMPTY;
 | 
			
		||||
		thread_ptr[i].connects = 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for (i = 0; i < thread_config.startservers; i++) {
 | 
			
		||||
		DEBUG2("Trying to create thread %d of %d", i + 1, thread_config.startservers);
 | 
			
		||||
		thread_ptr[i].status = T_WAITING;
 | 
			
		||||
		pthread_ret = pthread_create(&thread_ptr[i].tid, &thread_attr,
 | 
			
		||||
					     &thread_main, &thread_ptr[i]);
 | 
			
		||||
		if (pthread_ret != 0) {
 | 
			
		||||
			log_message(LOG_WARNING,
 | 
			
		||||
				    "Could not create thread number %d of %d: %s",
 | 
			
		||||
				    i, thread_config.startservers,
 | 
			
		||||
				    strerror(pthread_ret));
 | 
			
		||||
			return -1;
 | 
			
		||||
		} else {
 | 
			
		||||
			log_message(LOG_INFO,
 | 
			
		||||
				    "Creating thread number %d of %d ...",
 | 
			
		||||
				    i + 1, thread_config.startservers);
 | 
			
		||||
 | 
			
		||||
			SERVER_INC();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log_message(LOG_INFO, "Finished creating all threads.");
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Keep the proper number of servers running. This is the birth of the
 | 
			
		||||
 * servers. It monitors this at least once a second.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
thread_main_loop(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	int pthread_ret;
 | 
			
		||||
 | 
			
		||||
	while (1) {
 | 
			
		||||
		if (config.quit)
 | 
			
		||||
			return;
 | 
			
		||||
 | 
			
		||||
		/* If there are not enough spare servers, create more */
 | 
			
		||||
		SERVER_COUNT_LOCK();
 | 
			
		||||
		if (servers_waiting < thread_config.minspareservers) {
 | 
			
		||||
			log_message(LOG_NOTICE,
 | 
			
		||||
				    "Waiting servers (%d) is less than MinSpareServers (%d). Creating new thread.",
 | 
			
		||||
				    servers_waiting, thread_config.minspareservers);
 | 
			
		||||
 | 
			
		||||
			SERVER_COUNT_UNLOCK();
 | 
			
		||||
 | 
			
		||||
			for (i = 0; i < thread_config.maxclients; i++) {
 | 
			
		||||
				if (thread_ptr[i].status == T_EMPTY) {
 | 
			
		||||
					thread_ptr[i].status = T_WAITING;
 | 
			
		||||
					pthread_ret = pthread_create(&thread_ptr[i].tid,
 | 
			
		||||
								     &thread_attr,
 | 
			
		||||
								     &thread_main,
 | 
			
		||||
								     &thread_ptr[i]);
 | 
			
		||||
					if (pthread_ret != 0) {
 | 
			
		||||
						log_message(LOG_NOTICE,
 | 
			
		||||
							    "Could not create thread: %s",
 | 
			
		||||
							    strerror(pthread_ret));
 | 
			
		||||
 | 
			
		||||
						thread_ptr[i].status = T_EMPTY;
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					SERVER_INC();
 | 
			
		||||
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			SERVER_COUNT_UNLOCK();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		sleep(5);
 | 
			
		||||
 | 
			
		||||
		/* Handle log rotation if it was requested */
 | 
			
		||||
		if (log_rotation_request) {
 | 
			
		||||
			rotate_log_files();
 | 
			
		||||
			log_rotation_request = FALSE;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Go through all the non-empty threads and cancel them.
 | 
			
		||||
 */
 | 
			
		||||
#ifdef HAVE_PTHREAD_CANCEL
 | 
			
		||||
void
 | 
			
		||||
thread_kill_threads(void)
 | 
			
		||||
{
 | 
			
		||||
	int i;
 | 
			
		||||
	
 | 
			
		||||
	for (i = 0; i < thread_config.maxclients; i++) {
 | 
			
		||||
		if (thread_ptr[i].status != T_EMPTY)
 | 
			
		||||
			pthread_cancel(thread_ptr[i].tid);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
void
 | 
			
		||||
thread_kill_threads(void)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
thread_listening_sock(uint16_t port)
 | 
			
		||||
{
 | 
			
		||||
	listenfd = listen_sock(port, &addrlen);
 | 
			
		||||
	return listenfd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
thread_close_sock(void)
 | 
			
		||||
{
 | 
			
		||||
	close(listenfd);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								src/thread.h
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								src/thread.h
									
									
									
									
									
								
							@ -1,37 +0,0 @@
 | 
			
		||||
/* $Id: thread.h,v 1.4 2002-01-25 00:01:45 rjkaes Exp $
 | 
			
		||||
 *
 | 
			
		||||
 * See 'thread.c' for more information.
 | 
			
		||||
 *
 | 
			
		||||
 * Copyright (C) 2000 Robert James Kaes (rjkaes@flarenet.com)
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software; you can redistribute it and/or modify it
 | 
			
		||||
 * under the terms of the GNU General Public License as published by the
 | 
			
		||||
 * Free Software Foundation; either version 2, or (at your option) any
 | 
			
		||||
 * later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful, but
 | 
			
		||||
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
			
		||||
 * General Public License for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#ifndef _TINYPROXY_THREAD_H_
 | 
			
		||||
#define _TINYPROXY_THREAD_H_
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
	THREAD_MAXCLIENTS,
 | 
			
		||||
	THREAD_MAXSPARESERVERS,
 | 
			
		||||
	THREAD_MINSPARESERVERS,
 | 
			
		||||
	THREAD_STARTSERVERS,
 | 
			
		||||
	THREAD_MAXREQUESTSPERCHILD
 | 
			
		||||
} thread_config_t;
 | 
			
		||||
 | 
			
		||||
extern short int thread_pool_create(void);
 | 
			
		||||
extern int thread_listening_sock(uint16_t port);
 | 
			
		||||
extern void thread_close_sock(void);
 | 
			
		||||
extern void thread_main_loop(void);
 | 
			
		||||
extern void thread_kill_threads(void);
 | 
			
		||||
 | 
			
		||||
extern short int thread_configure(thread_config_t type, unsigned int val);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user