Bugzilla: 62396, fix threads in selfserv.c

This commit is contained in:
larryh%netscape.com 2000-12-09 01:35:54 +00:00
Родитель 68e18aa4b9
Коммит e769c1df54
1 изменённых файлов: 86 добавлений и 116 удалений

Просмотреть файл

@ -114,8 +114,12 @@ int ssl3CipherSuites[] = {
0
};
int requestCert;
/* data and structures for shutdown */
int stopping;
PRLock * stopLock;
PRCondVar * stopQ;
int requestCert;
int verbose;
SECItem bigBuf;
@ -144,7 +148,7 @@ Usage(const char *progName)
{
fprintf(stderr,
"Usage: %s -n rsa_nickname -p port [-3RTmrvx] [-w password]\n"
"Usage: %s -n rsa_nickname -p port [-3RTmrvx] [-w password] [-t threads]\n"
" [-i pid_file] [-c ciphers] [-d dbdir] [-f fortezza_nickname] \n"
"-3 means disable SSL v3\n"
"-T means disable TLS\n"
@ -155,6 +159,7 @@ Usage(const char *progName)
" 2 -r's mean request and require, cert on initial handshake.\n"
" 3 -r's mean request, not require, cert on second handshake.\n"
" 4 -r's mean request and require, cert on second handshake.\n"
"-t threads -- specify the number of threads to use for connections.\n"
"-v means verbose output\n"
"-x means use export policy.\n"
"-i pid_file file to write the process id of selfserve\n"
@ -364,17 +369,20 @@ extern long ssl3_hch_sid_cache_not_ok;
/**************************************************************************
** Begin thread management routines and data.
**************************************************************************/
#define MIN_THREADS 3
#define DEFAULT_THREADS 8
#define MAX_THREADS 128
static int maxThreads = DEFAULT_THREADS;
#define MAX_THREADS 32
typedef int startFn(PRFileDesc *a, PRFileDesc *b, int c);
PRLock * threadLock;
PRCondVar * threadStartQ;
PRCondVar * threadEndQ;
PRCondVar * threadQ;
int numUsed;
int numRunning;
PRLock * stopLock;
PRCondVar * stopQ;
static int threadCount = 0;
typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;
@ -385,29 +393,23 @@ typedef struct perThreadStr {
int rv;
startFn * startFunc;
PRThread * prThread;
PRBool inUse;
runState running;
runState state;
} perThread;
perThread threads[MAX_THREADS];
perThread *threads;
void
thread_wrapper(void * arg)
{
perThread * slot = (perThread *)arg;
/* wait for parent to finish launching us before proceeding. */
PR_Lock(threadLock);
PR_Unlock(threadLock);
slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c);
PR_Lock(threadLock);
slot->running = rs_zombie;
/* notify the thread exit handler. */
PR_NotifyCondVar(threadEndQ);
PR_Lock(threadLock);
slot->state = rs_zombie;
--threadCount;
PR_NotifyAllCondVar(threadQ);
PR_Unlock(threadLock);
}
@ -420,116 +422,59 @@ launch_thread(
{
perThread * slot;
int i;
static int highWaterMark = 0;
int workToDo = 1;
if (!threadStartQ) {
threadLock = PR_NewLock();
threadStartQ = PR_NewCondVar(threadLock);
threadEndQ = PR_NewCondVar(threadLock);
}
PR_Lock(threadLock);
while (numRunning >= MAX_THREADS) {
PR_WaitCondVar(threadStartQ, PR_INTERVAL_NO_TIMEOUT);
}
for (i = 0; i < numUsed; ++i) {
slot = threads + i;
if (slot->running == rs_idle)
break;
}
if (i >= numUsed) {
if (i >= MAX_THREADS) {
/* something's really wrong here. */
PORT_Assert(i < MAX_THREADS);
PR_Unlock(threadLock);
return SECFailure;
}
++numUsed;
PORT_Assert(numUsed == i + 1);
slot = threads + i;
}
/* for each perThread structure in the threads array */
while( workToDo ) {
for (i = 0; i < maxThreads; ++i) {
slot = threads + i;
slot->a = a;
slot->b = b;
slot->c = c;
/* create new thread */
if (( slot->state == rs_idle ) || ( slot->state == rs_zombie )) {
slot->state = 1;
workToDo = 0;
slot->a = a;
slot->b = b;
slot->c = c;
slot->startFunc = startFunc;
slot->prThread = PR_CreateThread(PR_USER_THREAD, thread_wrapper, slot,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_UNJOINABLE_THREAD, 0);
if (slot->prThread == NULL) {
printf("selfserv: Failed to launch thread!\n");
slot->state = rs_idle;
return SECFailure;
}
slot->startFunc = startFunc;
slot->prThread = PR_CreateThread(PR_USER_THREAD,
thread_wrapper, slot,
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 0);
if (slot->prThread == NULL) {
PR_Unlock(threadLock);
printf("selfserv: Failed to launch thread!\n");
return SECFailure;
}
slot->inUse = 1;
slot->running = 1;
++numRunning;
PR_Unlock(threadLock);
PRINTF("selfserv: Launched thread in slot %d \n", i);
FLUSH;
highWaterMark = ( i > highWaterMark )? i : highWaterMark;
PRINTF("selfserv: Launched thread in slot %d, highWaterMark: %d \n", i, highWaterMark );
FLUSH;
++threadCount;
break; /* we did what we came here for, leave */
}
} /* end for() */
if ( workToDo )
PR_WaitCondVar(threadQ, PR_INTERVAL_NO_TIMEOUT);
} /* end while() */
PR_Unlock(threadLock);
return SECSuccess;
}
int
reap_threads(void)
{
perThread * slot;
int i;
if (!threadLock)
return 0;
PR_Lock(threadLock);
while (numRunning > 0) {
PR_WaitCondVar(threadEndQ, PR_INTERVAL_NO_TIMEOUT);
for (i = 0; i < numUsed; ++i) {
slot = threads + i;
if (slot->running == rs_zombie) {
/* Handle cleanup of thread here. */
PRINTF("selfserv: Thread in slot %d returned %d\n", i, slot->rv);
/* Now make sure the thread has ended OK. */
PR_JoinThread(slot->prThread);
slot->running = rs_idle;
--numRunning;
/* notify the thread launcher. */
PR_NotifyCondVar(threadStartQ);
}
}
}
/* Safety Sam sez: make sure count is right. */
for (i = 0; i < numUsed; ++i) {
slot = threads + i;
if (slot->running != rs_idle) {
FPRINTF(stderr, "selfserv: Thread in slot %d is in state %d!\n",
i, slot->running);
}
}
PR_Unlock(threadLock);
FLUSH;
return 0;
}
void
destroy_thread_data(void)
{
PORT_Memset(threads, 0, sizeof threads);
if (threadEndQ) {
PR_DestroyCondVar(threadEndQ);
threadEndQ = NULL;
}
if (threadStartQ) {
PR_DestroyCondVar(threadStartQ);
threadStartQ = NULL;
if (threadQ) {
PR_DestroyCondVar(threadQ);
threadQ = NULL;
}
if (threadLock) {
PR_DestroyLock(threadLock);
threadLock = NULL;
PR_DestroyLock(threadLock);
threadLock = NULL;
}
}
@ -991,6 +936,13 @@ server_main(
PRSocketOptionData opt;
networkStart();
/* create the thread management serialization structs */
threadLock = PR_NewLock();
threadQ = PR_NewCondVar(threadLock);
stopLock = PR_NewLock();
stopQ = PR_NewCondVar(stopLock);
addr.inet.family = PR_AF_INET;
addr.inet.ip = PR_INADDR_ANY;
@ -1113,7 +1065,11 @@ server_main(
if (rv != SECSuccess) {
PR_Close(listen_sock);
} else {
reap_threads();
PR_Lock( stopLock );
while ( !stopping && threadCount > 0 ) {
PR_WaitCondVar(stopQ, PR_INTERVAL_NO_TIMEOUT);
}
PR_Unlock( stopLock );
destroy_thread_data();
}
@ -1187,7 +1143,7 @@ main(int argc, char **argv)
progName = strrchr(tmp, '\\');
progName = progName ? progName + 1 : tmp;
optstate = PL_CreateOptState(argc, argv, "RT2:3c:d:p:mn:i:f:rvw:x");
optstate = PL_CreateOptState(argc, argv, "RT2:3c:d:p:mn:i:f:rt:vw:x");
while (PL_GetNextOpt(optstate) == PL_OPT_OK) {
switch(optstate->option) {
default:
@ -1217,6 +1173,12 @@ main(int argc, char **argv)
case 'r': ++requestCert; break;
case 't':
maxThreads = PORT_Atoi(optstate->value);
if ( maxThreads > MAX_THREADS ) maxThreads = MAX_THREADS;
if ( maxThreads < MIN_THREADS ) maxThreads = MIN_THREADS;
break;
case 'v': verbose++; break;
case 'w': passwd = optstate->value; break;
@ -1225,6 +1187,13 @@ main(int argc, char **argv)
}
}
/* allocate the array of thread slots */
threads = PR_Calloc(maxThreads, sizeof(perThread));
if ( NULL == threads ) {
fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n");
goto mainExit;
}
if ((nickName == NULL) && (fNickName == NULL))
Usage(progName);
@ -1321,6 +1290,7 @@ main(int argc, char **argv)
server_main(port, requestCert, privKey, cert);
mainExit:
NSS_Shutdown();
PR_Cleanup();
return 0;