*** stunnel-3.20.orig/sthreads.c Sun Aug 12 11:14:51 2001 --- stunnel-3.20/sthreads.c Tue Oct 23 11:41:42 2001 *************** *** 28,37 **** #ifdef USE_PTHREAD #include ! pthread_mutex_t stunnel_cs[CRIT_SECTIONS]; pthread_mutex_t lock_cs[CRYPTO_NUM_LOCKS]; pthread_attr_t pth_attr; --- 28,95 ---- #ifdef USE_PTHREAD + + /** + * thread pooliging for posix pthreads. + */ + + + extern server_options options; + #include ! #ifndef MAX_CLIENTS ! #ifdef FD_SETSIZE ! #define MAX_CLIENTS ((FD_SETSIZE-24)/2) ! #else ! #define MAX_CLIENTS 500 ! #endif ! #endif ! ! #define THDATA_MAGIC 3849086 ! ! #define TH_NONE 0 ! #define TH_IDLE 1 ! #define TH_ACTIVE 2 ! #define TH_START 3 ! #define TH_STOP 4 ! ! ! /* ! * In this thread pool threads are divided to tree groups (LOW,NORM,HIGH) ! * if there is nothing to do for thread then threads quits. ! * HIGH threads are killed first NORM then and LOW last. ! * Each group has it's own IDLE_TIMEOUT ! * (this is quite ad hoc solution) ! */ ! ! #define LOW_THREADS 10 ! #define HIGH_THREADS 100 ! ! ! #define IDLE_TIMEOUT_LOW 300 ! #define IDLE_TIMEOUT_NORM 60 ! #define IDLE_TIMEOUT_HIGH 10 ! ! ! typedef struct { ! int status; /* status TH_NONE,TH_IDLE,TH_ACTIVE,TH_START, TH_STOP */ ! int magic; /* magic number for checking pointers */ ! int index; /* index of this in table */ ! pthread_t thread; /* actual posix thread */ ! pthread_cond_t cond; /* condition used to wake up thread */ ! void *data; /* data to give to thread */ ! void (*proc)(int); /* actual thread job function */ ! long long start_time; /* when started */ ! int count; /* how many times used */ ! } THDATA; ! ! static int thread_count = 0; ! static THDATA *thread_pool[MAX_CLIENTS]; + pthread_mutex_t pool_mutex = PTHREAD_MUTEX_INITIALIZER; + + pthread_mutex_t stunnel_cs[CRIT_SECTIONS]; pthread_mutex_t lock_cs[CRYPTO_NUM_LOCKS]; pthread_attr_t pth_attr; *************** *** 79,87 **** return (unsigned long)pthread_self(); } ! int create_client(int ls, int s, void (*cli)(int)) { ! pthread_t thread; sigset_t mask, oldmask; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); --- 137,279 ---- return (unsigned long)pthread_self(); } ! ! static void *th_child(void *data) ! { ! THDATA *th = (THDATA *) data; ! struct timeval now; ! struct timespec timeout; ! int my_timeout; ! int ret; ! int stop = 0; ! char *cl; ! ! if(th->magic != THDATA_MAGIC) abort(); ! ! th->status = TH_ACTIVE; ! ! if(th->index < LOW_THREADS) { ! my_timeout = IDLE_TIMEOUT_LOW; ! cl = "LOW"; ! } else if(th->index < HIGH_THREADS) { ! my_timeout = IDLE_TIMEOUT_NORM; ! cl = "NORM"; ! } else { ! my_timeout = IDLE_TIMEOUT_HIGH; ! cl = "HIGH"; ! } ! ! do { ! ! th->count++; ! ! (th->proc)((int) th->data); ! ! th->status = TH_IDLE; ! ! while(!stop && (th->status != TH_ACTIVE)) { ! ! gettimeofday(&now,NULL); ! ! timeout.tv_sec = now.tv_sec + my_timeout; ! timeout.tv_nsec = now.tv_usec * 1000; ! ! // wait for next connection. ! ! pthread_mutex_lock(&pool_mutex); ! ! if(my_timeout > 0) { ! ret = 0; ! ret = pthread_cond_timedwait(&th->cond,&pool_mutex,&timeout); ! ! if(ret == ETIMEDOUT) { ! thread_pool[th->index] = NULL; ! th->status = TH_STOP; ! thread_count--; ! stop = 1; ! } ! } else { ! pthread_cond_wait(&th->cond,&pool_mutex); ! } ! ! pthread_mutex_unlock(&pool_mutex); ! } ! ! ! } while(!stop); ! ! log(LOG_WARNING, "%s thread(%d) idle timout; active(%d) class(%s)", options.servname, th->index, thread_count, cl); ! ! pthread_cond_destroy(&th->cond); ! th->magic = 0; ! free(th); ! ! return NULL; ! } ! ! static THDATA th_reserve = { -1, THDATA_MAGIC }; ! ! ! int create_client(int ls, int s, void (*cli)(int)) ! { ! // pthread_t thread; sigset_t mask, oldmask; + int i; + int mark = -1; + THDATA *found = NULL; + THDATA *th; + + pthread_mutex_lock(&pool_mutex); + for(i=0; i < MAX_CLIENTS; i++) { + THDATA *t = thread_pool[i]; + if(t == NULL) { + if(mark < 0) mark = i; + } else if(t == &th_reserve) { + // well it's starting + } else if(t->status == TH_IDLE) { + found = t; + break; + } + } + + if(found) { + found->status = TH_ACTIVE; + found->data = (void *) s; + found->proc = cli; + pthread_cond_signal(&found->cond); + } else if(mark >= 0) { + thread_pool[mark] = &th_reserve; + } + + pthread_mutex_unlock(&pool_mutex); + + if(found) { + log(LOG_NOTICE, "%s using old thread(%d) count(%d)", options.servname, found->index, found->count); + return 0; + } + + if(mark < 0) { + log(LOG_WARNING, "%s TOO MANY CLIENTS (%d)", options.servname, MAX_CLIENTS); + return -1; + } + + // Create new thread + + th = calloc(sizeof(THDATA),1); + + th->magic = THDATA_MAGIC; + th->status = TH_START; + th->index = mark; + pthread_cond_init(&th->cond, NULL); + + pthread_mutex_lock(&pool_mutex); + thread_pool[mark] = th; + pthread_mutex_unlock(&pool_mutex); + + log(LOG_NOTICE, "%s start new thread (%d)", options.servname, th->index); + + th->data = (void *) s; + th->proc = cli; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); *************** *** 90,102 **** sigaddset(&mask, SIGINT); sigaddset(&mask, SIGHUP); pthread_sigmask(SIG_BLOCK, &mask, &oldmask); /* block SIGCHLD */ ! if(pthread_create(&thread, &pth_attr, (void *)cli, (void *)s)) { /* SIGCHLD will remain blocked here */ closesocket(s); return -1; } pthread_sigmask(SIG_SETMASK, &oldmask, NULL); /* restore the mask */ return 0; } #endif --- 282,304 ---- sigaddset(&mask, SIGINT); sigaddset(&mask, SIGHUP); pthread_sigmask(SIG_BLOCK, &mask, &oldmask); /* block SIGCHLD */ ! ! if(pthread_create(&th->thread, &pth_attr, (void *)th_child, (void *)th)) { /* SIGCHLD will remain blocked here */ + th->status = TH_NONE; closesocket(s); return -1; } + + pthread_mutex_lock(&pool_mutex); + thread_count++; + pthread_mutex_unlock(&pool_mutex); + pthread_sigmask(SIG_SETMASK, &oldmask, NULL); /* restore the mask */ + + return 0; + } #endif