rem: &timeout.sec) != TCL_OK) ||
add: &sec) != TCL_OK) ||
context: NsTclJobObjCmd(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv){    NsInterp            *itPtr = arg;    Queue               *queuePtr = NULL;    Job                 *jobPtr = NULL, **nextPtrPtr;    int                 code, new, create = 0, max;    char                *jobId = NULL, buf[100], *queueId;    Tcl_HashEntry       *hPtr, *jPtr;    Tcl_HashSearch      search;    int                 argIndex;    static CONST char *opts[] = {        "cancel", "create", "delete", "genid", "jobs", "joblist",        "threadlist", "queue", "queues", "queuelist", "wait",        "waitany",  NULL    };        enum {        JCancelIdx, JCreateIdx, JDeleteIdx, JGenIDIdx, JJobsIdx, JJobsListIdx,        JThreadListIdx, JQueueIdx, JQueuesIdx, JQueueListIdx, JWaitIdx, JWaitAnyIdx    } opt;    if (objc < 2) {	Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?");	return TCL_ERROR;    }    if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", TCL_EXACT,                            (int *) &opt) != TCL_OK) {        return TCL_ERROR;    }    code = TCL_OK;    switch (opt) {        case JCreateIdx:        {            /*             * ns_job create             *             * Create a new thread pool queue.             */            Tcl_Obj *queueIdObj = NULL;            char *queueDesc = "";            argIndex = 2;            if ((objc < 3) || (objc > 6)) {                Tcl_WrongNumArgs(interp, 2, objv,                                 "?-desc description? queueId ?maxThreads?");                return TCL_ERROR;            }            if (objc > 3) {                if (strncmp(Tcl_GetString(objv[argIndex]), "-desc", strlen("-desc")) == 0) {                    ++argIndex;                    queueDesc = Tcl_GetString(objv[argIndex++]);                }            }            queueIdObj = objv[argIndex++];            queueId = Tcl_GetString(queueIdObj);            max = NS_JOB_DEFAULT_MAXTHREADS;            if ((objc > argIndex) &&                Tcl_GetIntFromObj(interp, objv[argIndex++], &max) != TCL_OK) {                return TCL_ERROR;            }            Ns_MutexLock(&tp.queuelock);            hPtr = Tcl_CreateHashEntry(&tp.queues, Tcl_GetString(queueIdObj), &new);            if (new) {                queuePtr = NewQueue(Tcl_GetHashKey(&tp.queues, hPtr),queueDesc, max);                Tcl_SetHashValue(hPtr, queuePtr);            }            Ns_MutexUnlock(&tp.queuelock);            if (!new) {                Tcl_AppendResult(interp, "queue already exists: ", queueId, NULL);                return TCL_ERROR;            }            Tcl_SetObjResult(interp, queueIdObj);        }        break;        case JDeleteIdx:        {            /*             * ns_job delete             *             * Request that the specified queue be deleted. The queue will             * only be deleted when all jobs are removed.             */            if (objc != 3) {                Tcl_WrongNumArgs(interp, 2, objv, "queueId");                return TCL_ERROR;            }                        if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) {                return TCL_ERROR;            }            queuePtr->req = QUEUE_REQ_DELETE;            ReleaseQueue(queuePtr, 0);                            Ns_CondBroadcast(&tp.cond);            Tcl_SetResult(interp, "", TCL_STATIC);        }        break;        case JQueueIdx:        {            /*             * ns_job queue             *             * Add a new job the specified queue.             */            int job_type = JOB_NON_DETACHED;            argIndex = 2;            if ((objc != 4) && (objc != 5)) {                Tcl_WrongNumArgs(interp, 2, objv, "?-detached? queueId script");                return TCL_ERROR;            }            if (objc > 4) {                if (strcmp(Tcl_GetString(objv[argIndex++]), "-detached") == 0) {                    job_type = JOB_DETACHED;                } else {                    Tcl_WrongNumArgs(interp, 2, objv, "?-detached? queueId script");                    return TCL_ERROR;                }            }                            Ns_MutexLock(&tp.queuelock);            if (LookupQueue(interp, Tcl_GetString(objv[argIndex++]),                            &queuePtr, 1) != TCL_OK) {                Ns_MutexUnlock(&tp.queuelock);                return TCL_ERROR;            }                        /*             * Create a new job and add to the Thread Pool's list of jobs.             */            jobPtr = NewJob((itPtr->servPtr ? itPtr->servPtr->server : NULL),                            queuePtr->name,                            job_type,                            objv[argIndex++]);            Ns_GetTime(&jobPtr->startTime);            if ((tp.req == THREADPOOL_REQ_STOP) ||                 (queuePtr->req == QUEUE_REQ_DELETE))            {                Tcl_AppendResult(interp,                                 "The specified queue is being deleted or "                                 "the system is stopping.", NULL);                FreeJob(jobPtr);                ReleaseQueue(queuePtr, 1);                Ns_MutexUnlock(&tp.queuelock);                return TCL_ERROR;            }            /*             * Add the job to the thread pool's job list.             */            nextPtrPtr = &tp.firstPtr;            while (*nextPtrPtr != NULL) {                nextPtrPtr = &((*nextPtrPtr)->nextPtr);            }            *nextPtrPtr = jobPtr;                        /*             * Start a new thread if there are less than maxThreads currently             * running and there currently no idle threads.             */            if (tp.nidle == 0 && tp.nthreads < tp.maxThreads) {                create = 1;                ++tp.nthreads;            } else {                create = 0;            }            /*             * Add the job to queue.             */            jobId = buf;            do {                sprintf(jobId, "job%d", queuePtr->nextid++);                hPtr = Tcl_CreateHashEntry(&queuePtr->jobs, jobId, &new);            } while (!new);            Tcl_DStringAppend(&jobPtr->id, jobId, -1);            Tcl_SetHashValue(hPtr, jobPtr);            Ns_CondBroadcast(&tp.cond);            ReleaseQueue(queuePtr, 1);            Ns_MutexUnlock(&tp.queuelock);            if (create) {                Ns_ThreadCreate(JobThread, 0, 0, NULL);            }            Tcl_SetResult(interp, jobId, TCL_VOLATILE);        }        break;        case JWaitIdx:        {            /*             * ns_job wait             *             * Wait for the specified job.             */            int         timeoutFlag = 0;            Ns_Time     timeout;            int         timedOut = 0;            argIndex = 2;            if ((objc != 4) && (objc != 7)) {                Tcl_WrongNumArgs(interp, 2, objv,                                 "?-timeout seconds milliseconds? queueId jobId");                return TCL_ERROR;            }            if (objc > 4) {                if (strcmp(Tcl_GetString(objv[argIndex++]), "-timeout") == 0) {                    timeoutFlag = 1;                    if ((Tcl_GetLongFromObj(interp, objv[argIndex++],                                            &timeout.sec) != TCL_OK) ||                        (Tcl_GetLongFromObj(interp, objv[argIndex++],                                            &timeout.usec) != TCL_OK)) {                        return TCL_ERROR;                    }                    /*                     * Convert the specified milliseconds to microseconds.                     */                    timeout.usec *= 1000;                }            }            if (LookupQueue(interp, Tcl_GetString(objv[argIndex++]),                            &queuePtr, 0) != TCL_OK) {                return TCL_ERROR;            }            jobId = Tcl_GetString(objv[argIndex++]);            hPtr = Tcl_FindHashEntry(&queuePtr->jobs, jobId);            if (hPtr == NULL) {                ReleaseQueue(queuePtr, 0);                Tcl_AppendResult(interp, "no such job: ", jobId, NULL);                return TCL_ERROR;            }            jobPtr = Tcl_GetHashValue(hPtr);            if ((jobPtr->type == JOB_DETACHED) ||                (jobPtr->req == JOB_CANCEL) ||                (jobPtr->req == JOB_WAIT)) {                Tcl_AppendResult(interp,                                 "Cannot wait on job. Job ID : Job Req: %s",                                 Tcl_DStringValue(&jobPtr->id),                                 GetJobReqStr(jobPtr->req),                                 NULL);                ReleaseQueue(queuePtr, 0);                return TCL_ERROR;            }                            jobPtr->req = JOB_WAIT;                    if (timeoutFlag) {                while (jobPtr->state != JOB_DONE) {                    timedOut = Ns_CondTimedWait(&queuePtr->cond,                                                &queuePtr->lock, &timeout);                    if (timedOut == NS_TIMEOUT) {                        Tcl_SetResult(interp, "Wait timed out.", TCL_STATIC);                        jobPtr->req = JOB_NONE;                        ReleaseQueue(queuePtr, 0);                        return TCL_ERROR;                    }                }            } else {                while (jobPtr->state != JOB_DONE) {                    Ns_CondWait(&queuePtr->cond, &queuePtr->lock);                }            }            /*             * At this point the job we were waiting on has completed, so we return             * the job's results and errorcodes, then clean up the job.             */            /*             * The following is a sanity check to ensure that the no             * other process removed this job's entry.             */            hPtr = Tcl_FindHashEntry(&queuePtr->jobs, jobId);            assert(hPtr != NULL);            assert(jobPtr == Tcl_GetHashValue(hPtr));            if (hPtr != NULL) {                Tcl_DeleteHashEntry(hPtr);            }            ReleaseQueue(queuePtr, 0);            Tcl_DStringResult(interp, &jobPtr->results);            if (jobPtr->errorCode != NULL) {                Tcl_SetVar(interp, "errorCode", jobPtr->errorCode, TCL_GLOBAL_ONLY);            }            if (jobPtr->errorInfo != NULL) {                Tcl_SetVar(interp, "errorInfo", jobPtr->errorInfo, TCL_GLOBAL_ONLY);            }            code = jobPtr->code;            FreeJob(jobPtr);        }        break;        case JCancelIdx:        {            /*             * ns_job cancel             *             * Cancel the specified job.             */            if (objc != 4) {                Tcl_WrongNumArgs(interp, 2, objv, "queueId jobId");                return TCL_ERROR;            }            if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) {                return TCL_ERROR;            }            jobId = Tcl_GetString(objv[3]);            jPtr = Tcl_FindHashEntry(&queuePtr->jobs, jobId);            if (jPtr == NULL) {                ReleaseQueue(queuePtr, 0);                Tcl_AppendResult(interp, "no such job: ", jobId, NULL);                return TCL_ERROR;            }            jobPtr = Tcl_GetHashValue(jPtr);            if (jobPtr->req == JOB_WAIT) {                Tcl_AppendResult(interp,                                 "Can not cancel this job because someone"                                 " is waiting on it. Job ID: ",                                 Tcl_DStringValue(&jobPtr->id), NULL);                            ReleaseQueue(queuePtr, 0);                return TCL_ERROR;            }                            jobPtr->req = JOB_CANCEL;            if (jobPtr->state == JOB_DONE) {                Tcl_DeleteHashEntry(jPtr);                FreeJob(jobPtr);                            }             Ns_CondBroadcast(&queuePtr->cond);                        Ns_CondBroadcast(&tp.cond);            Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (jobPtr->state == JOB_RUNNING));            ReleaseQueue(queuePtr, 0);        }        break;        case JWaitAnyIdx:        {            /*             * ns_job waitany             *             * Wait for any job on the queue complete.             */            int         timeoutFlag = 0;            Ns_Time     timeout;            int         timedOut = 0;            argIndex = 2;            if ((objc != 3) && (objc != 6)) {                Tcl_WrongNumArgs(interp, 2, objv,                                 "?-timeout seconds milliseconds? queueId");                return TCL_ERROR;            }                   if (objc > 3) {                if (strcmp(Tcl_GetString(objv[argIndex++]), "-timeout") == 0) {                    timeoutFlag = 1;                    if ((Tcl_GetLongFromObj(interp, objv[argIndex++],                                            &timeout.sec) != TCL_OK) ||                        (Tcl_GetLongFromObj(interp, objv[argIndex++],                                            &timeout.usec) != TCL_OK)) {                        return TCL_ERROR;                    }                    /*                     * Convert the specified milliseconds to microseconds.                     */                    timeout.usec *= 1000;                }            }            if (LookupQueue(interp, Tcl_GetString(objv[argIndex++]),                            &queuePtr, 0) != TCL_OK) {                return TCL_ERROR;            }            /*              * While there are jobs in queue or no jobs are "done", wait             * on the queue condition variable.              */            if (timeoutFlag) {                while ((Tcl_FirstHashEntry(&queuePtr->jobs, &search) != NULL) &&                       (!AnyDone(queuePtr))) {                                        timedOut = Ns_CondTimedWait(&queuePtr->cond,                                                &queuePtr->lock, &timeout);                    if (timedOut == NS_TIMEOUT) {                        Tcl_SetResult(interp, "Wait timed out.", TCL_STATIC);                                                ReleaseQueue(queuePtr, 0);                        return TCL_ERROR;                    }                }            } else {                while ((Tcl_FirstHashEntry(&queuePtr->jobs, &search) != NULL) &&                       (!AnyDone(queuePtr))) {                    Ns_CondWait(&queuePtr->cond, &queuePtr->lock);                }            }            ReleaseQueue(queuePtr, 0);            Tcl_SetResult(interp, "", TCL_STATIC);        }        break;        case JJobsIdx:        {            /*             * ns_job jobs             *             * Returns a list of job IDs in arbitrary order.             */            if (objc != 3) {                Tcl_WrongNumArgs(interp, 2, objv, "queueId");                return TCL_ERROR;            }            if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) {                return TCL_ERROR;            }            hPtr = Tcl_FirstHashEntry(&queuePtr->jobs, &search);            while (hPtr != NULL) {                jobId = Tcl_GetHashKey(&queuePtr->jobs, hPtr);                Tcl_AppendElement(interp, jobId);                hPtr = Tcl_NextHashEntry(&search);            }            ReleaseQueue(queuePtr, 0);        }        break;        case JQueuesIdx:        {            /*             * ns_job queues             *             * Returns a list of the current queues.             */            Ns_MutexLock(&tp.queuelock);            hPtr = Tcl_FirstHashEntry(&tp.queues, &search);            while (hPtr != NULL) {                queuePtr = Tcl_GetHashValue(hPtr);                Tcl_AppendElement(interp, queuePtr->name);                hPtr = Tcl_NextHashEntry(&search);            }            Ns_MutexUnlock(&tp.queuelock);        }        break;         case JJobsListIdx:        {            /*             * ns_job joblist             *             * Returns a list of all the jobs in the queue. The "job" consists of:             *             * Job ID             * Job State (Scheduled, Running, or Done)             * Job Results (or job script, if job has not yet completed).             * Job Code (TCL_OK, TCL_ERROR, TCL_RETURN, TCL_BREAK, TCL_CONTINE)             * Job Running Time (TBD)             */            Tcl_Obj     *jobList, *jobFieldList;            char        *jobId, *jobState, *jobCode, *jobType;            char        *jobResults, *jobScript, *jobReq;            double      delta;            if (objc != 3) {                Tcl_WrongNumArgs(interp, 2, objv, "queueId");                return TCL_ERROR;            }            if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) {                return TCL_ERROR;            }            /* Create a Tcl List to hold the list of jobs. */            jobList = Tcl_NewListObj(0, NULL);            hPtr = Tcl_FirstHashEntry(&queuePtr->jobs, &search);            while (hPtr != NULL) {                jobPtr = Tcl_GetHashValue(hPtr);                jobId = Tcl_GetHashKey(&queuePtr->jobs, hPtr);                jobCode = GetJobCodeStr(jobPtr->code);                jobState = GetJobStateStr(jobPtr->state);                jobType = GetJobTypeStr(jobPtr->type);                jobReq = GetJobReqStr(jobPtr->req);                jobResults = Tcl_DStringValue(&jobPtr->results);                jobScript = Tcl_DStringValue(&jobPtr->script);                if ((jobPtr->state == JOB_SCHEDULED) ||                    (jobPtr->state == JOB_RUNNING)) {                    Ns_GetTime(&jobPtr->endTime);                }                delta = ComputeDelta(&jobPtr->startTime, &jobPtr->endTime);                /* Create a Tcl List to hold the list of job fields. */                jobFieldList = Tcl_NewListObj(0, NULL);                /* Add Job ID */                if ((AppendField(interp, jobFieldList,                                 "id", jobId) != TCL_OK) ||                    (AppendField(interp, jobFieldList,                                 "state", jobState) != TCL_OK) ||                    (AppendField(interp, jobFieldList,                                 "results", jobResults) != TCL_OK) ||                    (AppendField(interp, jobFieldList,                                 "script", jobScript) != TCL_OK) ||                    (AppendField(interp, jobFieldList,                                 "code", jobCode) != TCL_OK) ||                    (AppendField(interp, jobFieldList,                                 "type", jobType) != TCL_OK) ||                    (AppendField(interp, jobFieldList,                                 "req", jobReq) != TCL_OK) ||                    (AppendFieldDouble(interp, jobFieldList,                                       "time", delta) != TCL_OK) ||                    (AppendFieldLong(interp,                                     jobFieldList,                                     "starttime",                                     jobPtr->startTime.sec) != TCL_OK) ||                    (AppendFieldLong(interp,                                     jobFieldList,                                     "endtime",                                     jobPtr->endTime.sec) != TCL_OK))                {                    /* AppendField sets results if an error occurs. */                    Tcl_DecrRefCount(jobList);                    Tcl_DecrRefCount(jobFieldList);                    Ns_MutexUnlock(&queuePtr->lock);                    return TCL_ERROR;                }                /* Add the job to the job list */                if (Tcl_ListObjAppendElement(interp, jobList, jobFieldList) != TCL_OK) {                    Tcl_DecrRefCount(jobList);                    Tcl_DecrRefCount(jobFieldList);                                        ReleaseQueue(queuePtr, 0);                    return TCL_ERROR;                }                hPtr = Tcl_NextHashEntry(&search);            }            Tcl_SetObjResult(interp, jobList);            ReleaseQueue(queuePtr, 0);        }        break;        case JQueueListIdx:        {            /*             * ns_job queuelist             *             * Returns a list of all the queues and the queue information.             */            Tcl_Obj     *queueList, *queueFieldList;            char        *queueReq;            /* Create a Tcl List to hold the list of jobs. */            queueList = Tcl_NewListObj(0, NULL);            Ns_MutexLock(&tp.queuelock);            hPtr = Tcl_FirstHashEntry(&tp.queues, &search);            while (hPtr != NULL) {                queuePtr = Tcl_GetHashValue(hPtr);                /* Create a Tcl List to hold the list of queue fields. */                queueFieldList = Tcl_NewListObj(0, NULL);                queueReq = GetQueueReqStr(queuePtr->req);                /* Add queue name */                if ((AppendField(interp, queueFieldList,                                 "name", queuePtr->name) != TCL_OK) ||                    (AppendField(interp, queueFieldList,                                 "desc", queuePtr->desc) != TCL_OK) ||                    (AppendFieldInt(interp, queueFieldList,                                    "maxthreads", queuePtr->maxThreads) != TCL_OK) ||                    (AppendFieldInt(interp, queueFieldList,                                    "numrunning", queuePtr->nRunning) != TCL_OK) ||                    (AppendField(interp, queueFieldList,                                 "req", queueReq) != TCL_OK))                {                    /* AppendField sets results if an error occurs. */                    Tcl_DecrRefCount(queueList);                    Tcl_DecrRefCount(queueFieldList);                    Ns_MutexUnlock(&tp.queuelock);                    return TCL_ERROR;                }                /* Add the job to the job list */                if (Tcl_ListObjAppendElement(interp, queueList,                                             queueFieldList) != TCL_OK) {                    Tcl_DecrRefCount(queueList);                    Tcl_DecrRefCount(queueFieldList);                    Ns_MutexUnlock(&tp.queuelock);                    return TCL_ERROR;                }                hPtr = Tcl_NextHashEntry(&search);            }            Tcl_SetObjResult(interp, queueList);            Ns_MutexUnlock(&tp.queuelock);        }        break;         case JGenIDIdx:        {            /*             * ns_job genID             *             * Generate a unique queue name.             */            Ns_Time currentTime;            Ns_GetTime(&currentTime);            snprintf(buf, 100, "queue_id_%x_%x", tp.nextQueueId++, currentTime.sec);            Tcl_SetResult(interp, buf, TCL_VOLATILE);        }        break;        case JThreadListIdx:        {            /*             * ns_job threadlist             *             * Return a list of the thread pool's fields.             *             */             Tcl_Obj     *tpFieldList;            char        *tpReq;            /* Create a Tcl List to hold the list of thread fields. */            tpFieldList = Tcl_NewListObj(0, NULL);            tpReq = GetTpReqStr(tp.req);            Ns_MutexLock(&tp.queuelock);                        /* Add queue name */            if ((AppendFieldInt(interp, tpFieldList,                                "maxthreads", tp.maxThreads) != TCL_OK) ||                (AppendFieldInt(interp, tpFieldList,                                "numthreads", tp.nthreads) != TCL_OK) ||                (AppendFieldInt(interp, tpFieldList,                                "numidle", tp.nidle) != TCL_OK) ||                (AppendField(interp, tpFieldList,                             "req", tpReq) != TCL_OK))            {                /* AppendField sets results if an error occurs. */                Tcl_DecrRefCount(tpFieldList);                Ns_MutexUnlock(&tp.queuelock);                return TCL_ERROR;            }            Ns_MutexUnlock(&tp.queuelock);            Tcl_SetObjResult(interp, tpFieldList);        }        break;    }    return code;}