rem: if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 1,
add: if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0,
context: static PoolFunc ListPool;static void IteratePools(PoolFunc *func, void *arg);static int AppendPool(Tcl_Interp *interp, char *key, int val);static int PoolResult(Tcl_Interp *interp, Pool *poolPtr);#define GetPool(i,o,pp)	(NsTclGetPool((i),Tcl_GetString((o)),(pp)))/* * Static variables defined in this file. */static int            poolid;static Pool          *defPoolPtr;static Pool          *errPoolPtr;static Tcl_HashTable  pools;/* *---------------------------------------------------------------------- * * NsInitPools -- * *	Init thread pools. * * Results: *	None. * * Side effects: *	The default and error pools will be created. * *---------------------------------------------------------------------- */voidNsInitPools(void){    poolid = Ns_UrlSpecificAlloc();    Tcl_InitHashTable(&pools, TCL_STRING_KEYS);    defPoolPtr = CreatePool("default");    errPoolPtr = CreatePool("error");}/* *---------------------------------------------------------------------- * * NsTclPoolsObjCmd -- * *	Implements ns_pools command to create and query thread pools. * * Results: *	Tcl result.  * * Side effects: *	See docs.  * *---------------------------------------------------------------------- */intNsTclPoolsObjCmd(ClientData data, Tcl_Interp *interp, int objc, Tcl_Obj **objv){    Pool *poolPtr, savedPool;    char *pool;    int i, val;    static CONST char *opts[] = {        "get", "set", "list", "register", NULL    };    enum {        PGetIdx, PSetIdx, PListIdx, PRegisterIdx    } opt;    static CONST char *cfgs[] = {        "-maxthreads", "-minthreads", "-maxconns", "-timeout", NULL    };    enum {        PCMaxThreadsIdx, PCMinThreadsIdx, PCMaxConnsIdx, PCTimeoutIdx    } cfg;    if (objc < 2) {        Tcl_WrongNumArgs(interp, 1, objv, "option ?args?");        return TCL_ERROR;    }    if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 1,                (int *) &opt) != TCL_OK) {        return TCL_ERROR;    }    switch (opt) {    case PListIdx:	return NsTclListPoolsObjCmd(data, interp, objc, objv);        break;    case PGetIdx:        if (objc != 3) {            Tcl_WrongNumArgs(interp, 2, objv, "pool");            return TCL_ERROR;        }        if (GetPool(interp, objv[2], &poolPtr) != TCL_OK) {            return TCL_ERROR;        }        if (PoolResult(interp, poolPtr) != TCL_OK) {            return TCL_ERROR;        }        break;    case PSetIdx:        if (objc < 3 || (((objc - 3) % 2) != 0)) {            Tcl_WrongNumArgs(interp, 2, objv, "limit ?opt val opt val...?");            return TCL_ERROR;        }        pool = Tcl_GetString(objv[2]);	poolPtr = CreatePool(pool);        savedPool = *poolPtr;        for (i = 3; i < objc; i += 2) {            if (Tcl_GetIndexFromObj(interp, objv[i], cfgs, "cfg", 0,                        (int *) &cfg) != TCL_OK ||                     Tcl_GetIntFromObj(interp, objv[i+1], &val) != TCL_OK) {                *poolPtr = savedPool;                return TCL_ERROR;            }            switch (cfg) {            case PCMinThreadsIdx:                poolPtr->threads.min = val;                break;            case PCMaxThreadsIdx:                poolPtr->threads.max = val;                break;            case PCTimeoutIdx:                poolPtr->threads.timeout = val;                break;            case PCMaxConnsIdx:                poolPtr->threads.maxconns = val;                break;            }        }        if (PoolResult(interp, poolPtr) != TCL_OK) {            return TCL_ERROR;        }        break;    case PRegisterIdx:        if (objc != 6) {            Tcl_WrongNumArgs(interp, 2, objv, "pool server method url");            return TCL_ERROR;        }        if (GetPool(interp, objv[2], &poolPtr) != TCL_OK) {            return TCL_ERROR;        }        Ns_UrlSpecificSet(Tcl_GetString(objv[3]),                Tcl_GetString(objv[4]),                Tcl_GetString(objv[5]), poolid, poolPtr, 0, NULL);        break;    }    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclListPoolsObjCmd -- * *	Sub-command to list all pools. Called by the ns_pools and *	ns_server commands. * * Results: *	Standard Tcl result. * * Side effects: *	None. * *---------------------------------------------------------------------- */intNsTclListPoolsObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv){    AppendData data;    if (objc != 2 && objc != 3) {        Tcl_WrongNumArgs(interp, 2, objv, "?pattern?");        return TCL_ERROR;    }    data.interp = interp;    if (objc == 2) {        data.pattern = NULL;    } else {        data.pattern = Tcl_GetString(objv[2]);    }    IteratePools(ListPool, &data);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsTclGetPool -- * *	Return Pool by name in Tcl. * * Results: *	Standard Tcl result. * * Side effects: *	Will update poolPtrPtr to point to Pool struct or leave *	an error message in given interp if no such pool. * *---------------------------------------------------------------------- */intNsTclGetPool(Tcl_Interp *interp, char *pool, Pool **poolPtrPtr){    Tcl_HashEntry *hPtr;    hPtr = Tcl_FindHashEntry(&pools, pool);    if (hPtr == NULL) {    	Tcl_AppendResult(interp, "no such pool: ", pool, NULL);    	return TCL_ERROR;    }    *poolPtrPtr = Tcl_GetHashValue(hPtr);    return TCL_OK;}/* *---------------------------------------------------------------------- * * NsGetConnPool -- * *	Get pool for given connection. * * Results: *	Pointer to Pool. * * Side effects: *	None. * *---------------------------------------------------------------------- */Pool *NsGetConnPool(Conn *connPtr){    Pool *poolPtr;    if (connPtr->flags & NS_CONN_OVERFLOW) {	return errPoolPtr;    }    poolPtr = Ns_UrlSpecificGet(connPtr->server, connPtr->request->method,				    connPtr->request->url, poolid);    if (poolPtr == NULL) {	return defPoolPtr;    }    return poolPtr;}/* *---------------------------------------------------------------------- * * NsStartPools, NsStopPools -- * *	Start and stop all connection pools. * * Results: *	None. * * Side effects: *	On stop, will wait for existing connections to complete. * *---------------------------------------------------------------------- */voidNsStartPools(void){    IteratePools(StartPool, NULL);}voidNsStopPools(Ns_Time *timePtr){    IteratePools(StopPool, NULL);    IteratePools(WaitPool, timePtr);}/* *---------------------------------------------------------------------- * * CreatePool -- * *	Create a new connection pool with default, unlimited values. * * Results: *	Pointer to new pool. * * Side effects: *	Pool is added to pools hash table. * *---------------------------------------------------------------------- */static Pool *CreatePool(char *name){    Pool *poolPtr;    Tcl_HashEntry *hPtr;    int new;    hPtr = Tcl_CreateHashEntry(&pools, name, &new);    if (!new) {	poolPtr = Tcl_GetHashValue(hPtr);    } else {    	poolPtr = ns_calloc(sizeof(Pool), 1);    	Ns_MutexInit(&poolPtr->lock);    	Ns_CondInit(&poolPtr->cond);    	Tcl_SetHashValue(hPtr, poolPtr);    	poolPtr->name = Tcl_GetHashKey(&pools, hPtr);    	poolPtr->threads.min = 0;           	poolPtr->threads.max = 10;          	poolPtr->threads.timeout = 120; /* NB: Exit after 2 minutes idle. */    	poolPtr->threads.maxconns = 0;  /* NB: Never exit thread. */   }    return poolPtr;}/* *---------------------------------------------------------------------- * * PoolResult -- * *	Append a list of current values for given pool. * * Results: *	TCL_OK or TCL_ERROR if list could not be appended. * * Side effects: *	Will leave list in interp result. * *---------------------------------------------------------------------- */static intPoolResult(Tcl_Interp *interp, Pool *poolPtr){    if (!AppendPool(interp, "minthreads", poolPtr->threads.min) ||        !AppendPool(interp, "maxthreads", poolPtr->threads.max) ||        !AppendPool(interp, "idle", poolPtr->threads.idle) ||        !AppendPool(interp, "current", poolPtr->threads.current) ||        !AppendPool(interp, "maxconns", poolPtr->threads.maxconns) ||        !AppendPool(interp, "queued", poolPtr->threads.queued) ||        !AppendPool(interp, "timeout", poolPtr->threads.timeout)) {    	return TCL_ERROR;    }    return TCL_OK;}static intAppendPool(Tcl_Interp *interp, char *key, int val){    Tcl_Obj *result = Tcl_GetObjResult(interp);    if (Tcl_ListObjAppendElement(interp, result, Tcl_NewStringObj(key, -1))            != TCL_OK ||            Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(val))            != TCL_OK) {        return 0;    }    return 1;}/* *---------------------------------------------------------------------- * * IteratePools -- * *	Invoke a callback for all current pools. * * Results: *	None. * * Side effects: *	Depends on callback. * *---------------------------------------------------------------------- */static voidIteratePools(PoolFunc *func, void *arg){    Tcl_HashSearch search;    Tcl_HashEntry *hPtr;    hPtr = Tcl_FirstHashEntry(&pools, &search);    while (hPtr != NULL) {        (*func)(Tcl_GetHashValue(hPtr), arg);        hPtr = Tcl_NextHashEntry(&search);    }}/* *---------------------------------------------------------------------- * * StartPool, StopPool, WaitPool, ListPool -- * *	Callbacks for IteratePools. * * Results: *	None. * * Side effects: *	Will start, signal stop, wait for stop, or append a pool *	to given interp depending on callback. * *---------------------------------------------------------------------- */static voidStartPool(Pool *poolPtr, void *ignored){    int i;    poolPtr->threads.current = poolPtr->threads.idle = poolPtr->threads.min;    for (i = 0; i < poolPtr->threads.min; ++i) {        NsCreateConnThread(poolPtr);    }}static voidStopPool(Pool *poolPtr, void *ignored){    Ns_MutexLock(&poolPtr->lock);    poolPtr->shutdown = 1;    Ns_CondBroadcast(&poolPtr->cond);    Ns_MutexUnlock(&poolPtr->lock);}static voidWaitPool(Pool *poolPtr, void *arg){    Ns_Time *timePtr = arg;    int status;        status = NS_OK;    Ns_MutexLock(&poolPtr->lock);    while (status == NS_OK &&            (poolPtr->queue.wait.firstPtr != NULL ||             poolPtr->threads.current > 0)) {        status = Ns_CondTimedWait(&poolPtr->cond, &poolPtr->lock, timePtr);    }    if (status != NS_OK) {        Ns_Log(Warning, "timeout waiting for connection thread exit");    }}static voidListPool(Pool *poolPtr, void *arg){    AppendData *dataPtr = arg;    if (dataPtr->pattern == NULL		|| Tcl_StringMatch(poolPtr->name, dataPtr->pattern)) {	Tcl_AppendElement(dataPtr->interp, poolPtr->name);    }}