зеркало из 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
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
int requestCert;
|
/* data and structures for shutdown */
|
||||||
int stopping;
|
int stopping;
|
||||||
|
PRLock * stopLock;
|
||||||
|
PRCondVar * stopQ;
|
||||||
|
|
||||||
|
int requestCert;
|
||||||
int verbose;
|
int verbose;
|
||||||
SECItem bigBuf;
|
SECItem bigBuf;
|
||||||
|
|
||||||
|
@ -144,7 +148,7 @@ Usage(const char *progName)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
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"
|
" [-i pid_file] [-c ciphers] [-d dbdir] [-f fortezza_nickname] \n"
|
||||||
"-3 means disable SSL v3\n"
|
"-3 means disable SSL v3\n"
|
||||||
"-T means disable TLS\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"
|
" 2 -r's mean request and require, cert on initial handshake.\n"
|
||||||
" 3 -r's mean request, not require, cert on second 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"
|
" 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"
|
"-v means verbose output\n"
|
||||||
"-x means use export policy.\n"
|
"-x means use export policy.\n"
|
||||||
"-i pid_file file to write the process id of selfserve\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.
|
** 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);
|
typedef int startFn(PRFileDesc *a, PRFileDesc *b, int c);
|
||||||
|
|
||||||
PRLock * threadLock;
|
PRLock * threadLock;
|
||||||
PRCondVar * threadStartQ;
|
PRCondVar * threadQ;
|
||||||
PRCondVar * threadEndQ;
|
|
||||||
|
|
||||||
int numUsed;
|
PRLock * stopLock;
|
||||||
int numRunning;
|
PRCondVar * stopQ;
|
||||||
|
static int threadCount = 0;
|
||||||
|
|
||||||
typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;
|
typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState;
|
||||||
|
|
||||||
|
@ -385,29 +393,23 @@ typedef struct perThreadStr {
|
||||||
int rv;
|
int rv;
|
||||||
startFn * startFunc;
|
startFn * startFunc;
|
||||||
PRThread * prThread;
|
PRThread * prThread;
|
||||||
PRBool inUse;
|
runState state;
|
||||||
runState running;
|
|
||||||
} perThread;
|
} perThread;
|
||||||
|
|
||||||
perThread threads[MAX_THREADS];
|
perThread *threads;
|
||||||
|
|
||||||
void
|
void
|
||||||
thread_wrapper(void * arg)
|
thread_wrapper(void * arg)
|
||||||
{
|
{
|
||||||
perThread * slot = (perThread *)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);
|
slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c);
|
||||||
|
|
||||||
PR_Lock(threadLock);
|
|
||||||
slot->running = rs_zombie;
|
|
||||||
|
|
||||||
/* notify the thread exit handler. */
|
/* notify the thread exit handler. */
|
||||||
PR_NotifyCondVar(threadEndQ);
|
PR_Lock(threadLock);
|
||||||
|
slot->state = rs_zombie;
|
||||||
|
--threadCount;
|
||||||
|
PR_NotifyAllCondVar(threadQ);
|
||||||
PR_Unlock(threadLock);
|
PR_Unlock(threadLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,116 +422,59 @@ launch_thread(
|
||||||
{
|
{
|
||||||
perThread * slot;
|
perThread * slot;
|
||||||
int i;
|
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);
|
PR_Lock(threadLock);
|
||||||
while (numRunning >= MAX_THREADS) {
|
/* for each perThread structure in the threads array */
|
||||||
PR_WaitCondVar(threadStartQ, PR_INTERVAL_NO_TIMEOUT);
|
while( workToDo ) {
|
||||||
}
|
for (i = 0; i < maxThreads; ++i) {
|
||||||
for (i = 0; i < numUsed; ++i) {
|
slot = threads + 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
slot->a = a;
|
/* create new thread */
|
||||||
slot->b = b;
|
if (( slot->state == rs_idle ) || ( slot->state == rs_zombie )) {
|
||||||
slot->c = c;
|
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;
|
highWaterMark = ( i > highWaterMark )? i : highWaterMark;
|
||||||
|
PRINTF("selfserv: Launched thread in slot %d, highWaterMark: %d \n", i, highWaterMark );
|
||||||
slot->prThread = PR_CreateThread(PR_USER_THREAD,
|
FLUSH;
|
||||||
thread_wrapper, slot,
|
++threadCount;
|
||||||
PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
|
break; /* we did what we came here for, leave */
|
||||||
PR_JOINABLE_THREAD, 0);
|
}
|
||||||
if (slot->prThread == NULL) {
|
} /* end for() */
|
||||||
PR_Unlock(threadLock);
|
if ( workToDo )
|
||||||
printf("selfserv: Failed to launch thread!\n");
|
PR_WaitCondVar(threadQ, PR_INTERVAL_NO_TIMEOUT);
|
||||||
return SECFailure;
|
} /* end while() */
|
||||||
}
|
PR_Unlock(threadLock);
|
||||||
|
|
||||||
slot->inUse = 1;
|
|
||||||
slot->running = 1;
|
|
||||||
++numRunning;
|
|
||||||
PR_Unlock(threadLock);
|
|
||||||
PRINTF("selfserv: Launched thread in slot %d \n", i);
|
|
||||||
FLUSH;
|
|
||||||
|
|
||||||
return SECSuccess;
|
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
|
void
|
||||||
destroy_thread_data(void)
|
destroy_thread_data(void)
|
||||||
{
|
{
|
||||||
PORT_Memset(threads, 0, sizeof threads);
|
PORT_Memset(threads, 0, sizeof threads);
|
||||||
|
|
||||||
if (threadEndQ) {
|
if (threadQ) {
|
||||||
PR_DestroyCondVar(threadEndQ);
|
PR_DestroyCondVar(threadQ);
|
||||||
threadEndQ = NULL;
|
threadQ = NULL;
|
||||||
}
|
|
||||||
if (threadStartQ) {
|
|
||||||
PR_DestroyCondVar(threadStartQ);
|
|
||||||
threadStartQ = NULL;
|
|
||||||
}
|
}
|
||||||
if (threadLock) {
|
if (threadLock) {
|
||||||
PR_DestroyLock(threadLock);
|
PR_DestroyLock(threadLock);
|
||||||
threadLock = NULL;
|
threadLock = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,6 +936,13 @@ server_main(
|
||||||
PRSocketOptionData opt;
|
PRSocketOptionData opt;
|
||||||
|
|
||||||
networkStart();
|
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.family = PR_AF_INET;
|
||||||
addr.inet.ip = PR_INADDR_ANY;
|
addr.inet.ip = PR_INADDR_ANY;
|
||||||
|
@ -1113,7 +1065,11 @@ server_main(
|
||||||
if (rv != SECSuccess) {
|
if (rv != SECSuccess) {
|
||||||
PR_Close(listen_sock);
|
PR_Close(listen_sock);
|
||||||
} else {
|
} else {
|
||||||
reap_threads();
|
PR_Lock( stopLock );
|
||||||
|
while ( !stopping && threadCount > 0 ) {
|
||||||
|
PR_WaitCondVar(stopQ, PR_INTERVAL_NO_TIMEOUT);
|
||||||
|
}
|
||||||
|
PR_Unlock( stopLock );
|
||||||
destroy_thread_data();
|
destroy_thread_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1187,7 +1143,7 @@ main(int argc, char **argv)
|
||||||
progName = strrchr(tmp, '\\');
|
progName = strrchr(tmp, '\\');
|
||||||
progName = progName ? progName + 1 : 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) {
|
while (PL_GetNextOpt(optstate) == PL_OPT_OK) {
|
||||||
switch(optstate->option) {
|
switch(optstate->option) {
|
||||||
default:
|
default:
|
||||||
|
@ -1217,6 +1173,12 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
case 'r': ++requestCert; break;
|
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 'v': verbose++; break;
|
||||||
|
|
||||||
case 'w': passwd = optstate->value; 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))
|
if ((nickName == NULL) && (fNickName == NULL))
|
||||||
Usage(progName);
|
Usage(progName);
|
||||||
|
|
||||||
|
@ -1321,6 +1290,7 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
server_main(port, requestCert, privKey, cert);
|
server_main(port, requestCert, privKey, cert);
|
||||||
|
|
||||||
|
mainExit:
|
||||||
NSS_Shutdown();
|
NSS_Shutdown();
|
||||||
PR_Cleanup();
|
PR_Cleanup();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче