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:
Robert James Kaes 2002-05-26 18:48:32 +00:00
parent 1fda8899b1
commit c35e56ae66
2 changed files with 0 additions and 437 deletions

View File

@ -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);
}

View File

@ -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