Applied patches from Stephen Deasey for better compile time error checking.
1 | /* |
2 | * The contents of this file are subject to the AOLserver Public License |
3 | * Version 1.1 (the "License"); you may not use this file except in |
4 | * compliance with the License. You may obtain a copy of the License at |
5 | * http://aolserver.com/. |
6 | * |
7 | * Software distributed under the License is distributed on an "AS IS" |
8 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See |
9 | * the License for the specific language governing rights and limitations |
10 | * under the License. |
11 | * |
12 | * The Original Code is AOLserver Code and related documentation |
13 | * distributed by AOL. |
14 | * |
15 | * The Initial Developer of the Original Code is America Online, |
16 | * Inc. Portions created by AOL are Copyright (C) 1999 America Online, |
17 | * Inc. All Rights Reserved. |
18 | * |
19 | * Alternatively, the contents of this file may be used under the terms |
20 | * of the GNU General Public License (the "GPL"), in which case the |
21 | * provisions of GPL are applicable instead of those above. If you wish |
22 | * to allow use of your version of this file only under the terms of the |
23 | * GPL and not to allow others to use your version of this file under the |
24 | * License, indicate your decision by deleting the provisions above and |
25 | * replace them with the notice and other provisions required by the GPL. |
26 | * If you do not delete the provisions above, a recipient may use your |
27 | * version of this file under either the License or the GPL. |
28 | */ |
29 | |
30 | |
31 | /* |
32 | * tcljob.c -- |
33 | * |
34 | * Tcl job queueing routines. |
35 | * |
36 | * Lock rules: |
37 | * |
38 | * Lock the queuelock when modifing tp structure elements. |
39 | * |
40 | * Lock the queue's lock when modifing queue structure elements. |
41 | * |
42 | * Jobs are shared between tp and the queue but are owned by the queue, |
43 | * so use queue's lock is used to control access to the jobs. |
44 | * |
45 | * To avoid deadlock, when locking both the queuelock and queue's |
46 | * lock lock the queuelock first. |
47 | * |
48 | * |
49 | * To avoid deadlock, the tp queuelock should be locked before the |
50 | * queue's lock. |
51 | * |
52 | * |
53 | * Notes: |
54 | * |
55 | * The threadpool's max number of thread is the sum of all the current |
56 | * queue's max threads. |
57 | * |
58 | * The number of threads in the thread pool can be greater than |
59 | * the current max number of threads. This situtation can occur when |
60 | * a queue is deleted. Later on if a new queue is created it will simply |
61 | * use one of the previously created threads. Basically the number of |
62 | * threads is a "high water mark". |
63 | * |
64 | * The queues are reference counted. Only when a queue is empty and |
65 | * its reference count is zero can it be deleted. |
66 | * |
67 | * We can no longer use a Tcl_Obj to represent the queue because queues can |
68 | * now be deleted. Tcl_Objs are deleted when the object goes out of |
69 | * scope, whereas queues are deleted when delete is called. By doing |
70 | * this the queue can be used across tcl interpreters. |
71 | * |
72 | * ToDo: |
73 | * |
74 | * Users can leak queues. A queue will stay around until a user |
75 | * cleans it up. It order to help the user out we would like to |
76 | * add an "-autoclean" option to queue create function. However, |
77 | * AOLServer does not currently supply a "good" connection cleanup |
78 | * callback. We tryed to use "<a href="/cvs/aolserver/aolserver/nsd/filter.c#A_Ns_RegisterConnCleanup">Ns_RegisterConnCleanup</a>" however it does |
79 | * not have a facility to remove registered callbacks. |
80 | * |
81 | */ |
82 | |
83 | static const char *RCSID = "@(#) $Header: /cvsroot-fuse/aolserver/aolserver/nsd/tcljob.c,v 1.31 2005/08/23 21:41:31 jgdavidson Exp $, compiled: " __DATE__ " " __TIME__; |
84 | |
85 | #include "nsd.h" |
86 | |
87 | /* |
88 | * Default Max Threads |
89 | * - If a user does not specify the a max number of threads for a queue, |
90 | * then the following default is used. |
91 | */ |
92 | #define NS_JOB_DEFAULT_MAXTHREADS 4 |
93 | |
94 | typedef enum JobStates { |
95 | JOB_SCHEDULED = 0, |
96 | JOB_RUNNING, |
97 | JOB_DONE |
98 | } JobStates; |
99 | |
100 | typedef enum JobTypes { |
101 | JOB_NON_DETACHED = 0, |
102 | JOB_DETACHED |
103 | } JobTypes; |
104 | |
105 | typedef enum JobRequests { |
106 | JOB_NONE = 0, |
107 | JOB_WAIT, |
108 | JOB_CANCEL |
109 | } JobRequests; |
110 | |
111 | typedef enum QueueRequests { |
112 | QUEUE_REQ_NONE = 0, |
113 | QUEUE_REQ_DELETE |
114 | } QueueRequests; |
115 | |
116 | typedef enum ThreadPoolRequests { |
117 | THREADPOOL_REQ_NONE = 0, |
118 | THREADPOOL_REQ_STOP |
119 | } ThreadPoolRequests; |
120 | |
121 | |
122 | /* |
123 | * Job structure. Jobs are enqueued on queues. |
124 | */ |
125 | |
126 | typedef struct Job { |
127 | struct Job *nextPtr; |
128 | char *server; |
129 | JobStates state; |
130 | int code; |
131 | JobTypes type; |
132 | JobRequests req; |
133 | char *errorCode; |
134 | char *errorInfo; |
135 | char *queueId; |
136 | Tcl_DString id; |
137 | Tcl_DString script; |
138 | Tcl_DString results; |
139 | Ns_Time startTime; |
140 | Ns_Time endTime; |
141 | } Job; |
142 | |
143 | /* |
144 | * <a href="/cvs/aolserver/aolserver/nsd/sockcallback.c#A_Queue">Queue</a> structure. A queue manages a set of jobs. |
145 | */ |
146 | |
147 | typedef struct JobQueue { |
148 | char *name; |
149 | char *desc; |
150 | Ns_Mutex lock; |
151 | Ns_Cond cond; |
152 | unsigned int nextid; |
153 | QueueRequests req; |
154 | int maxThreads; |
155 | int nRunning; |
156 | Tcl_HashTable jobs; |
157 | int refCount; |
158 | } JobQueue; |
159 | |
160 | /* |
161 | * Thread pool structure. ns_job mananges a global set of threads. |
162 | */ |
163 | |
164 | typedef struct ThreadPool { |
165 | Ns_Cond cond; |
166 | Ns_Mutex queuelock; |
167 | Tcl_HashTable queues; |
168 | ThreadPoolRequests req; |
169 | int nextThreadId; |
170 | unsigned long nextQueueId; |
171 | int maxThreads; |
172 | int nthreads; |
173 | int nidle; |
174 | Job *firstPtr; |
175 | } ThreadPool; |
176 | |
177 | /* |
178 | * Function prototypes/forward declarations. |
179 | */ |
180 | |
181 | static void <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_JobThread">JobThread</a>(void *arg); |
182 | static Job *<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NextJob">NextJob</a>(void); |
183 | static JobQueue *<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewQueue">NewQueue</a>(CONST char* queueName, CONST char* queueDesc, int maxThreads); |
184 | static void <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeQueue">FreeQueue</a>(JobQueue *queuePtr); |
185 | static Job* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewJob">NewJob</a>(CONST char* server, CONST char* queueName, int type, Tcl_Obj *script); |
186 | static void <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a>(Job *jobPtr); |
187 | static int LookupQueue(Tcl_Interp *interp, |
188 | CONST char *queue_name, |
189 | JobQueue **queuePtr, |
190 | int locked); |
191 | static int <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(JobQueue *queuePtr, int locked); |
192 | static int <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AnyDone">AnyDone</a>(JobQueue *queue); |
193 | static CONST char* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobCodeStr">GetJobCodeStr</a>(int code); |
194 | static CONST char* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobStateStr">GetJobStateStr</a>(JobStates state); |
195 | static CONST char* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobTypeStr">GetJobTypeStr</a>(JobTypes type); |
196 | static CONST char* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobReqStr">GetJobReqStr</a>(JobRequests req); |
197 | static CONST char* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetQueueReqStr">GetQueueReqStr</a>(QueueRequests req); |
198 | static CONST char* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetTpReqStr">GetTpReqStr</a>(ThreadPoolRequests req); |
199 | |
200 | static int <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(Tcl_Interp *interp, |
201 | Tcl_Obj *list, |
202 | CONST char *name, |
203 | CONST char *value); |
204 | |
205 | static int <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldInt">AppendFieldInt</a>(Tcl_Interp *interp, |
206 | Tcl_Obj *list, |
207 | CONST char *name, |
208 | int value); |
209 | |
210 | static int <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldLong">AppendFieldLong</a>(Tcl_Interp *interp, |
211 | Tcl_Obj *list, |
212 | CONST char *name, |
213 | long value); |
214 | |
215 | |
216 | static int <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldDouble">AppendFieldDouble</a>(Tcl_Interp *interp, |
217 | Tcl_Obj *list, |
218 | CONST char *name, |
219 | double value); |
220 | |
221 | static double ComputeDelta(Ns_Time *start, Ns_Time *end); |
222 | |
223 | /* |
224 | * Globals |
225 | */ |
226 | |
227 | static ThreadPool tp; |
228 | |
229 | |
230 | /* |
231 | *---------------------------------------------------------------------- |
232 | * |
233 | * NsInitTclQueueType -- |
234 | * |
235 | * Initialize the Tcl job queue. |
236 | * |
237 | * Results: |
238 | * None. |
239 | * |
240 | * Side effects: |
241 | * None. |
242 | * |
243 | *---------------------------------------------------------------------- |
244 | */ |
245 | |
246 | void |
247 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NsTclInitQueueType">NsTclInitQueueType</a>(void) |
248 | { |
249 | Tcl_InitHashTable(&tp.queues, TCL_STRING_KEYS); |
250 | Ns_MutexSetName(&tp.queuelock, "nsd:tcljobs"); |
251 | tp.nextThreadId = 0; |
252 | tp.nextQueueId = 0; |
253 | tp.maxThreads = 0; |
254 | tp.nthreads = 0; |
255 | tp.nidle = 0; |
256 | tp.firstPtr = NULL; |
257 | tp.req = THREADPOOL_REQ_NONE; |
258 | } |
259 | |
260 | |
261 | /* |
262 | *---------------------------------------------------------------------- |
263 | * |
264 | * <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NsStartJobsShutdown">NsStartJobsShutdown</a> -- |
265 | * |
266 | * Signal stop of the Tcl job threads. |
267 | * |
268 | * Results: |
269 | * None. |
270 | * |
271 | * Side effects: |
272 | * All pending jobs are cancelled and waiting threads interrupted. |
273 | * |
274 | *---------------------------------------------------------------------- |
275 | */ |
276 | |
277 | void |
278 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NsStartJobsShutdown">NsStartJobsShutdown</a>(void) |
279 | { |
280 | Tcl_HashSearch search; |
281 | Tcl_HashEntry *hPtr; |
282 | |
283 | hPtr = Tcl_FirstHashEntry(&tp.queues, &search); |
284 | while (hPtr != NULL) { |
285 | Ns_MutexLock(&tp.queuelock); |
286 | tp.req = THREADPOOL_REQ_STOP; |
287 | Ns_CondBroadcast(&tp.cond); |
288 | Ns_MutexUnlock(&tp.queuelock); |
289 | hPtr = Tcl_NextHashEntry(&search); |
290 | } |
291 | } |
292 | |
293 | |
294 | /* |
295 | *---------------------------------------------------------------------- |
296 | * |
297 | * <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NsWaitJobsShutdown">NsWaitJobsShutdown</a> -- |
298 | * |
299 | * Wait for Tcl job threads to exit. |
300 | * |
301 | * Results: |
302 | * None. |
303 | * |
304 | * Side effects: |
305 | * None. |
306 | * |
307 | *---------------------------------------------------------------------- |
308 | */ |
309 | |
310 | void |
311 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NsWaitJobsShutdown">NsWaitJobsShutdown</a>(Ns_Time *toPtr) |
312 | { |
313 | Tcl_HashSearch search; |
314 | Tcl_HashEntry *hPtr; |
315 | int status = NS_OK; |
316 | |
317 | hPtr = Tcl_FirstHashEntry(&tp.queues, &search); |
318 | while (status == NS_OK && hPtr != NULL) { |
319 | Ns_MutexLock(&tp.queuelock); |
320 | while (status == NS_OK && tp.nthreads > 0) { |
321 | status = Ns_CondTimedWait(&tp.cond, &tp.queuelock, toPtr); |
322 | } |
323 | Ns_MutexUnlock(&tp.queuelock); |
324 | hPtr = Tcl_NextHashEntry(&search); |
325 | } |
326 | if (status != NS_OK) { |
327 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Warning, "tcljobs: timeout waiting for exit"); |
328 | } |
329 | } |
330 | |
331 | |
332 | /* |
333 | *---------------------------------------------------------------------- |
334 | * |
335 | * NsTclJobCmd -- |
336 | * |
337 | * Implement the ns_job command to manage background tasks. |
338 | * |
339 | * Results: |
340 | * Standard Tcl result. |
341 | * |
342 | * Side effects: |
343 | * Jobs may be queued to run in another thread. |
344 | * |
345 | *---------------------------------------------------------------------- |
346 | */ |
347 | |
348 | int |
349 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NsTclJobObjCmd">NsTclJobObjCmd</a>(ClientData arg, Tcl_Interp *interp, int objc, Tcl_Obj **objv) |
350 | { |
351 | NsInterp *itPtr = arg; |
352 | JobQueue *queuePtr = NULL; |
353 | Job *jobPtr = NULL, **nextPtrPtr; |
354 | int code, new, create = 0, max; |
355 | char *jobId = NULL, buf[100], *queueId; |
356 | Tcl_HashEntry *hPtr, *jPtr; |
357 | Tcl_HashSearch search; |
358 | int argIndex; |
359 | |
360 | static CONST char *opts[] = { |
361 | "cancel", "create", "delete", "genid", "jobs", "joblist", |
362 | "threadlist", "queue", "queues", "queuelist", "wait", |
363 | "waitany", NULL |
364 | }; |
365 | |
366 | enum { |
367 | JCancelIdx, JCreateIdx, JDeleteIdx, JGenIDIdx, JJobsIdx, JJobsListIdx, |
368 | JThreadListIdx, JQueueIdx, JQueuesIdx, JQueueListIdx, JWaitIdx, JWaitAnyIdx |
369 | } _nsmayalias opt; |
370 | |
371 | if (objc < 2) { |
372 | Tcl_WrongNumArgs(interp, 1, objv, "option ?arg?"); |
373 | return TCL_ERROR; |
374 | } |
375 | if (Tcl_GetIndexFromObj(interp, objv[1], opts, "option", 0, |
376 | (int *) &opt) != TCL_OK) { |
377 | return TCL_ERROR; |
378 | } |
379 | |
380 | code = TCL_OK; |
381 | switch (opt) { |
382 | case JCreateIdx: |
383 | { |
384 | /* |
385 | * ns_job create |
386 | * |
387 | * Create a new thread pool queue. |
388 | */ |
389 | Tcl_Obj *queueIdObj = NULL; |
390 | char *queueDesc = ""; |
391 | |
392 | argIndex = 2; |
393 | if ((objc < 3) || (objc > 6)) { |
394 | Tcl_WrongNumArgs(interp, 2, objv, |
395 | "?-desc description? queueId ?maxThreads?"); |
396 | return TCL_ERROR; |
397 | } |
398 | if (objc > 3) { |
399 | if (strncmp(Tcl_GetString(objv[argIndex]), "-desc", strlen("-desc")) == 0) { |
400 | ++argIndex; |
401 | queueDesc = Tcl_GetString(objv[argIndex++]); |
402 | } |
403 | } |
404 | |
405 | queueIdObj = objv[argIndex++]; |
406 | queueId = Tcl_GetString(queueIdObj); |
407 | |
408 | max = NS_JOB_DEFAULT_MAXTHREADS; |
409 | if ((objc > argIndex) && |
410 | Tcl_GetIntFromObj(interp, objv[argIndex++], &max) != TCL_OK) { |
411 | return TCL_ERROR; |
412 | } |
413 | |
414 | Ns_MutexLock(&tp.queuelock); |
415 | hPtr = Tcl_CreateHashEntry(&tp.queues, Tcl_GetString(queueIdObj), &new); |
416 | if (new) { |
417 | queuePtr = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewQueue">NewQueue</a>(Tcl_GetHashKey(&tp.queues, hPtr),queueDesc, max); |
418 | Tcl_SetHashValue(hPtr, queuePtr); |
419 | } |
420 | Ns_MutexUnlock(&tp.queuelock); |
421 | if (!new) { |
422 | Tcl_AppendResult(interp, "queue already exists: ", queueId, NULL); |
423 | return TCL_ERROR; |
424 | } |
425 | Tcl_SetObjResult(interp, queueIdObj); |
426 | } |
427 | break; |
428 | case JDeleteIdx: |
429 | { |
430 | /* |
431 | * ns_job delete |
432 | * |
433 | * Request that the specified queue be deleted. The queue will |
434 | * only be deleted when all jobs are removed. |
435 | */ |
436 | if (objc != 3) { |
437 | Tcl_WrongNumArgs(interp, 2, objv, "queueId"); |
438 | return TCL_ERROR; |
439 | } |
440 | |
441 | if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) { |
442 | return TCL_ERROR; |
443 | } |
444 | queuePtr->req = QUEUE_REQ_DELETE; |
445 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
446 | |
447 | Ns_CondBroadcast(&tp.cond); |
448 | Tcl_SetResult(interp, "", TCL_STATIC); |
449 | } |
450 | break; |
451 | case JQueueIdx: |
452 | { |
453 | /* |
454 | * ns_job queue |
455 | * |
456 | * Add a new job the specified queue. |
457 | */ |
458 | int job_type = JOB_NON_DETACHED; |
459 | |
460 | argIndex = 2; |
461 | if ((objc != 4) && (objc != 5)) { |
462 | Tcl_WrongNumArgs(interp, 2, objv, "?-detached? queueId script"); |
463 | return TCL_ERROR; |
464 | } |
465 | if (objc > 4) { |
466 | if (strcmp(Tcl_GetString(objv[argIndex++]), "-detached") == 0) { |
467 | job_type = JOB_DETACHED; |
468 | } else { |
469 | Tcl_WrongNumArgs(interp, 2, objv, "?-detached? queueId script"); |
470 | return TCL_ERROR; |
471 | } |
472 | } |
473 | |
474 | Ns_MutexLock(&tp.queuelock); |
475 | if (LookupQueue(interp, Tcl_GetString(objv[argIndex++]), |
476 | &queuePtr, 1) != TCL_OK) { |
477 | Ns_MutexUnlock(&tp.queuelock); |
478 | return TCL_ERROR; |
479 | } |
480 | |
481 | /* |
482 | * Create a new job and add to the Thread Pool's list of jobs. |
483 | */ |
484 | jobPtr = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewJob">NewJob</a>(itPtr->servPtr->server, |
485 | queuePtr->name, |
486 | job_type, |
487 | objv[argIndex++]); |
488 | Ns_GetTime(&jobPtr->startTime); |
489 | |
490 | |
491 | if ((tp.req == THREADPOOL_REQ_STOP) || |
492 | (queuePtr->req == QUEUE_REQ_DELETE)) |
493 | { |
494 | Tcl_AppendResult(interp, |
495 | "The specified queue is being deleted or " |
496 | "the system is stopping.", NULL); |
497 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a>(jobPtr); |
498 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 1); |
499 | Ns_MutexUnlock(&tp.queuelock); |
500 | return TCL_ERROR; |
501 | } |
502 | |
503 | /* |
504 | * Add the job to the thread pool's job list. |
505 | */ |
506 | nextPtrPtr = &tp.firstPtr; |
507 | while (*nextPtrPtr != NULL) { |
508 | nextPtrPtr = &((*nextPtrPtr)->nextPtr); |
509 | } |
510 | *nextPtrPtr = jobPtr; |
511 | |
512 | /* |
513 | * Start a new thread if there are less than maxThreads currently |
514 | * running and there currently no idle threads. |
515 | */ |
516 | if (tp.nidle == 0 && tp.nthreads < tp.maxThreads) { |
517 | create = 1; |
518 | ++tp.nthreads; |
519 | } else { |
520 | create = 0; |
521 | } |
522 | |
523 | /* |
524 | * Add the job to queue. |
525 | */ |
526 | jobId = buf; |
527 | do { |
528 | sprintf(jobId, "job%d", queuePtr->nextid++); |
529 | hPtr = Tcl_CreateHashEntry(&queuePtr->jobs, jobId, &new); |
530 | } while (!new); |
531 | |
532 | Tcl_DStringAppend(&jobPtr->id, jobId, -1); |
533 | Tcl_SetHashValue(hPtr, jobPtr); |
534 | Ns_CondBroadcast(&tp.cond); |
535 | |
536 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 1); |
537 | Ns_MutexUnlock(&tp.queuelock); |
538 | |
539 | if (create) { |
540 | Ns_ThreadCreate(<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_JobThread">JobThread</a>, 0, 0, NULL); |
541 | } |
542 | |
543 | Tcl_SetResult(interp, jobId, TCL_VOLATILE); |
544 | } |
545 | break; |
546 | case JWaitIdx: |
547 | { |
548 | /* |
549 | * ns_job wait |
550 | * |
551 | * Wait for the specified job. |
552 | */ |
553 | int timeoutFlag = 0; |
554 | Ns_Time timeout; |
555 | int timedOut = 0; |
556 | Ns_Time delta_timeout; |
557 | |
558 | argIndex = 2; |
559 | if ((objc != 4) && (objc != 6)) { |
560 | Tcl_WrongNumArgs(interp, 2, objv, |
561 | "?-timeout seconds:microseconds? queueId jobId"); |
562 | return TCL_ERROR; |
563 | } |
564 | if (objc > 4) { |
565 | if (strcmp(Tcl_GetString(objv[argIndex++]), "-timeout") == 0) { |
566 | timeoutFlag = 1; |
567 | if (<a href="/cvs/aolserver/aolserver/nsd/tclobj.c#A_Ns_TclGetTimeFromObj">Ns_TclGetTimeFromObj</a>(interp, objv[argIndex++], |
568 | &delta_timeout) != TCL_OK) { |
569 | return TCL_ERROR; |
570 | } |
571 | |
572 | /* |
573 | * Set the timeout time. This is an absolute time. |
574 | */ |
575 | Ns_GetTime(&timeout); |
576 | Ns_IncrTime(&timeout, delta_timeout.sec, delta_timeout.usec); |
577 | } |
578 | } |
579 | |
580 | if (LookupQueue(interp, Tcl_GetString(objv[argIndex++]), |
581 | &queuePtr, 0) != TCL_OK) { |
582 | return TCL_ERROR; |
583 | } |
584 | jobId = Tcl_GetString(objv[argIndex++]); |
585 | |
586 | hPtr = Tcl_FindHashEntry(&queuePtr->jobs, jobId); |
587 | if (hPtr == NULL) { |
588 | |
589 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
590 | Tcl_AppendResult(interp, "no such job: ", jobId, NULL); |
591 | return TCL_ERROR; |
592 | } |
593 | |
594 | jobPtr = Tcl_GetHashValue(hPtr); |
595 | |
596 | if ((jobPtr->type == JOB_DETACHED) || |
597 | (jobPtr->req == JOB_CANCEL) || |
598 | (jobPtr->req == JOB_WAIT)) { |
599 | Tcl_AppendResult(interp, "cannot wait on job: ", |
600 | Tcl_DStringValue(&jobPtr->id), NULL); |
601 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
602 | return TCL_ERROR; |
603 | } |
604 | |
605 | jobPtr->req = JOB_WAIT; |
606 | |
607 | if (timeoutFlag) { |
608 | while (jobPtr->state != JOB_DONE) { |
609 | timedOut = Ns_CondTimedWait(&queuePtr->cond, |
610 | &queuePtr->lock, &timeout); |
611 | if (timedOut == NS_TIMEOUT) { |
612 | Tcl_SetResult(interp, "Wait timed out.", TCL_STATIC); |
613 | jobPtr->req = JOB_NONE; |
614 | |
615 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
616 | |
617 | return TCL_ERROR; |
618 | } |
619 | } |
620 | } else { |
621 | while (jobPtr->state != JOB_DONE) { |
622 | Ns_CondWait(&queuePtr->cond, &queuePtr->lock); |
623 | } |
624 | } |
625 | |
626 | /* |
627 | * At this point the job we were waiting on has completed, so we return |
628 | * the job's results and errorcodes, then clean up the job. |
629 | */ |
630 | |
631 | /* |
632 | * The following is a sanity check that ensures no other |
633 | * process removed this job's entry. |
634 | */ |
635 | if (((hPtr = Tcl_FindHashEntry(&queuePtr->jobs, jobId)) == NULL) || |
636 | (jobPtr == Tcl_GetHashValue(hPtr))) { |
637 | Tcl_SetResult(interp, "Internal ns_job error.", TCL_STATIC); |
638 | } |
639 | |
640 | Tcl_DeleteHashEntry(hPtr); |
641 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
642 | |
643 | Tcl_DStringResult(interp, &jobPtr->results); |
644 | if (jobPtr->errorCode != NULL) { |
645 | Tcl_SetVar(interp, "errorCode", jobPtr->errorCode, TCL_GLOBAL_ONLY); |
646 | } |
647 | if (jobPtr->errorInfo != NULL) { |
648 | Tcl_SetVar(interp, "errorInfo", jobPtr->errorInfo, TCL_GLOBAL_ONLY); |
649 | } |
650 | code = jobPtr->code; |
651 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a>(jobPtr); |
652 | } |
653 | break; |
654 | case JCancelIdx: |
655 | { |
656 | /* |
657 | * ns_job cancel |
658 | * |
659 | * Cancel the specified job. |
660 | */ |
661 | if (objc != 4) { |
662 | Tcl_WrongNumArgs(interp, 2, objv, "queueId jobId"); |
663 | return TCL_ERROR; |
664 | } |
665 | if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) { |
666 | return TCL_ERROR; |
667 | } |
668 | jobId = Tcl_GetString(objv[3]); |
669 | jPtr = Tcl_FindHashEntry(&queuePtr->jobs, jobId); |
670 | if (jPtr == NULL) { |
671 | |
672 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
673 | Tcl_AppendResult(interp, "no such job: ", jobId, NULL); |
674 | return TCL_ERROR; |
675 | } |
676 | |
677 | jobPtr = Tcl_GetHashValue(jPtr); |
678 | |
679 | if (jobPtr->req == JOB_WAIT) { |
680 | Tcl_AppendResult(interp, |
681 | "Can not cancel this job because someone" |
682 | " is waiting on it. Job ID: ", |
683 | Tcl_DStringValue(&jobPtr->id), NULL); |
684 | |
685 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
686 | |
687 | return TCL_ERROR; |
688 | } |
689 | |
690 | jobPtr->req = JOB_CANCEL; |
691 | |
692 | if (jobPtr->state == JOB_DONE) { |
693 | Tcl_DeleteHashEntry(jPtr); |
694 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a>(jobPtr); |
695 | } |
696 | |
697 | Ns_CondBroadcast(&queuePtr->cond); |
698 | |
699 | Ns_CondBroadcast(&tp.cond); |
700 | |
701 | Tcl_SetBooleanObj(Tcl_GetObjResult(interp), (jobPtr->state == JOB_RUNNING)); |
702 | |
703 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
704 | } |
705 | break; |
706 | case JWaitAnyIdx: |
707 | { |
708 | /* |
709 | * ns_job waitany |
710 | * |
711 | * Wait for any job on the queue complete. |
712 | */ |
713 | int timeoutFlag = 0; |
714 | Ns_Time timeout; |
715 | int timedOut = 0; |
716 | Ns_Time delta_timeout; |
717 | |
718 | argIndex = 2; |
719 | if ((objc != 3) && (objc != 5)) { |
720 | Tcl_WrongNumArgs(interp, 2, objv, |
721 | "?-timeout seconds:microseconds? queueId"); |
722 | return TCL_ERROR; |
723 | } |
724 | if (objc > 3) { |
725 | if (strcmp(Tcl_GetString(objv[argIndex++]), "-timeout") == 0) { |
726 | timeoutFlag = 1; |
727 | if (<a href="/cvs/aolserver/aolserver/nsd/tclobj.c#A_Ns_TclGetTimeFromObj">Ns_TclGetTimeFromObj</a>(interp, objv[argIndex++], |
728 | &delta_timeout) != TCL_OK) { |
729 | return TCL_ERROR; |
730 | } |
731 | /* |
732 | * Set the timeout time. This is an absolute time. |
733 | */ |
734 | Ns_GetTime(&timeout); |
735 | Ns_IncrTime(&timeout, delta_timeout.sec, delta_timeout.usec); |
736 | } |
737 | } |
738 | |
739 | if (LookupQueue(interp, Tcl_GetString(objv[argIndex++]), |
740 | &queuePtr, 0) != TCL_OK) { |
741 | return TCL_ERROR; |
742 | } |
743 | |
744 | /* |
745 | * While there are jobs in queue or no jobs are "done", wait |
746 | * on the queue condition variable. |
747 | */ |
748 | if (timeoutFlag) { |
749 | while ((Tcl_FirstHashEntry(&queuePtr->jobs, &search) != NULL) && |
750 | (!<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AnyDone">AnyDone</a>(queuePtr))) { |
751 | |
752 | timedOut = Ns_CondTimedWait(&queuePtr->cond, |
753 | &queuePtr->lock, &timeout); |
754 | if (timedOut == NS_TIMEOUT) { |
755 | Tcl_SetResult(interp, "Wait timed out.", TCL_STATIC); |
756 | |
757 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
758 | return TCL_ERROR; |
759 | } |
760 | } |
761 | } else { |
762 | while ((Tcl_FirstHashEntry(&queuePtr->jobs, &search) != NULL) && |
763 | (!<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AnyDone">AnyDone</a>(queuePtr))) { |
764 | Ns_CondWait(&queuePtr->cond, &queuePtr->lock); |
765 | } |
766 | } |
767 | |
768 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
769 | Tcl_SetResult(interp, "", TCL_STATIC); |
770 | } |
771 | break; |
772 | case JJobsIdx: |
773 | { |
774 | /* |
775 | * ns_job jobs |
776 | * |
777 | * Returns a list of job IDs in arbitrary order. |
778 | */ |
779 | if (objc != 3) { |
780 | Tcl_WrongNumArgs(interp, 2, objv, "queueId"); |
781 | return TCL_ERROR; |
782 | } |
783 | if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) { |
784 | return TCL_ERROR; |
785 | } |
786 | hPtr = Tcl_FirstHashEntry(&queuePtr->jobs, &search); |
787 | while (hPtr != NULL) { |
788 | jobId = Tcl_GetHashKey(&queuePtr->jobs, hPtr); |
789 | Tcl_AppendElement(interp, jobId); |
790 | hPtr = Tcl_NextHashEntry(&search); |
791 | } |
792 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
793 | } |
794 | break; |
795 | case JQueuesIdx: |
796 | { |
797 | /* |
798 | * ns_job queues |
799 | * |
800 | * Returns a list of the current queues. |
801 | */ |
802 | Ns_MutexLock(&tp.queuelock); |
803 | hPtr = Tcl_FirstHashEntry(&tp.queues, &search); |
804 | while (hPtr != NULL) { |
805 | queuePtr = Tcl_GetHashValue(hPtr); |
806 | Tcl_AppendElement(interp, queuePtr->name); |
807 | hPtr = Tcl_NextHashEntry(&search); |
808 | } |
809 | Ns_MutexUnlock(&tp.queuelock); |
810 | } |
811 | break; |
812 | case JJobsListIdx: |
813 | { |
814 | /* |
815 | * ns_job joblist |
816 | * |
817 | * Returns a list of all the jobs in the queue. The "job" consists of: |
818 | * |
819 | * Job ID |
820 | * Job State (Scheduled, Running, or Done) |
821 | * Job Results (or job script, if job has not yet completed). |
822 | * Job Code (TCL_OK, TCL_ERROR, TCL_RETURN, TCL_BREAK, TCL_CONTINE) |
823 | * Job Running Time (TBD) |
824 | */ |
825 | |
826 | Tcl_Obj *jobList, *jobFieldList; |
827 | char *jobId, *jobState, *jobCode, *jobType; |
828 | char *jobResults, *jobScript, *jobReq; |
829 | double delta; |
830 | |
831 | if (objc != 3) { |
832 | Tcl_WrongNumArgs(interp, 2, objv, "queueId"); |
833 | return TCL_ERROR; |
834 | } |
835 | if (LookupQueue(interp, Tcl_GetString(objv[2]), &queuePtr, 0) != TCL_OK) { |
836 | return TCL_ERROR; |
837 | } |
838 | |
839 | /* Create a Tcl List to hold the list of jobs. */ |
840 | jobList = Tcl_NewListObj(0, NULL); |
841 | |
842 | hPtr = Tcl_FirstHashEntry(&queuePtr->jobs, &search); |
843 | while (hPtr != NULL) { |
844 | |
845 | jobPtr = Tcl_GetHashValue(hPtr); |
846 | |
847 | jobId = Tcl_GetHashKey(&queuePtr->jobs, hPtr); |
848 | jobCode = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobCodeStr">GetJobCodeStr</a>(jobPtr->code); |
849 | jobState = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobStateStr">GetJobStateStr</a>(jobPtr->state); |
850 | jobType = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobTypeStr">GetJobTypeStr</a>(jobPtr->type); |
851 | jobReq = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobReqStr">GetJobReqStr</a>(jobPtr->req); |
852 | jobResults = Tcl_DStringValue(&jobPtr->results); |
853 | jobScript = Tcl_DStringValue(&jobPtr->script); |
854 | |
855 | if ((jobPtr->state == JOB_SCHEDULED) || |
856 | (jobPtr->state == JOB_RUNNING)) { |
857 | Ns_GetTime(&jobPtr->endTime); |
858 | } |
859 | delta = ComputeDelta(&jobPtr->startTime, &jobPtr->endTime); |
860 | |
861 | /* Create a Tcl List to hold the list of job fields. */ |
862 | jobFieldList = Tcl_NewListObj(0, NULL); |
863 | |
864 | /* Add Job ID */ |
865 | if ((<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, jobFieldList, |
866 | "id", jobId) != TCL_OK) || |
867 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, jobFieldList, |
868 | "state", jobState) != TCL_OK) || |
869 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, jobFieldList, |
870 | "results", jobResults) != TCL_OK) || |
871 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, jobFieldList, |
872 | "script", jobScript) != TCL_OK) || |
873 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, jobFieldList, |
874 | "code", jobCode) != TCL_OK) || |
875 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, jobFieldList, |
876 | "type", jobType) != TCL_OK) || |
877 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, jobFieldList, |
878 | "req", jobReq) != TCL_OK) || |
879 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldDouble">AppendFieldDouble</a>(interp, jobFieldList, |
880 | "time", delta) != TCL_OK) || |
881 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldLong">AppendFieldLong</a>(interp, |
882 | jobFieldList, |
883 | "starttime", |
884 | jobPtr->startTime.sec) != TCL_OK) || |
885 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldLong">AppendFieldLong</a>(interp, |
886 | jobFieldList, |
887 | "endtime", |
888 | jobPtr->endTime.sec) != TCL_OK)) |
889 | { |
890 | /* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a> sets results if an error occurs. */ |
891 | Tcl_DecrRefCount(jobList); |
892 | Tcl_DecrRefCount(jobFieldList); |
893 | Ns_MutexUnlock(&queuePtr->lock); |
894 | return TCL_ERROR; |
895 | } |
896 | |
897 | /* Add the job to the job list */ |
898 | if (Tcl_ListObjAppendElement(interp, jobList, jobFieldList) != TCL_OK) { |
899 | Tcl_DecrRefCount(jobList); |
900 | Tcl_DecrRefCount(jobFieldList); |
901 | |
902 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
903 | return TCL_ERROR; |
904 | } |
905 | |
906 | hPtr = Tcl_NextHashEntry(&search); |
907 | } |
908 | Tcl_SetObjResult(interp, jobList); |
909 | |
910 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 0); |
911 | } |
912 | break; |
913 | case JQueueListIdx: |
914 | { |
915 | /* |
916 | * ns_job queuelist |
917 | * |
918 | * Returns a list of all the queues and the queue information. |
919 | */ |
920 | Tcl_Obj *queueList, *queueFieldList; |
921 | char *queueReq; |
922 | |
923 | /* Create a Tcl List to hold the list of jobs. */ |
924 | queueList = Tcl_NewListObj(0, NULL); |
925 | |
926 | Ns_MutexLock(&tp.queuelock); |
927 | hPtr = Tcl_FirstHashEntry(&tp.queues, &search); |
928 | while (hPtr != NULL) { |
929 | |
930 | queuePtr = Tcl_GetHashValue(hPtr); |
931 | |
932 | /* Create a Tcl List to hold the list of queue fields. */ |
933 | queueFieldList = Tcl_NewListObj(0, NULL); |
934 | |
935 | queueReq = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetQueueReqStr">GetQueueReqStr</a>(queuePtr->req); |
936 | |
937 | /* Add queue name */ |
938 | if ((<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, queueFieldList, |
939 | "name", queuePtr->name) != TCL_OK) || |
940 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, queueFieldList, |
941 | "desc", queuePtr->desc) != TCL_OK) || |
942 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldInt">AppendFieldInt</a>(interp, queueFieldList, |
943 | "maxthreads", queuePtr->maxThreads) != TCL_OK) || |
944 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldInt">AppendFieldInt</a>(interp, queueFieldList, |
945 | "numrunning", queuePtr->nRunning) != TCL_OK) || |
946 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, queueFieldList, |
947 | "req", queueReq) != TCL_OK)) |
948 | { |
949 | /* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a> sets results if an error occurs. */ |
950 | Tcl_DecrRefCount(queueList); |
951 | Tcl_DecrRefCount(queueFieldList); |
952 | Ns_MutexUnlock(&tp.queuelock); |
953 | return TCL_ERROR; |
954 | } |
955 | |
956 | /* Add the job to the job list */ |
957 | if (Tcl_ListObjAppendElement(interp, queueList, |
958 | queueFieldList) != TCL_OK) { |
959 | Tcl_DecrRefCount(queueList); |
960 | Tcl_DecrRefCount(queueFieldList); |
961 | Ns_MutexUnlock(&tp.queuelock); |
962 | return TCL_ERROR; |
963 | } |
964 | |
965 | hPtr = Tcl_NextHashEntry(&search); |
966 | } |
967 | Tcl_SetObjResult(interp, queueList); |
968 | Ns_MutexUnlock(&tp.queuelock); |
969 | } |
970 | break; |
971 | case JGenIDIdx: |
972 | { |
973 | /* |
974 | * ns_job genID |
975 | * |
976 | * Generate a unique queue name. |
977 | */ |
978 | Ns_Time currentTime; |
979 | Ns_GetTime(¤tTime); |
980 | snprintf(buf, 100, "queue_id_%x_%x", tp.nextQueueId++, currentTime.sec); |
981 | Tcl_SetResult(interp, buf, TCL_VOLATILE); |
982 | } |
983 | break; |
984 | case JThreadListIdx: |
985 | { |
986 | /* |
987 | * ns_job threadlist |
988 | * |
989 | * Return a list of the thread pool's fields. |
990 | * |
991 | */ |
992 | |
993 | Tcl_Obj *tpFieldList; |
994 | char *tpReq; |
995 | |
996 | /* Create a Tcl List to hold the list of thread fields. */ |
997 | tpFieldList = Tcl_NewListObj(0, NULL); |
998 | |
999 | tpReq = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetTpReqStr">GetTpReqStr</a>(tp.req); |
1000 | |
1001 | Ns_MutexLock(&tp.queuelock); |
1002 | |
1003 | /* Add queue name */ |
1004 | if ((<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldInt">AppendFieldInt</a>(interp, tpFieldList, |
1005 | "maxthreads", tp.maxThreads) != TCL_OK) || |
1006 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldInt">AppendFieldInt</a>(interp, tpFieldList, |
1007 | "numthreads", tp.nthreads) != TCL_OK) || |
1008 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldInt">AppendFieldInt</a>(interp, tpFieldList, |
1009 | "numidle", tp.nidle) != TCL_OK) || |
1010 | (<a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(interp, tpFieldList, |
1011 | "req", tpReq) != TCL_OK)) |
1012 | |
1013 | { |
1014 | /* <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a> sets results if an error occurs. */ |
1015 | Tcl_DecrRefCount(tpFieldList); |
1016 | Ns_MutexUnlock(&tp.queuelock); |
1017 | return TCL_ERROR; |
1018 | } |
1019 | Ns_MutexUnlock(&tp.queuelock); |
1020 | Tcl_SetObjResult(interp, tpFieldList); |
1021 | } |
1022 | break; |
1023 | } |
1024 | return code; |
1025 | } |
1026 | |
1027 | |
1028 | /* |
1029 | *---------------------------------------------------------------------- |
1030 | * |
1031 | * <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_JobThread">JobThread</a> -- |
1032 | * |
1033 | * Background thread for the ns_job command. |
1034 | * |
1035 | * Results: |
1036 | * None. |
1037 | * |
1038 | * Side effects: |
1039 | * Jobs will be run from the queue. |
1040 | * |
1041 | *---------------------------------------------------------------------- |
1042 | */ |
1043 | |
1044 | static void |
1045 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_JobThread">JobThread</a>(void *arg) |
1046 | { |
1047 | Tcl_Interp *interp; |
1048 | Job *jobPtr; |
1049 | char buf[100]; |
1050 | CONST char *err; |
1051 | JobQueue *queuePtr; |
1052 | Tcl_HashEntry *jPtr; |
1053 | |
1054 | <a href="/cvs/aolserver/aolserver/nsd/nsmain.c#A_Ns_WaitForStartup">Ns_WaitForStartup</a>(); |
1055 | Ns_MutexLock(&tp.queuelock); |
1056 | snprintf(buf, 100, "-ns_job_%x-", tp.nextThreadId++); |
1057 | Ns_ThreadSetName(buf); |
1058 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "Starting thread: %s", buf); |
1059 | while (1) { |
1060 | ++tp.nidle; |
1061 | while (((jobPtr = <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NextJob">NextJob</a>()) == NULL) && |
1062 | !(tp.req == THREADPOOL_REQ_STOP)) { |
1063 | Ns_CondWait(&tp.cond, &tp.queuelock); |
1064 | } |
1065 | --tp.nidle; |
1066 | |
1067 | if (tp.req == THREADPOOL_REQ_STOP) { |
1068 | break; |
1069 | } |
1070 | |
1071 | /* |
1072 | * Run the job. |
1073 | */ |
1074 | Ns_MutexUnlock(&tp.queuelock); |
1075 | |
1076 | interp = <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclAllocateInterp">Ns_TclAllocateInterp</a>(jobPtr->server); |
1077 | Ns_GetTime(&jobPtr->endTime); |
1078 | Ns_GetTime(&jobPtr->startTime); |
1079 | jobPtr->code = Tcl_EvalEx(interp, jobPtr->script.string, -1, 0); |
1080 | |
1081 | /* |
1082 | * Save the results. |
1083 | */ |
1084 | Tcl_DStringAppend(&jobPtr->results, Tcl_GetStringResult(interp), -1); |
1085 | err = Tcl_GetVar(interp, "errorCode", TCL_GLOBAL_ONLY); |
1086 | if (err != NULL) { |
1087 | jobPtr->errorCode = ns_strdup(err); |
1088 | } |
1089 | err = Tcl_GetVar(interp, "errorInfo", TCL_GLOBAL_ONLY); |
1090 | if (err != NULL) { |
1091 | jobPtr->errorInfo = ns_strdup(err); |
1092 | } |
1093 | Ns_GetTime(&jobPtr->endTime); |
1094 | <a href="/cvs/aolserver/aolserver/nsd/tclinit.c#A_Ns_TclDeAllocateInterp">Ns_TclDeAllocateInterp</a>(interp); |
1095 | |
1096 | Ns_MutexLock(&tp.queuelock); |
1097 | |
1098 | LookupQueue(NULL, jobPtr->queueId, &queuePtr, 1); |
1099 | |
1100 | --(queuePtr->nRunning); |
1101 | jobPtr->state = JOB_DONE; |
1102 | |
1103 | /* |
1104 | * Clean any cancelled or detached jobs. |
1105 | */ |
1106 | if ((jobPtr->req == JOB_CANCEL) || (jobPtr->type == JOB_DETACHED)) { |
1107 | jPtr = Tcl_FindHashEntry(&queuePtr->jobs, Tcl_DStringValue(&jobPtr->id)); |
1108 | Tcl_DeleteHashEntry(jPtr); |
1109 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a>(jobPtr); |
1110 | } |
1111 | |
1112 | Ns_CondBroadcast(&queuePtr->cond); |
1113 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 1); |
1114 | } |
1115 | |
1116 | --tp.nthreads; |
1117 | |
1118 | Ns_CondBroadcast(&tp.cond); |
1119 | Ns_MutexUnlock(&tp.queuelock); |
1120 | |
1121 | <a href="/cvs/aolserver/aolserver/nsd/log.c#A_Ns_Log">Ns_Log</a>(Notice, "exiting"); |
1122 | } |
1123 | |
1124 | |
1125 | /* |
1126 | *---------------------------------------------------------------------- |
1127 | * Get the "next" job. |
1128 | * |
1129 | * Queues have a "maxThreads" so if the queue is already at |
1130 | * "maxThreads" jobs of that queue will be skipped. |
1131 | * |
1132 | * Note: the "queuelock" should be locked when calling this function. |
1133 | * |
1134 | * Results: |
1135 | * |
1136 | * Side effects: |
1137 | * |
1138 | *---------------------------------------------------------------------- |
1139 | */ |
1140 | |
1141 | static Job * |
1142 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NextJob">NextJob</a>(void) |
1143 | { |
1144 | JobQueue *queuePtr; |
1145 | Tcl_HashEntry *jPtr; |
1146 | Job *prev = NULL; |
1147 | Job *tmp = NULL; |
1148 | Job *jobPtr = NULL; |
1149 | int done = 0; |
1150 | |
1151 | jobPtr = tp.firstPtr; |
1152 | prev = tp.firstPtr; |
1153 | while ((!done) && (jobPtr != NULL)) { |
1154 | LookupQueue(NULL, jobPtr->queueId, &queuePtr, 1); |
1155 | |
1156 | /* |
1157 | * Check if the job is not cancel and |
1158 | */ |
1159 | |
1160 | if (jobPtr->req == JOB_CANCEL) { |
1161 | /* |
1162 | * Remove job from the list. |
1163 | */ |
1164 | tmp = jobPtr; |
1165 | if (jobPtr == tp.firstPtr) { |
1166 | tp.firstPtr = jobPtr->nextPtr; |
1167 | } else { |
1168 | prev->nextPtr = jobPtr->nextPtr; |
1169 | } |
1170 | jobPtr = jobPtr->nextPtr; |
1171 | |
1172 | /* |
1173 | * Remove cancelled job from the queue and free it. |
1174 | */ |
1175 | jPtr = Tcl_FindHashEntry(&queuePtr->jobs, Tcl_DStringValue(&tmp->id)); |
1176 | Tcl_DeleteHashEntry(jPtr); |
1177 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a>(tmp); |
1178 | } else if (queuePtr->nRunning < queuePtr->maxThreads) { |
1179 | /* |
1180 | * Remove job from the list. |
1181 | */ |
1182 | if (jobPtr == tp.firstPtr) { |
1183 | tp.firstPtr = jobPtr->nextPtr; |
1184 | } else { |
1185 | prev->nextPtr = jobPtr->nextPtr; |
1186 | } |
1187 | |
1188 | done = 1; |
1189 | jobPtr->state = JOB_RUNNING; |
1190 | ++(queuePtr->nRunning); |
1191 | } else { |
1192 | /* |
1193 | * Advance the list pointer. |
1194 | */ |
1195 | prev = jobPtr; |
1196 | jobPtr = jobPtr->nextPtr; |
1197 | } |
1198 | |
1199 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(queuePtr, 1); |
1200 | } |
1201 | |
1202 | return jobPtr; |
1203 | } |
1204 | |
1205 | |
1206 | /* |
1207 | *---------------------------------------------------------------------- |
1208 | * |
1209 | * <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewQueue">NewQueue</a> -- |
1210 | * |
1211 | * Create a thread pool queue. |
1212 | * |
1213 | * Results: |
1214 | * None. |
1215 | * |
1216 | * Side effects: |
1217 | * None. |
1218 | * |
1219 | *---------------------------------------------------------------------- |
1220 | */ |
1221 | |
1222 | static JobQueue * |
1223 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewQueue">NewQueue</a>(CONST char* queueName, CONST char* queueDesc, int maxThreads) |
1224 | { |
1225 | JobQueue *queuePtr = NULL; |
1226 | |
1227 | queuePtr = ns_calloc(1, sizeof(JobQueue)); |
1228 | queuePtr->req = QUEUE_REQ_NONE; |
1229 | |
1230 | queuePtr->name = ns_calloc(1, strlen(queueName) + 1); |
1231 | strcpy(queuePtr->name, queueName); |
1232 | |
1233 | queuePtr->desc = ns_calloc(1, strlen(queueDesc) + 1); |
1234 | strcpy(queuePtr->desc, queueDesc); |
1235 | queuePtr->maxThreads = maxThreads; |
1236 | |
1237 | queuePtr->refCount = 0; |
1238 | |
1239 | Ns_MutexSetName2(&queuePtr->lock, "tcljob", queueName); |
1240 | Tcl_InitHashTable(&queuePtr->jobs, TCL_STRING_KEYS); |
1241 | |
1242 | tp.maxThreads += maxThreads; |
1243 | |
1244 | return queuePtr; |
1245 | } |
1246 | |
1247 | |
1248 | /* |
1249 | *---------------------------------------------------------------------- |
1250 | * |
1251 | * <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeQueue">FreeQueue</a> -- |
1252 | * |
1253 | * Cleanup the |
1254 | * |
1255 | * Results: |
1256 | * None. |
1257 | * |
1258 | * Side effects: |
1259 | * None. |
1260 | * |
1261 | *---------------------------------------------------------------------- |
1262 | */ |
1263 | |
1264 | static void |
1265 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeQueue">FreeQueue</a>(JobQueue *queuePtr) |
1266 | { |
1267 | Ns_MutexDestroy(&queuePtr->lock); |
1268 | Tcl_DeleteHashTable(&queuePtr->jobs); |
1269 | ns_free(queuePtr->desc); |
1270 | ns_free(queuePtr->name); |
1271 | ns_free(queuePtr); |
1272 | } |
1273 | |
1274 | |
1275 | /* |
1276 | *---------------------------------------------------------------------- |
1277 | * |
1278 | * <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewJob">NewJob</a> -- |
1279 | * |
1280 | * Create a new job and initialize it. |
1281 | * |
1282 | * Results: |
1283 | * None. |
1284 | * |
1285 | * Side effects: |
1286 | * None. |
1287 | * |
1288 | *---------------------------------------------------------------------- |
1289 | */ |
1290 | |
1291 | static Job * |
1292 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_NewJob">NewJob</a>(CONST char* server, CONST char* queueId, int type, Tcl_Obj *script) |
1293 | { |
1294 | Job *jobPtr = NULL; |
1295 | |
1296 | jobPtr = ns_malloc(sizeof(Job)); |
1297 | jobPtr->nextPtr = NULL; |
1298 | jobPtr->server = server; |
1299 | jobPtr->state = JOB_SCHEDULED; |
1300 | jobPtr->code = TCL_OK; |
1301 | jobPtr->type = type; |
1302 | jobPtr->req = JOB_NONE; |
1303 | jobPtr->errorCode = jobPtr->errorInfo = NULL; |
1304 | |
1305 | jobPtr->queueId = ns_calloc(1, strlen(queueId) + 1); |
1306 | strcpy(jobPtr->queueId, queueId); |
1307 | |
1308 | Tcl_DStringInit(&jobPtr->id); |
1309 | Tcl_DStringInit(&jobPtr->script); |
1310 | Tcl_DStringAppend(&jobPtr->script, Tcl_GetString(script), -1); |
1311 | Tcl_DStringInit(&jobPtr->results); |
1312 | |
1313 | return jobPtr; |
1314 | } |
1315 | |
1316 | |
1317 | /* |
1318 | *---------------------------------------------------------------------- |
1319 | * |
1320 | * <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a> -- |
1321 | * |
1322 | * Destory a Job structure. |
1323 | * |
1324 | * Results: |
1325 | * None. |
1326 | * |
1327 | * Side effects: |
1328 | * None. |
1329 | * |
1330 | *---------------------------------------------------------------------- |
1331 | */ |
1332 | |
1333 | void |
1334 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeJob">FreeJob</a>(Job *jobPtr) |
1335 | { |
1336 | Tcl_DStringFree(&jobPtr->results); |
1337 | Tcl_DStringFree(&jobPtr->script); |
1338 | Tcl_DStringFree(&jobPtr->id); |
1339 | |
1340 | ns_free(jobPtr->queueId); |
1341 | |
1342 | if (jobPtr->errorCode) { |
1343 | ns_free(jobPtr->errorCode); |
1344 | } |
1345 | if (jobPtr->errorInfo) { |
1346 | ns_free(jobPtr->errorInfo); |
1347 | } |
1348 | ns_free(jobPtr); |
1349 | } |
1350 | |
1351 | |
1352 | /* |
1353 | *---------------------------------------------------------------------- |
1354 | * Find the specified queue and lock it if found. |
1355 | * |
1356 | * Specify "locked" true if the "queuelock" is already locked. |
1357 | * |
1358 | * PWM: With the new locking scheme refCount is not longer necessary. |
1359 | * However, if there is ever a case in the future where an unlocked |
1360 | * queue can be referenced then we will again need the refCount. |
1361 | * |
1362 | * Results: |
1363 | * |
1364 | * Side effects: |
1365 | * |
1366 | *---------------------------------------------------------------------- |
1367 | */ |
1368 | static int LookupQueue(Tcl_Interp *interp, |
1369 | CONST char *queueId, |
1370 | JobQueue **queuePtr, |
1371 | int locked) |
1372 | { |
1373 | Tcl_HashEntry *hPtr; |
1374 | |
1375 | if (!locked) |
1376 | Ns_MutexLock(&tp.queuelock); |
1377 | |
1378 | *queuePtr = NULL; |
1379 | |
1380 | hPtr = Tcl_FindHashEntry(&tp.queues, queueId); |
1381 | if (hPtr != NULL) { |
1382 | *queuePtr = Tcl_GetHashValue(hPtr); |
1383 | Ns_MutexLock(&(*queuePtr)->lock); |
1384 | ++((*queuePtr)->refCount); |
1385 | } |
1386 | |
1387 | if (!locked) |
1388 | Ns_MutexUnlock(&tp.queuelock); |
1389 | |
1390 | if (*queuePtr == NULL) { |
1391 | if (interp != NULL) { |
1392 | Tcl_AppendResult(interp, "no such queue: ", queueId, NULL); |
1393 | } |
1394 | return TCL_ERROR; |
1395 | } |
1396 | return TCL_OK; |
1397 | } |
1398 | |
1399 | |
1400 | /* |
1401 | *---------------------------------------------------------------------- |
1402 | * Release queue |
1403 | * |
1404 | * Specify "locked" true if the queuelock is already locked. |
1405 | * |
1406 | * Results: |
1407 | * |
1408 | * Side effects: |
1409 | * |
1410 | *---------------------------------------------------------------------- |
1411 | */ |
1412 | static int |
1413 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_ReleaseQueue">ReleaseQueue</a>(JobQueue *queuePtr, int locked) |
1414 | { |
1415 | Tcl_HashEntry *qPtr; |
1416 | Tcl_HashSearch search; |
1417 | int deleted = 0; |
1418 | |
1419 | --(queuePtr->refCount); |
1420 | |
1421 | /* |
1422 | * If user requested that the queue be deleted and |
1423 | * no other thread is referencing the queueu and |
1424 | * the queue is emtpy, then delete it. |
1425 | * |
1426 | */ |
1427 | if ((queuePtr->req == QUEUE_REQ_DELETE) && |
1428 | (queuePtr->refCount <= 0) && |
1429 | (Tcl_FirstHashEntry(&queuePtr->jobs, &search) == NULL)) { |
1430 | |
1431 | if (!locked) |
1432 | Ns_MutexLock(&tp.queuelock); |
1433 | |
1434 | /* |
1435 | * Remove the queue from the list. |
1436 | */ |
1437 | qPtr = Tcl_FindHashEntry(&tp.queues, queuePtr->name); |
1438 | if (qPtr != NULL) { |
1439 | Tcl_DeleteHashEntry(qPtr); |
1440 | tp.maxThreads -= queuePtr->maxThreads; |
1441 | deleted = 1; |
1442 | } |
1443 | |
1444 | Ns_MutexUnlock(&queuePtr->lock); |
1445 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_FreeQueue">FreeQueue</a>(queuePtr); |
1446 | |
1447 | if (!locked) |
1448 | Ns_MutexUnlock(&tp.queuelock); |
1449 | } else { |
1450 | Ns_MutexUnlock(&queuePtr->lock); |
1451 | } |
1452 | |
1453 | return deleted; |
1454 | } |
1455 | |
1456 | |
1457 | /* |
1458 | *---------------------------------------------------------------------- |
1459 | * Check if any jobs on the queue are "done". |
1460 | * |
1461 | * 1 (true) there is at least one job done. |
1462 | * 0 (false) there are no jobs done. |
1463 | * |
1464 | * Results: |
1465 | * |
1466 | * Side effects: |
1467 | * |
1468 | *---------------------------------------------------------------------- |
1469 | */ |
1470 | |
1471 | static int |
1472 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AnyDone">AnyDone</a>(JobQueue *queue) |
1473 | { |
1474 | Tcl_HashEntry *hPtr; |
1475 | Job *jobPtr; |
1476 | Tcl_HashSearch search; |
1477 | |
1478 | hPtr = Tcl_FirstHashEntry(&queue->jobs, &search); |
1479 | |
1480 | while (hPtr != NULL) { |
1481 | jobPtr = Tcl_GetHashValue(hPtr); |
1482 | if (jobPtr->state == JOB_DONE) { |
1483 | return 1; |
1484 | } |
1485 | hPtr = Tcl_NextHashEntry(&search); |
1486 | } |
1487 | return 0; |
1488 | } |
1489 | |
1490 | |
1491 | /* |
1492 | *---------------------------------------------------------------------- |
1493 | * Convert the job code into a string. |
1494 | * |
1495 | * Results: |
1496 | * |
1497 | * Side effects: |
1498 | * |
1499 | *---------------------------------------------------------------------- |
1500 | */ |
1501 | |
1502 | static CONST char* |
1503 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobCodeStr">GetJobCodeStr</a>(int code) |
1504 | { |
1505 | static CONST char *codeArr[] = { |
1506 | "TCL_OK", /* 0 */ |
1507 | "TCL_ERROR", /* 1 */ |
1508 | "TCL_RETURN", /* 2 */ |
1509 | "TCL_BREAK", /* 3 */ |
1510 | "TCL_CONTINUE", /* 4 */ |
1511 | "UNKNOWN_CODE" /* 5 */ |
1512 | }; |
1513 | static int max_code_index = 5; |
1514 | |
1515 | /* Check the caller's input. */ |
1516 | if (code > (max_code_index)) { |
1517 | code = max_code_index; |
1518 | } |
1519 | |
1520 | return codeArr[code]; |
1521 | } |
1522 | |
1523 | |
1524 | /* |
1525 | *---------------------------------------------------------------------- |
1526 | * Convert the job states into a string. |
1527 | * |
1528 | * Results: |
1529 | * |
1530 | * Side effects: |
1531 | * |
1532 | *---------------------------------------------------------------------- |
1533 | */ |
1534 | |
1535 | static CONST char* |
1536 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobStateStr">GetJobStateStr</a>(JobStates state) |
1537 | { |
1538 | static CONST char *stateArr[] = { |
1539 | "scheduled", /* 0 */ |
1540 | "running", /* 1 */ |
1541 | "done", /* 2 */ |
1542 | "unknown" /* 3 */ |
1543 | }; |
1544 | static int max_state_index = 3; |
1545 | |
1546 | /* Check the caller's input. */ |
1547 | if (state > (max_state_index)) { |
1548 | state = max_state_index; |
1549 | } |
1550 | |
1551 | return stateArr[state]; |
1552 | } |
1553 | |
1554 | |
1555 | /* |
1556 | *---------------------------------------------------------------------- |
1557 | * Convert the job states into a string. |
1558 | * |
1559 | * Results: |
1560 | * |
1561 | * Side effects: |
1562 | * |
1563 | *---------------------------------------------------------------------- |
1564 | */ |
1565 | static CONST char* |
1566 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobTypeStr">GetJobTypeStr</a>(JobTypes type) |
1567 | { |
1568 | static CONST char *typeArr[] = { |
1569 | "nondetached", /* 0 */ |
1570 | "detached", /* 1 */ |
1571 | "unknown" /* 2 */ |
1572 | }; |
1573 | static int max_type_index = 2; |
1574 | |
1575 | /* Check the caller's input. */ |
1576 | if (type > (max_type_index)) { |
1577 | type = max_type_index; |
1578 | } |
1579 | |
1580 | return typeArr[type]; |
1581 | } |
1582 | |
1583 | |
1584 | /* |
1585 | *---------------------------------------------------------------------- |
1586 | * Convert the job req into a string. |
1587 | * |
1588 | * Results: |
1589 | * |
1590 | * Side effects: |
1591 | * |
1592 | *---------------------------------------------------------------------- |
1593 | */ |
1594 | static CONST char* |
1595 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetJobReqStr">GetJobReqStr</a>(JobRequests req) |
1596 | { |
1597 | static CONST char *reqArr[] = { |
1598 | "none", /* 0 */ |
1599 | "wait", /* 1 */ |
1600 | "cancel", /* 2 */ |
1601 | "unknown" /* 3 */ |
1602 | }; |
1603 | static int req_max_index = 3; |
1604 | |
1605 | /* Check the caller's input. */ |
1606 | if (req > (req_max_index)) { |
1607 | req = req_max_index; |
1608 | } |
1609 | |
1610 | return reqArr[req]; |
1611 | } |
1612 | |
1613 | |
1614 | /* |
1615 | *---------------------------------------------------------------------- |
1616 | * Convert the queue req into a string. |
1617 | * |
1618 | * Results: |
1619 | * |
1620 | * Side effects: |
1621 | * |
1622 | *---------------------------------------------------------------------- |
1623 | */ |
1624 | static CONST char* |
1625 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetQueueReqStr">GetQueueReqStr</a>(QueueRequests req) |
1626 | { |
1627 | static CONST char *reqArr[] = { |
1628 | "none", /* 0 */ |
1629 | "delete" /* 1 */ |
1630 | }; |
1631 | static int req_max_index = 1; |
1632 | |
1633 | /* Check the caller's input. */ |
1634 | if (req > (req_max_index)) { |
1635 | req = req_max_index; |
1636 | } |
1637 | |
1638 | return reqArr[req]; |
1639 | } |
1640 | |
1641 | |
1642 | /* |
1643 | *---------------------------------------------------------------------- |
1644 | * Convert the thread pool req into a string. |
1645 | * |
1646 | * Results: |
1647 | * |
1648 | * Side effects: |
1649 | * |
1650 | *---------------------------------------------------------------------- |
1651 | */ |
1652 | static CONST char* |
1653 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_GetTpReqStr">GetTpReqStr</a>(ThreadPoolRequests req) |
1654 | { |
1655 | static CONST char *reqArr[] = { |
1656 | "none", /* 0 */ |
1657 | "stop" /* 1 */ |
1658 | }; |
1659 | static int req_max_index = 1; |
1660 | |
1661 | /* Check the caller's input. */ |
1662 | if (req > (req_max_index)) { |
1663 | req = req_max_index; |
1664 | } |
1665 | |
1666 | return reqArr[req]; |
1667 | } |
1668 | |
1669 | |
1670 | /* |
1671 | *---------------------------------------------------------------------- |
1672 | * Append job field to the job field list. |
1673 | * |
1674 | * Results: |
1675 | * |
1676 | * Side effects: |
1677 | * |
1678 | *---------------------------------------------------------------------- |
1679 | */ |
1680 | |
1681 | static int |
1682 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendField">AppendField</a>(Tcl_Interp *interp, |
1683 | Tcl_Obj *list, |
1684 | CONST char *name, |
1685 | CONST char *value) |
1686 | { |
1687 | /* Add Job ID */ |
1688 | if (Tcl_ListObjAppendElement(interp, list, |
1689 | Tcl_NewStringObj(name, |
1690 | (int)strlen(name))) == TCL_ERROR) { |
1691 | /* |
1692 | * Note: If there is an error occurs within Tcl_ListObjAppendElement |
1693 | * it will set the result. |
1694 | */ |
1695 | return TCL_ERROR; |
1696 | } |
1697 | |
1698 | if (Tcl_ListObjAppendElement(interp, list, |
1699 | Tcl_NewStringObj(value, |
1700 | (int)strlen(value))) == TCL_ERROR) { |
1701 | return TCL_ERROR; |
1702 | } |
1703 | |
1704 | return TCL_OK; |
1705 | } |
1706 | |
1707 | |
1708 | /* |
1709 | *---------------------------------------------------------------------- |
1710 | * Append job field to the job field list. |
1711 | * |
1712 | * Results: |
1713 | * |
1714 | * Side effects: |
1715 | * |
1716 | *---------------------------------------------------------------------- |
1717 | */ |
1718 | |
1719 | static int |
1720 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldInt">AppendFieldInt</a>(Tcl_Interp *interp, |
1721 | Tcl_Obj *list, |
1722 | CONST char *name, |
1723 | int value) |
1724 | { |
1725 | /* Add Job ID */ |
1726 | if (Tcl_ListObjAppendElement(interp, list, |
1727 | Tcl_NewStringObj(name, |
1728 | (int)strlen(name))) == TCL_ERROR) { |
1729 | /* |
1730 | * Note: If there is an error occurs within Tcl_ListObjAppendElement |
1731 | * it will set the result. |
1732 | */ |
1733 | return TCL_ERROR; |
1734 | } |
1735 | |
1736 | if (Tcl_ListObjAppendElement(interp, list, Tcl_NewIntObj(value)) == TCL_ERROR) { |
1737 | return TCL_ERROR; |
1738 | } |
1739 | |
1740 | return TCL_OK; |
1741 | } |
1742 | |
1743 | |
1744 | /* |
1745 | *---------------------------------------------------------------------- |
1746 | * Append job field to the job field list. |
1747 | * |
1748 | * Results: |
1749 | * |
1750 | * Side effects: |
1751 | * |
1752 | *---------------------------------------------------------------------- |
1753 | */ |
1754 | |
1755 | static int |
1756 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldLong">AppendFieldLong</a>(Tcl_Interp *interp, |
1757 | Tcl_Obj *list, |
1758 | CONST char *name, |
1759 | long value) |
1760 | { |
1761 | /* Add Job ID */ |
1762 | if (Tcl_ListObjAppendElement(interp, list, |
1763 | Tcl_NewStringObj(name, |
1764 | (int)strlen(name))) == TCL_ERROR) { |
1765 | /* |
1766 | * Note: If there is an error occurs within Tcl_ListObjAppendElement |
1767 | * it will set the result. |
1768 | */ |
1769 | return TCL_ERROR; |
1770 | } |
1771 | |
1772 | if (Tcl_ListObjAppendElement(interp, list, Tcl_NewLongObj(value)) == TCL_ERROR) { |
1773 | return TCL_ERROR; |
1774 | } |
1775 | |
1776 | return TCL_OK; |
1777 | } |
1778 | |
1779 | |
1780 | /* |
1781 | *---------------------------------------------------------------------- |
1782 | * Append the job field to the job field list. |
1783 | * |
1784 | * Results: |
1785 | * |
1786 | * Side effects: |
1787 | * |
1788 | *---------------------------------------------------------------------- |
1789 | */ |
1790 | |
1791 | static int |
1792 | <a href="/cvs/aolserver/aolserver/nsd/tcljob.c#A_AppendFieldDouble">AppendFieldDouble</a>(Tcl_Interp *interp, |
1793 | Tcl_Obj *list, |
1794 | CONST char *name, |
1795 | double value) |
1796 | { |
1797 | /* Add Job ID */ |
1798 | if (Tcl_ListObjAppendElement(interp, list, |
1799 | Tcl_NewStringObj(name, |
1800 | (int)strlen(name))) == TCL_ERROR) { |
1801 | /* |
1802 | * Note: If there is an error occurs within Tcl_ListObjAppendElement |
1803 | * it will set the result. |
1804 | */ |
1805 | return TCL_ERROR; |
1806 | } |
1807 | |
1808 | if (Tcl_ListObjAppendElement(interp, list, Tcl_NewDoubleObj(value)) == TCL_ERROR) { |
1809 | return TCL_ERROR; |
1810 | } |
1811 | |
1812 | return TCL_OK; |
1813 | } |
1814 | |
1815 | |
1816 | /* |
1817 | *---------------------------------------------------------------------- |
1818 | * Compute the time difference and return the result in milliseconds. |
1819 | *---------------------------------------------------------------------- |
1820 | */ |
1821 | |
1822 | static double ComputeDelta(Ns_Time *start, Ns_Time *end) { |
1823 | Ns_Time diff; |
1824 | Ns_DiffTime(end, start, &diff); |
1825 | return ((double)diff.sec * 1000.0) + ((double)diff.usec / 1000.0); |
1826 | } |
Copyright © 2010 Geeknet, Inc. All rights reserved. Terms of Use