Esempio n. 1
0
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);
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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);
}
Esempio n. 4
0
int
Ns_LockMutex(Ns_Mutex *mutexPtr)
{
    Ns_MutexLock(mutexPtr);

    return NS_OK;
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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);
	}
    }
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
void
Ns_ThreadSetName(char *name)
{
    Thread *thrPtr = GetThread();

    Ns_MutexLock(&threadlock);
    strncpy(thrPtr->name, name, NS_THREAD_NAMESIZE);
    Ns_MutexUnlock(&threadlock);
}
Esempio n. 10
0
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);
    }
}
Esempio n. 11
0
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);
}
Esempio n. 12
0
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);
    }
}
Esempio n. 13
0
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);
}
Esempio n. 14
0
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);
}
Esempio n. 15
0
long
Ns_ThreadStackSize(long stacksize)
{
    long prev;

    Ns_MutexLock(&sizelock);
    prev = stackdef;
    if (stacksize > 0) {
	stackdef = stacksize;
    }
    Ns_MutexUnlock(&sizelock);
    return prev;
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
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);
}
Esempio n. 18
0
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);
    }
}
Esempio n. 19
0
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;
}
Esempio n. 20
0
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);
}
Esempio n. 21
0
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;
}
Esempio n. 22
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;
}
Esempio n. 23
0
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);
}
Esempio n. 24
0
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;
}
Esempio n. 25
0
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);
}