void MemTime(int ns) { Ns_Time start, end, diff; int i; Ns_Thread *tids; tids = ns_malloc(sizeof(Ns_Thread *) * nthreads); Ns_MutexLock(&lock); nrunning = 0; memstart = 0; Ns_MutexUnlock(&lock); printf("starting %d %smalloc threads...", nthreads, ns ? "ns_" : ""); fflush(stdout); Ns_GetTime(&start); for (i = 0; i < nthreads; ++i) { Ns_ThreadCreate(MemThread, (void *) ns, 0, &tids[i]); } Ns_MutexLock(&lock); while (nrunning < nthreads) { Ns_CondWait(&cond, &lock); } printf("waiting...."); fflush(stdout); memstart = 1; Ns_CondBroadcast(&cond); Ns_MutexUnlock(&lock); for (i = 0; i < nthreads; ++i) { Ns_ThreadJoin(&tids[i], NULL); } Ns_GetTime(&end); Ns_DiffTime(&end, &start, &diff); printf("done: %d seconds, %d usec\n", (int) diff.sec, (int) diff.usec); }
void DumperThread(void *arg) { Ns_Time to; Tcl_DString ds; Tcl_DStringInit(&ds); Ns_ThreadSetName("-dumper-"); Ns_MutexLock(&block); Ns_MutexLock(&dlock); while (!dstop) { Ns_GetTime(&to); Ns_IncrTime(&to, 1, 0); Ns_CondTimedWait(&dcond, &dlock, &to); Ns_MutexLock(&mlock); Ns_ThreadList(&ds, NULL); DumpString(&ds); Ns_MutexList(&ds); DumpString(&ds); #if !defined(_WIN32) && defined(USE_THREAD_ALLOC) && (STATIC_BUILD == 0) /* NB: Not yet exported in WIN32 Tcl. */ Tcl_GetMemoryInfo(&ds); #endif DumpString(&ds); Ns_MutexUnlock(&mlock); } Ns_MutexUnlock(&dlock); Ns_MutexUnlock(&block); }
void Ns_ThreadList(Tcl_DString *dsPtr, Ns_ThreadArgProc *proc) { Thread *thrPtr; char buf[100]; Ns_MutexLock(&threadlock); thrPtr = firstThreadPtr; while (thrPtr != NULL) { Tcl_DStringStartSublist(dsPtr); Tcl_DStringAppendElement(dsPtr, thrPtr->name); Tcl_DStringAppendElement(dsPtr, thrPtr->parent); sprintf(buf, " %d %d %ld", thrPtr->tid, (thrPtr->flags & FLAG_DETACHED) ? NS_THREAD_DETACHED : 0, thrPtr->ctime.sec); Tcl_DStringAppend(dsPtr, buf, -1); if (proc != NULL) { (*proc)(dsPtr, (void *) thrPtr->proc, thrPtr->arg); } else { sprintf(buf, " %p %p", thrPtr->proc, thrPtr->arg); Tcl_DStringAppend(dsPtr, buf, -1); } Tcl_DStringEndSublist(dsPtr); thrPtr = thrPtr->nextPtr; } Ns_MutexUnlock(&threadlock); }
int Ns_LockMutex(Ns_Mutex *mutexPtr) { Ns_MutexLock(mutexPtr); return NS_OK; }
void NsCreateConnThread(Pool *poolPtr, int joinThreads) { ConnData *dataPtr; /* * Reap any dead threads. */ if (joinThreads) { NsJoinConnThreads(); } /* * Create a new connection thread. */ dataPtr = ns_malloc(sizeof(ConnData)); dataPtr->poolPtr = poolPtr; dataPtr->connPtr = NULL; Ns_MutexLock(&poolPtr->lock); poolPtr->threads.starting ++; Ns_MutexUnlock(&poolPtr->lock); Ns_ThreadCreate(NsConnThread, dataPtr, 0, &dataPtr->thread); }
void MemThread(void *arg) { int i; void *ptr; Ns_ThreadSetName("memthread"); Ns_MutexLock(&lock); ++nrunning; Ns_CondBroadcast(&cond); while (!memstart) { Ns_CondWait(&cond, &lock); } Ns_MutexUnlock(&lock); ptr = NULL; for (i = 0; i < NA; ++i) { if (arg) { if (ptr) ns_free(ptr); ptr = ns_malloc(10); } else { if (ptr) free(ptr); ptr = malloc(10); } } }
void * Pthread(void *arg) { static Ns_Tls tls; /* * Allocate TLS first time (this is recommended TLS * self-initialization style. */ Ns_ThreadSetName("pthread"); sleep(5); if (tls == NULL) { Ns_MasterLock(); if (tls == NULL) { Ns_TlsAlloc(&tls, PthreadTlsCleanup); } Ns_MasterUnlock(); } Ns_TlsSet(&tls, arg); /* * Wait for exit signal from main(). */ Ns_MutexLock(&plock); while (!pgo) { Ns_CondWait(&pcond, &plock); } Ns_MutexUnlock(&plock); return arg; }
static Thread * NewThread(ThreadArg *argPtr) { Thread *thrPtr; int stack; thrPtr = ns_calloc(1, sizeof(Thread)); Ns_GetTime(&thrPtr->ctime); thrPtr->tid = Ns_ThreadId(); sprintf(thrPtr->name, "-thread%d-", thrPtr->tid); if (argPtr == NULL) { thrPtr->flags = FLAG_DETACHED; } else { thrPtr->flags = argPtr->flags; thrPtr->proc = argPtr->proc; thrPtr->arg = argPtr->arg; strcpy(thrPtr->parent, argPtr->parent); } stack = NsGetStack(&thrPtr->stackaddr, &thrPtr->stacksize); if (stack) { thrPtr->flags |= FLAG_HAVESTACK; if (stack < 0) { thrPtr->flags |= FLAG_STACKDOWN; } } Ns_TlsSet(&key, thrPtr); Ns_MutexLock(&threadlock); thrPtr->nextPtr = firstThreadPtr; firstThreadPtr = thrPtr; Ns_MutexUnlock(&threadlock); return thrPtr; }
void Ns_ThreadSetName(char *name) { Thread *thrPtr = GetThread(); Ns_MutexLock(&threadlock); strncpy(thrPtr->name, name, NS_THREAD_NAMESIZE); Ns_MutexUnlock(&threadlock); }
void NsAppendRequest(Tcl_DString *dsPtr, Ns_Request *request) { if (request == NULL) { Tcl_DStringAppend(dsPtr, " ? ?", -1); } else { Ns_MutexLock(&reqlock); Tcl_DStringAppendElement(dsPtr, request->method); Tcl_DStringAppendElement(dsPtr, request->url); Ns_MutexUnlock(&reqlock); } }
void Ns_SemaWait(Ns_Sema *semaPtr) { Sema *sPtr = (Sema *) *semaPtr; Ns_MutexLock(&sPtr->lock); while (sPtr->count == 0) { Ns_CondWait(&sPtr->cond, &sPtr->lock); } sPtr->count--; Ns_MutexUnlock(&sPtr->lock); }
void NsQueueConn(Conn *connPtr) { Pool *poolPtr = NsGetConnPool(connPtr); int create = 0; /* * Queue connection. */ connPtr->flags |= NS_CONN_RUNNING; Ns_MutexLock(&poolPtr->lock); ++poolPtr->threads.queued; if (poolPtr->queue.wait.firstPtr == NULL) { poolPtr->queue.wait.firstPtr = connPtr; } else { poolPtr->queue.wait.lastPtr->nextPtr = connPtr; } poolPtr->queue.wait.lastPtr = connPtr; connPtr->nextPtr = NULL; if (poolPtr->threads.waiting == 0 && poolPtr->threads.current < poolPtr->threads.max) { /* Create a new thread if no thread is waiting and the number of currently starting or running threads is below max. */ create = 1; } poolPtr->queue.wait.num ++; if (create) { poolPtr->threads.current ++; Ns_MutexUnlock(&poolPtr->lock); NsCreateConnThread(poolPtr, 1); } else if (poolPtr->threads.waiting > 0) { /* There are threads waiting. Signal to process the request. */ Ns_CondSignal(&poolPtr->cond); Ns_MutexUnlock(&poolPtr->lock); } else { /* We might have missed signaling, since we are already using max resources, and no thread is available. In such a case the autorecovery at thread exist has to care to process the outstanding requests */ Ns_MutexUnlock(&poolPtr->lock); } }
void NsConnArgProc(Tcl_DString *dsPtr, void *arg) { ConnData *dataPtr = arg; Ns_MutexLock(&connlock); if (dataPtr->connPtr != NULL) { NsAppendConn(dsPtr, dataPtr->connPtr, "running"); } else { Tcl_DStringAppendElement(dsPtr, ""); } Ns_MutexUnlock(&connlock); }
void Ns_SetRequestUrl(Ns_Request * request, char *url) { Ns_DString ds; Ns_MutexLock(&reqlock); FreeUrl(request); Ns_DStringInit(&ds); Ns_DStringAppend(&ds, url); SetUrl(request, ds.string, NULL); Ns_MutexUnlock(&reqlock); Ns_DStringFree(&ds); }
long Ns_ThreadStackSize(long stacksize) { long prev; Ns_MutexLock(&sizelock); prev = stackdef; if (stacksize > 0) { stackdef = stacksize; } Ns_MutexUnlock(&sizelock); return prev; }
void Ns_SemaPost(Ns_Sema *semaPtr, int count) { Sema *sPtr = (Sema *) *semaPtr; Ns_MutexLock(&sPtr->lock); sPtr->count += count; if (count == 1) { Ns_CondSignal(&sPtr->cond); } else { Ns_CondBroadcast(&sPtr->cond); } Ns_MutexUnlock(&sPtr->lock); }
static void CleanupThread(void *arg) { Thread **thrPtrPtr; Thread *thrPtr = arg; Ns_MutexLock(&threadlock); thrPtrPtr = &firstThreadPtr; while (*thrPtrPtr != thrPtr) { thrPtrPtr = &(*thrPtrPtr)->nextPtr; } *thrPtrPtr = thrPtr->nextPtr; thrPtr->nextPtr = NULL; Ns_MutexUnlock(&threadlock); ns_free(thrPtr); }
void NsJoinConnThreads(void) { ConnData *firstPtr; void *arg; Ns_MutexLock(&joinlock); firstPtr = joinPtr; joinPtr = NULL; Ns_MutexUnlock(&joinlock); while (firstPtr != NULL) { Ns_ThreadJoin(&firstPtr->thread, &arg); firstPtr = firstPtr->nextPtr; ns_free(arg); } }
static Thread * NewThread(void) { Thread *thrPtr; static unsigned int nextuid = 0; pthread_t tid; #if defined(HAVE_PTHREAD_GETATTR_NP) static char *func = "NewThread"; pthread_attr_t attr; int err; #endif thrPtr = ns_calloc(1, sizeof(Thread)); Ns_MutexLock(&uidlock); thrPtr->uid = nextuid++; Ns_MutexUnlock(&uidlock); tid = pthread_self(); #if defined(HAVE_PTHREAD_GETATTR_NP) err = pthread_getattr_np(tid, &attr); if (err != 0) { NsThreadFatal(func, "pthread_getattr_np", err); } err = pthread_attr_getstackaddr(&attr, &thrPtr->stackaddr); if (err != 0) { NsThreadFatal(func, "pthread_attr_getstackaddr", err); } err = pthread_attr_getstacksize(&attr, &thrPtr->stacksize); if (err != 0) { NsThreadFatal(func, "pthread_attr_getstacksize", err); } thrPtr->stacksize -= guardsize; err = pthread_attr_destroy(&attr); if (err != 0) { NsThreadFatal(func, "pthread_attr_destroy", err); } #elif defined(HAVE_PTHREAD_GET_STACKADDR_NP) thrPtr->stackaddr = pthread_get_stackaddr_np(tid); thrPtr->stacksize = pthread_get_stacksize_np(tid) - guardsize; #endif return thrPtr; }
void Msg(char *fmt,...) { va_list ap; char *s, *r; time_t now; time(&now); s = ns_ctime(&now); r = strchr(s, '\n'); if (r) { *r = '\0'; } va_start(ap, fmt); Ns_MutexLock(&mlock); printf("[%s][%s]: ", Ns_ThreadGetName(), s); vfprintf(stdout, fmt, ap); printf("\n"); Ns_MutexUnlock(&mlock); va_end(ap); }
int main(int argc, char *argv[]) { int i, code; Ns_Thread threads[10]; Ns_Thread self, dumper; void *arg; char *p; #if PTHREAD_TEST pthread_t tids[10]; #endif NsThreads_LibInit(); Ns_ThreadSetName("-main-"); /* * Jump directly to memory test if requested. */ for (i = 1; i < argc; ++i) { p = argv[i]; switch (*p) { case 'n': break; case 'm': nthreads = atoi(p + 1); goto mem; break; } } Ns_ThreadCreate(DetachedThread, NULL, 0, NULL); Ns_ThreadCreate(DumperThread, NULL, 0, &dumper); Ns_MutexSetName(&lock, "startlock"); Ns_MutexSetName(&dlock, "dumplock"); Ns_MutexSetName(&mlock, "msglock"); Ns_MutexSetName(&block, "busylock"); Ns_ThreadStackSize(81920); Ns_SemaInit(&sema, 3); Msg("sema initialized to 3"); atexit(AtExit); Msg("pid = %d", getpid()); Ns_TlsAlloc(&key, TlsLogArg); for (i = 0; i < 10; ++i) { Msg("starting work thread %d", i); Ns_ThreadCreate(WorkThread, (void *) i, 0, &threads[i]); } sleep(1); /* Ns_CondSignal(&cond); */ Ns_SemaPost(&sema, 10); Msg("sema post 10"); Ns_RWLockWrLock(&rwlock); Msg("rwlock write locked (main thread)"); sleep(1); Ns_RWLockUnlock(&rwlock); Msg("rwlock write unlocked (main thread)"); for (i = 0; i < 10; ++i) { Msg("waiting for thread %d to exit", i); Ns_ThreadJoin(&threads[i], (void **) &code); Msg("thread %d exited - code: %d", i, code); } #if PTHREAD_TEST for (i = 0; i < 10; ++i) { pthread_create(&tids[i], NULL, Pthread, (void *) i); printf("pthread: create %d = %d\n", i, (int) tids[i]); Ns_ThreadYield(); } Ns_MutexLock(&plock); pgo = 1; Ns_MutexUnlock(&plock); Ns_CondBroadcast(&pcond); for (i = 0; i < 10; ++i) { pthread_join(tids[i], &arg); printf("pthread: join %d = %d\n", i, (int) arg); } #endif Ns_ThreadSelf(&self); Ns_MutexLock(&dlock); dstop = 1; Ns_CondSignal(&dcond); Ns_MutexUnlock(&dlock); Ns_ThreadJoin(&dumper, NULL); Msg("threads joined"); for (i = 0; i < 10; ++i) { Ns_ThreadCreate(CheckStackThread, NULL, 8192*(i+1), &threads[i]); } for (i = 0; i < 10; ++i) { Ns_ThreadJoin(&threads[i], &arg); printf("check stack %d = %d\n", i, (int) arg); } /*Ns_ThreadEnum(DumpThreads, NULL);*/ /*Ns_MutexEnum(DumpLocks, NULL);*/ mem: MemTime(0); MemTime(1); return 0; }
int NsTclServerObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) { Pool *poolPtr; char buf[100], *pool; Tcl_DString ds; static CONST char *opts[] = { "active", "all", "connections", "keepalive", "pools", "queued", "threads", "waiting", NULL, }; enum { SActiveIdx, SAllIdx, SConnectionsIdx, SKeepaliveIdx, SPoolsIdx, SQueuedIdx, SThreadsIdx, SWaitingIdx, } _nsmayalias opt; if (objc != 2 && objc != 3) { Tcl_WrongNumArgs(interp, 1, objv, "option ?pool?"); return TCL_ERROR; } if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0, (int *) &opt) != TCL_OK) { return TCL_ERROR; } if (opt == SPoolsIdx) { return NsTclListPoolsObjCmd(arg, interp, objc, objv); } if (objc == 2) { pool = "default"; } else { pool = Tcl_GetString(objv[2]); } if (NsTclGetPool(interp, pool, &poolPtr) != TCL_OK) { return TCL_ERROR; } Ns_MutexLock(&poolPtr->lock); switch (opt) { case SPoolsIdx: /* NB: Silence compiler. */ break; case SWaitingIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj(poolPtr->queue.wait.num)); break; case SKeepaliveIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj(0/*nsconf.keepalive.npending*/)); break; case SConnectionsIdx: Tcl_SetObjResult(interp, Tcl_NewIntObj((int) poolPtr->threads.nextid)); break; case SThreadsIdx: sprintf(buf, "min %d", poolPtr->threads.min); Tcl_AppendElement(interp, buf); sprintf(buf, "max %d", poolPtr->threads.max); Tcl_AppendElement(interp, buf); sprintf(buf, "current %d", poolPtr->threads.current); Tcl_AppendElement(interp, buf); sprintf(buf, "idle %d", poolPtr->threads.idle); Tcl_AppendElement(interp, buf); sprintf(buf, "stopping 0"); Tcl_AppendElement(interp, buf); break; case SActiveIdx: case SQueuedIdx: case SAllIdx: Tcl_DStringInit(&ds); if (opt != SQueuedIdx) { AppendConnList(&ds, poolPtr->queue.active.firstPtr, "running"); } if (opt != SActiveIdx) { AppendConnList(&ds, poolPtr->queue.wait.firstPtr, "queued"); } Tcl_DStringResult(interp, &ds); } Ns_MutexUnlock(&poolPtr->lock); return TCL_OK; }
void WorkThread(void *arg) { int i = (int) arg; int *ip; time_t now; Ns_Thread self; char name[32]; sprintf(name, "-work:%d-", i); Ns_ThreadSetName(name); if (i == 2) { Ns_RWLockWrLock(&rwlock); Msg("rwlock write aquired"); sleep(2); } else { Ns_RWLockRdLock(&rwlock); Msg("rwlock read aquired aquired"); sleep(1); } Ns_CsEnter(&cs); Msg("enter critical section once"); Ns_CsEnter(&cs); Msg("enter critical section twice"); Ns_CsLeave(&cs); Ns_CsLeave(&cs); Ns_ThreadSelf(&self); arg = Ns_TlsGet(&key); Ns_SemaWait(&sema); Msg("got semaphore posted from main"); if (arg == NULL) { arg = ns_malloc(sizeof(int)); Ns_TlsSet(&key, arg); } ip = arg; *ip = i; if (i == 5) { Ns_Time to; int st; Ns_GetTime(&to); Msg("time: %ld %ld", to.sec, to.usec); Ns_IncrTime(&to, 5, 0); Msg("time: %ld %ld", to.sec, to.usec); Ns_MutexLock(&lock); time(&now); Msg("timed wait starts: %s", ns_ctime(&now)); st = Ns_CondTimedWait(&cond, &lock, &to); Ns_MutexUnlock(&lock); time(&now); Msg("timed wait ends: %s - status: %d", ns_ctime(&now), st); } if (i == 9) { Msg("sleep 4 seconds start"); sleep(4); Msg("sleep 4 seconds done"); } time(&now); Ns_RWLockUnlock(&rwlock); Msg("rwlock unlocked"); Msg("exiting"); Ns_ThreadExit((void *) i); }
int NsTclEnvCmd(ClientData dummy, Tcl_Interp *interp, int argc, char **argv) { char *name, *value, **envp; int status, i; Tcl_DString ds; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " command ?args ...?\"", NULL); return TCL_ERROR; } status = TCL_OK; Ns_MutexLock(&lock); if (STREQ(argv[1], "names")) { if (argc != 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " names\"", NULL); status = TCL_ERROR; } else { Tcl_DStringInit(&ds); envp = Ns_GetEnviron(); for (i = 0; envp[i] != NULL; ++i) { name = envp[i]; value = strchr(name, '='); Tcl_DStringAppend(&ds, name, value ? value - name : -1); Tcl_AppendElement(interp, ds.string); Tcl_DStringTrunc(&ds, 0); } Tcl_DStringFree(&ds); } } else if (STREQ(argv[1], "exists")) { if (argc != 3) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " exists name\"", NULL); status = TCL_ERROR; } else { Tcl_SetResult(interp, getenv(argv[2]) ? "1" : "0", TCL_STATIC); } } else if (STREQ(argv[1], "get")) { if ((argc != 3 && argc != 4) || (argc == 4 && !STREQ(argv[2], "-nocomplain"))) { badargs: Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ", argv[1], " ?-nocomplain? name\"", NULL); status = TCL_ERROR; } name = argv[argc-1]; value = getenv(name); if (value != NULL) { Tcl_SetResult(interp, value, TCL_VOLATILE); } else if (argc == 4) { Tcl_AppendResult(interp, "no such environment variable: ", argv[argc-1], NULL); status = TCL_ERROR; } } else if (STREQ(argv[1], "set")) { if (argc != 4) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " set name value\"", NULL); status = TCL_ERROR; } else { status = PutEnv(interp, argv[2], argv[3]); } } else if (STREQ(argv[1], "unset")) { if ((argc != 3 && argc != 4) || (argc == 4 && !STREQ(argv[2], "-nocomplain"))) { goto badargs; } name = argv[argc-1]; if (argc == 3 && getenv(name) == NULL) { Tcl_AppendResult(interp, "no such environment variable: ", name, NULL); status = TCL_ERROR; } else { status = PutEnv(interp, name, ""); } } else { Tcl_AppendResult(interp, "unknown command \"", argv[1], "\": should be exists, names, get, set, or unset", NULL); status = TCL_ERROR; } Ns_MutexUnlock(&lock); return status; }
void NsConnThread(void *arg) { ConnData *dataPtr = arg; Pool *poolPtr = dataPtr->poolPtr; Conn *connPtr; Ns_Time wait, *timePtr; char name[100]; int status, ncons; char *msg; double spread; /* * Set the conn thread name. */ Ns_TlsSet(&ctdtls, dataPtr); Ns_MutexLock(&poolPtr->lock); sprintf(name, "-%s:%d-", poolPtr->name, poolPtr->threads.nextid++); Ns_MutexUnlock(&poolPtr->lock); Ns_ThreadSetName(name); /* spread is a value of 1.0 +- specified percentage, i.e. between 0.0 and 2.0 when the configured percentage is 100 */ spread = 1.0 + (2 * poolPtr->threads.spread * Ns_DRand() - poolPtr->threads.spread) / 100.0; ncons = round(poolPtr->threads.maxconns * spread); msg = "exceeded max connections per thread"; /* * Start handling connections. */ Ns_MutexLock(&poolPtr->lock); poolPtr->threads.starting--; poolPtr->threads.idle++; while (poolPtr->threads.maxconns <= 0 || ncons-- > 0) { /* * Wait for a connection to arrive, exiting if one doesn't * arrive in the configured timeout period. */ if (poolPtr->threads.current <= poolPtr->threads.min) { timePtr = NULL; } else { Ns_GetTime(&wait); Ns_IncrTime(&wait, round(poolPtr->threads.timeout * spread), 0); timePtr = &wait; } status = NS_OK; while (!poolPtr->shutdown && status == NS_OK && poolPtr->queue.wait.firstPtr == NULL) { /* nothing is queued, we wait for a queue entry */ poolPtr->threads.waiting++; status = Ns_CondTimedWait(&poolPtr->cond, &poolPtr->lock, timePtr); poolPtr->threads.waiting--; } if (poolPtr->queue.wait.firstPtr == NULL) { msg = "timeout waiting for connection"; break; } /* * Pull the first connection off the waiting list. */ connPtr = poolPtr->queue.wait.firstPtr; poolPtr->queue.wait.firstPtr = connPtr->nextPtr; if (poolPtr->queue.wait.lastPtr == connPtr) { poolPtr->queue.wait.lastPtr = NULL; } connPtr->nextPtr = NULL; connPtr->prevPtr = poolPtr->queue.active.lastPtr; if (poolPtr->queue.active.lastPtr != NULL) { poolPtr->queue.active.lastPtr->nextPtr = connPtr; } poolPtr->queue.active.lastPtr = connPtr; if (poolPtr->queue.active.firstPtr == NULL) { poolPtr->queue.active.firstPtr = connPtr; } poolPtr->threads.idle--; poolPtr->queue.wait.num--; Ns_MutexUnlock(&poolPtr->lock); /* * Run the connection. */ Ns_MutexLock(&connlock); dataPtr->connPtr = connPtr; Ns_MutexUnlock(&connlock); Ns_GetTime(&connPtr->times.run); ConnRun(connPtr); Ns_MutexLock(&connlock); dataPtr->connPtr = NULL; Ns_MutexUnlock(&connlock); /* * Remove from the active list and push on the free list. */ Ns_MutexLock(&poolPtr->lock); if (connPtr->prevPtr != NULL) { connPtr->prevPtr->nextPtr = connPtr->nextPtr; } else { poolPtr->queue.active.firstPtr = connPtr->nextPtr; } if (connPtr->nextPtr != NULL) { connPtr->nextPtr->prevPtr = connPtr->prevPtr; } else { poolPtr->queue.active.lastPtr = connPtr->prevPtr; } poolPtr->threads.idle++; Ns_MutexUnlock(&poolPtr->lock); NsFreeConn(connPtr); Ns_MutexLock(&poolPtr->lock); } /* * Append this thread to list of threads to reap. */ Ns_MutexLock(&joinlock); dataPtr->nextPtr = joinPtr; joinPtr = dataPtr; Ns_MutexUnlock(&joinlock); /* * Mark this thread as no longer active. */ if (poolPtr->shutdown) { msg = "shutdown pending"; } poolPtr->threads.current--; poolPtr->threads.idle--; if (((poolPtr->queue.wait.num > 0 && poolPtr->threads.idle == 0 && poolPtr->threads.starting == 0 ) || (poolPtr->threads.current < poolPtr->threads.min) ) && !poolPtr->shutdown) { /* Recreate a thread when on of the condings hold - there are more queue entries are still waiting, but no thread is either starting or idle, or - there are less than minthreads connection threads alive. */ poolPtr->threads.current ++; Ns_MutexUnlock(&poolPtr->lock); NsCreateConnThread(poolPtr, 0); /* joinThreads == 0 to avoid deadlock */ } else if (poolPtr->queue.wait.num > 0 && poolPtr->threads.waiting > 0) { /* Wake up a waiting thread */ Ns_CondSignal(&poolPtr->cond); Ns_MutexUnlock(&poolPtr->lock); } else { Ns_MutexUnlock(&poolPtr->lock); } Ns_Log(Notice, "exiting: %s", msg); Ns_ThreadExit(dataPtr); }