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); }
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 NsAppendConn(Tcl_DString *dsPtr, Conn *connPtr, char *state) { Ns_Time now, diff; Ns_GetTime(&now); Ns_DiffTime(&now, &connPtr->times.queue, &diff); Tcl_DStringStartSublist(dsPtr); Ns_DStringPrintf(dsPtr, "%d", connPtr->id); Tcl_DStringAppendElement(dsPtr, Ns_ConnPeer((Ns_Conn *) connPtr)); Tcl_DStringAppendElement(dsPtr, state); NsAppendRequest(dsPtr, connPtr->request); Ns_DStringPrintf(dsPtr, " %ld.%ld %d", diff.sec, diff.usec, connPtr->nContentSent); Tcl_DStringEndSublist(dsPtr); }
int Ns_UTimedWaitForEvent(Ns_Event *event, Ns_Mutex *lock, int seconds, int microseconds) { Ns_Time to, *timePtr; if (seconds <= 0 && microseconds <= 0) { timePtr = NULL; } else { Ns_GetTime(&to); Ns_IncrTime(&to, seconds, microseconds); timePtr = &to; } return Ns_CondTimedWait((Ns_Cond *) event, lock, timePtr); }
int Ns_ConnClose(Ns_Conn *conn) { Conn *connPtr = (Conn *)conn; int keep; if (connPtr->sockPtr != NULL) { Ns_GetTime(&connPtr->times.close); keep = (conn->flags & NS_CONN_KEEPALIVE) ? 1 : 0; NsSockClose(connPtr->sockPtr, keep); connPtr->sockPtr = NULL; connPtr->flags |= NS_CONN_CLOSED; if (connPtr->itPtr != NULL) { NsTclRunAtClose(connPtr->itPtr); } } return NS_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); }
static void StackPages(Thread *thrPtr, int mark) { Ns_Time now; caddr_t start, end, guard, base; int fd, overflow, pagewords, pages, maxpage, bytes; uint32_t *ip; char file[100]; /* * Determine the range of pages to mark or check. Basically the first * page to be used is ignored assuming it's being used now and the * guard pages are marked completely to check for overflow. All pages * in between are marked on the first integer word to be later counted * to get a pages used count. */ if (stackdown) { start = thrPtr->stackaddr - thrPtr->stacksize + guardsize; end = thrPtr->stackaddr - pagesize; guard = start - guardsize; } else { start = thrPtr->stackaddr + pagesize; end = thrPtr->stackaddr + thrPtr->stacksize - guardsize; guard = end; } /* * Completely mark the guard page. */ overflow = 0; ip = (uint32_t *) guard; while (ip < (uint32_t *) (guard + guardsize)) { if (mark) { *ip = STACK_MAGIC; } else if (*ip != STACK_MAGIC) { overflow = 1; break; } ++ip; } /* * For each stack page, either mark with the magic number at thread * startup or count unmarked pages at thread cleanup. */ pagewords = pagesize / sizeof(uint32_t); maxpage = pages = 1; ip = (uint32_t *) start; if (stackdown) { /* NB: Mark last word, not first, of each page. */ ip += pagewords - 1; } while (ip < (uint32_t *) end) { if (mark) { *ip = STACK_MAGIC; } else if (*ip != STACK_MAGIC) { maxpage = pages; } ++pages; ip += pagewords; } if (!mark) { pages = maxpage; } bytes = pages * pagesize; if (!mark && dumpdir != NULL) { sprintf(file, "%s/nsstack.%lu", dumpdir, thrPtr->uid); fd = open(file, O_WRONLY|O_TRUNC|O_CREAT, 0644); if (fd >= 0) { base = thrPtr->stackaddr; if (stackdown) { base -= thrPtr->stacksize; } (void) write(fd, base, thrPtr->stacksize); close(fd); } } if (logfp) { Ns_GetTime(&now); fprintf(logfp, "%s: time: %ld:%ld, thread: %lu, %s: %d pages, %d bytes%s\n", mark ? "create" : "exit", now.sec, now.usec, thrPtr->uid, mark ? "stackavil" : "stackuse", pages, bytes, overflow ? " - possible overflow!" : ""); } }
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); }