зеркало из https://github.com/mozilla/gecko-dev.git
Bugzilla: 62396, fix threads in selfserv.c
This commit is contained in:
Родитель
68e18aa4b9
Коммит
e769c1df54
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче