add: Tcl_GetTime(&jobPtr->endTime);
context: JobThread(void *arg){    Tcl_Interp *interp;    Job *jobPtr;    Queue *queuePtr = arg;    char buf[100];    CONST char *err;    Tcl_HashEntry *hPtr;    Ns_WaitForStartup();    Ns_MutexLock(&queuePtr->lock);    sprintf(buf, "-tcljob%d-", queuePtr->nthreads);    Ns_ThreadSetName(buf);    Ns_Log(Notice, "starting");    while (1) {	++queuePtr->nidle;	while ((queuePtr->firstPtr == NULL) &&               !(queuePtr->req == QUEUE_REQ_STOP)) {	    Ns_CondWait(&queuePtr->cond, &queuePtr->lock);	}	--queuePtr->nidle;	if (queuePtr->firstPtr == NULL) {	    break;	}	jobPtr = queuePtr->firstPtr;	queuePtr->firstPtr = jobPtr->nextPtr;	if (jobPtr->req == JOB_CANCEL) {	    FreeJob(jobPtr);	    continue;	}	jobPtr->state = JOB_RUNNING;	Ns_MutexUnlock(&queuePtr->lock);	interp = Ns_TclAllocateInterp(jobPtr->server);	jobPtr->code = Tcl_EvalEx(interp, jobPtr->ds.string, -1, 0);	Tcl_DStringTrunc(&jobPtr->ds, 0);	Tcl_DStringAppend(&jobPtr->ds, Tcl_GetStringResult(interp), -1);	err = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY);	if (err != NULL) {	    jobPtr->errorCode = ns_strdup(err);	}	err = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY);	if (err != NULL) {	    jobPtr->errorInfo = ns_strdup(err);	}	Ns_TclDeAllocateInterp(interp);	Ns_MutexLock(&queuePtr->lock);        jobPtr->state = JOB_DONE;	if ((jobPtr->req == JOB_CANCEL) ||            (jobPtr->type == JOB_DETACHED)) {            hPtr = Tcl_FindHashEntry(&queuePtr->jobs, Tcl_DStringValue(&jobPtr->id));            Tcl_DeleteHashEntry(hPtr);	    FreeJob(jobPtr);	}        Ns_CondBroadcast(&queuePtr->cond);    }    --queuePtr->nthreads;    Ns_CondBroadcast(&queuePtr->cond);    Ns_MutexUnlock(&queuePtr->lock);    Ns_Log(Notice, "exiting");}