1 /***********************************************************************/
2 /* Open Visualization Data Explorer */
3 /* (C) Copyright IBM Corp. 1989,1999 */
4 /* ALL RIGHTS RESERVED */
5 /* This code licensed under the */
6 /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */
7 /***********************************************************************/
8 /* #define CPV_DEBUG */
9
10 #include <dxconfig.h>
11 #include <dx/dx.h>
12
13 /*
14 * Description:
15 * This module contains these basic functions:
16 * 1) ExQueueGraph:
17 * It takes a Program and resolves inputs and outputs from the global
18 * dictionary, checks the cache, and decides to what to run.
19 * 2) ExStartModules
20 * It provides a function (called by step 1 and 3) that gets the next
21 * module to run, and puts it in the run queue.
22 * 3) _execGnode
23 * It actually builds the argument list and calls a module. It also
24 * sticks the result in the cache. It handles errors, deciding to
25 * skip or kill a module, ....
26 */
27
28 #if defined(HAVE_SYS_TIMEB_H)
29 #include <sys/timeb.h>
30 #endif
31
32 #if defined(HAVE_TIME_H)
33 #include <time.h>
34 #endif
35
36 #if defined(HAVE_SYS_TIMES_H)
37 #include <sys/times.h>
38 #endif
39
40 #include "evalgraph.h"
41 #include "config.h"
42 #include "graph.h"
43 #include "pmodflags.h"
44 #include "context.h"
45 #include "utils.h"
46 #include "cache.h"
47 #include "cachegraph.h"
48 #include "swap.h"
49 #include "log.h"
50 #include "packet.h"
51 #include "attribute.h"
52 #include "rq.h"
53 #include "status.h"
54 #include "vcr.h"
55 #include "_variable.h"
56 #include "sysvars.h"
57 #include "distp.h"
58 #include "graphIntr.h"
59 #include "exobject.h"
60
61 extern void DXMarkTimeX(char *s); /* from libdx/timing.c */
62 extern int _dxfHostIsLocal(char *host); /* from libdx/ */
63
64 /* Internal use functions */
65 static int QueueSendRequest(qsr_args *args);
66 static void ExExecError(Program *p, gfunc *n, ErrorCode code, Error status);
67 static int _execGnode(Pointer n);
68 static void ExStartModules(Program *p);
69 static int ExFixSwitchSelector(Program *p, gfunc *gf,
70 int executionTime, int requiredFlag);
71 static int ExFixRouteSelector(Program *p, gfunc *gf,
72 int executionTime, int requiredFlag);
73 static int ExProcessGraphFunc(Program *p, int fnbr, int executionTime);
74 static void ExRefFuncIO(Program *p, int fnbr);
75 static int ExCheckDDI(Program *p, gfunc *gf);
76 static int ExCacheDDIInputs(Program *p, gfunc *gf);
77 static void ExDoPreExecPreparation(Program *p);
78 static int ExProcessDPSENDFunction(Program *p, gfunc *gf, Object *DPSEND_obj);
79 static int ExRunOnThisProcessor(char *procid);
80 static int ExCheckInputAvailability(Program *p, gfunc *gf, int fnbr);
81 static void ExFixConstantSwitch(Program *p);
82 static void ExCleanupForState();
83
84 long
ExTime()85 ExTime()
86 {
87 uint32 dxtime;
88 #if DXD_HAS_LIBIOP
89 /*
90 * SVS time is floating-point seconds to microsecond
91 * resolution; multiply by 100 to get time to 100ths
92 */
93 dxtime = (uint32) SVS_double_time()*100;
94 #else
95 #ifdef DXD_WIN
96 time_t ltime;
97 dxtime = time(<ime); /* from 2.1.5 branch */
98 #else
99 struct tms buf;
100 dxtime = (uint32)times(&buf);
101 #endif
102 #endif
103 return dxtime;
104 }
105
106 #define CHECK_EXEC_OBJS 1
107
108 #define MARK_1(_x) ExMarkTime (0x10, _x)
109
110 #define LOCAL_ARG_MAX 512 /* max bytes to hold statically */
111 #define MAX_LABEL_LEN 64
112 #define MAX_ROUTE_OUTPUTS 21
113
114 #define INCR_RUNABLE \
115 { p->runable++;\
116 if(_dxd_exContext->subp[0] != p) _dxd_exContext->subp[0]->runable++; }
117
118 #define DECR_RUNABLE \
119 { if(p->runable > 0) p->runable--; \
120 if(_dxd_exContext->subp[0] != p && _dxd_exContext->subp[0]->runable > 0) \
121 _dxd_exContext->subp[0]->runable--; }
122
123 enum REQ_TYPE
124 {
125 NOT_SET = -1, NOT_REQUIRED = 0, REQUIRED, ALREADY_RUN, REQD_IFNOT_CACHED, RUNNING
126 };
127
128
129 typedef struct execArg
130 {
131 Program *p;
132 gfunc *gf;
133 } execArg;
134
135 static int graph_id;
136
137 int *_dxd_exKillGraph = NULL;
138 int *_dxd_exBadFunc = NULL;
139
ExCacheNewGvar(gvar * gv)140 void ExCacheNewGvar(gvar *gv)
141 {
142 gvar *cachegvar;
143 cachegvar = _dxf_ExCreateGvar(GV_UNRESOLVED);
144 _dxf_ExDefineGvar(cachegvar, gv->obj);
145 cachegvar->reccrc = gv->reccrc;
146 cachegvar->cost = gv->cost;
147 ExReference(gv->oneshot);
148 cachegvar->oneshot = gv->oneshot;
149 _dxf_ExCacheInsert(cachegvar);
150 }
151
152 /*
153 * Initialize graph execution environment
154 */
155 Error
_dxf_ExQueueGraphInit()156 _dxf_ExQueueGraphInit()
157 {
158 graph_id = 0;
159
160 if ((_dxd_exKillGraph = (int *) DXAllocate(sizeof(int))) == NULL)
161 return (ERROR);
162
163 if ((_dxd_exBadFunc = (int *) DXAllocate(sizeof(int))) == NULL)
164 return (ERROR);
165
166 *_dxd_exKillGraph = FALSE;
167 *_dxd_exBadFunc = FALSE;
168
169 return (OK);
170 }
171
172
173 /*
174 * evaluate a graph
175 */
176 void
_dxf_ExQueueGraph(Program * p)177 _dxf_ExQueueGraph(Program * p)
178 {
179 int i, j, index;
180 gvar *global;
181 ProgramVariable *pv;
182 ProgramRef *pr;
183 gfunc *gf, *gf2;
184 int ilimit, jlimit;
185 DistMsg msgtype;
186
187 MARK_1("_dxf_ExQueueGraph");
188
189 *_dxd_extoplevelloop = FALSE;
190 /*
191 * Send msg to all slave processors to execute their graphs
192 */
193 if (!_dxd_exRemoteSlave) {
194 _dxf_ResetSlavesDone();
195 msgtype = DM_EXECGRAPH;
196 for (i = 0, ilimit = SIZE_LIST(p->funcs); i < ilimit; ++i) {
197 gf = FETCH_LIST(p->funcs, i);
198 if(!_dxf_ExValidGroupAttach(gf->procgroupid)) {
199 *_dxd_exKillGraph = TRUE;
200 DXUIMessage("ERROR",
201 "Bad group attachment: Terminating graph execution");
202 msgtype = DM_KILLEXECGRAPH;
203 break;
204 }
205 if(ilimit == 1 && gf->ftype == F_MACRO)
206 for(j=0,jlimit=SIZE_LIST(gf->func.subP->funcs); j<jlimit; ++j) {
207 gf2 = FETCH_LIST(gf->func.subP->funcs, j);
208 if(!_dxf_ExValidGroupAttach(gf2->procgroupid)) {
209 *_dxd_exKillGraph = TRUE;
210 DXUIMessage("ERROR",
211 "Bad group attachment: Terminating graph execution");
212 msgtype = DM_KILLEXECGRAPH;
213 break;
214 }
215 }
216 }
217 if(ilimit > 0) /* we have at least one function in graph */
218 _dxf_ExDistributeMsg(msgtype, (Pointer)p->graphId, 0, TOSLAVES);
219 }
220
221 if(SIZE_LIST(p->funcs) != 0) {
222 _dxd_exContext->program = p;
223 _dxd_exContext->subp = (Program **)DXAllocateZero(
224 sizeof(Program *) * (SIZE_LIST(p->macros)+1));
225 if(_dxd_exContext->subp == NULL)
226 _dxf_ExDie("Could not allocate memory for list of subprograms");
227 _dxd_exContext->subp[0] = p;
228 }
229
230 p->informedMaster = FALSE;
231
232 /*
233 * Look up all undefineds, keep a reference to them until the end. If
234 * the undefined isn't found (or is named NULL) define a null gvar.
235 */
236 for (i = 0, ilimit = SIZE_LIST(p->undefineds); i < ilimit; ++i)
237 {
238 pr = FETCH_LIST(p->undefineds, i);
239 pv = FETCH_LIST(p->vars, pr->index);
240 if (pv == NULL)
241 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 001");
242 if (strcmp(pr->name, "NULL") == 0)
243 {
244 pv->gv = _dxf_ExCreateGvar(GV_DEFINED);
245 ExReference(pv->gv);
246 pv->refs++;
247 #ifdef CPV_DEBUG
248 if (pv->refs > pv->gv->object.refs)
249 printf("weird for NULL pvar\n");
250 #endif
251 }
252 else
253 {
254 global = (gvar *)_dxf_ExVariableSearch(pr->name, _dxd_exGlobalDict);
255 if (global == NULL)
256 {
257 if (!_dxd_exRemote && !_dxd_exRemoteSlave)
258 {
259 DXWarning("#4680", pr->name);
260 }
261 pv->gv = _dxf_ExCreateGvar(GV_DEFINED);
262 ExReference(pv->gv);
263 pv->refs++;
264 #ifdef CPV_DEBUG
265 if (pv->refs > pv->gv->object.refs)
266 printf("weird for undefined pvar\n");
267 #endif
268 }
269 else
270 {
271 pv->gv = global;
272 pv->gv->skip = GV_DONTSKIP;
273 pv->gv->disable_cache = FALSE;
274 pv->refs++;
275 #ifdef CPV_DEBUG
276 if (pv->refs > pv->gv->object.refs)
277 printf("weird for global pvar\n");
278 #endif
279 }
280 }
281 /* Put an extra reference on all variables from the dictionary. */
282 ExReference(pv->gv);
283 pv->refs++;
284 #ifdef CPV_DEBUG
285 if (pv->refs > pv->gv->object.refs)
286 printf("weird for variable pvar\n");
287 #endif
288 }
289
290 /* Reset oneshots and free names. */
291 for (i = 0, ilimit = SIZE_LIST(p->undefineds); i < ilimit; ++i)
292 {
293 pr = FETCH_LIST(p->undefineds, i);
294 if (strcmp(pr->name, "NULL") != 0)
295 {
296 global = (gvar *)_dxf_ExVariableSearch(pr->name, _dxd_exGlobalDict);
297 if (global != NULL)
298 {
299 /*
300 * If the original variable was a oneshot, reset it.
301 * Null out the gvar's version so it doesn't get deleted twice.
302 */
303 if (global->oneshot)
304 {
305 Object o = global->oneshot;
306 global->oneshot = NULL;
307 ExDelete(global);
308 global = _dxf_ExCreateGvar(GV_UNRESOLVED);
309 _dxf_ExDefineGvar(global, o);
310 _dxf_ExVariableInsertNoBackground(pr->name,
311 _dxd_exGlobalDict,
312 (EXObj) global);
313 DXUIMessage(pr->name, "Resetting oneshot");
314 }
315 else
316 ExDelete(global);
317 }
318 }
319 DXFree((Pointer) pr->name);
320 pr->name = NULL;
321 }
322
323
324
325 MARK_1("undefineds");
326
327 /*
328 * Define all variables: If there is not yet a gvar for each variable,
329 * make one, and if this is a constant or default (pv->defined == TRUE),
330 * set the gvar to be this value
331 */
332 for (i = 0, ilimit = SIZE_LIST(p->vars); i < ilimit; ++i)
333 {
334 pv = FETCH_LIST(p->vars, i);
335 if (pv == NULL)
336 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 004");
337 /*
338 * This first clause takes care of everything but the undefineds
339 * noted above. All vars are refed again because non-intermidiate
340 * variables need an extra reference to be held on to.
341 */
342 #if 0
343 if (pv->gv == NULL)
344 {
345 pv->gv = _dxf_ExCreateGvar(GV_UNRESOLVED);
346 ExReference(pv->gv);
347 pv->refs++;
348 #ifdef CPV_DEBUG
349 if (pv->refs > pv->gv->object.refs)
350 printf("weird for some pvar\n");
351 #endif
352 if (pv->defined)
353 {
354 _dxf_ExDefineGvar(pv->gv, pv->obj);
355 /* Put an extra reference on all constants. */
356 ExReference(pv->gv);
357 pv->refs++;
358 #ifdef CPV_DEBUG
359 if (pv->refs > pv->gv->object.refs)
360 printf("weird for defined pvar\n");
361 #endif
362 }
363 }
364 #endif
365 if(pv->gv == NULL && pv->defined)
366 {
367 pv->gv = _dxf_ExCreateGvar(GV_UNRESOLVED);
368 ExReference(pv->gv);
369 pv->refs++;
370 _dxf_ExDefineGvar(pv->gv, pv->obj);
371 /*??????*/
372 /* Put an extra reference on all constants. */
373 ExReference(pv->gv);
374 pv->refs++;
375 }
376 }
377
378 MARK_1("define vars");
379
380 for (i = 0, ilimit = SIZE_LIST(p->wiredvars); i < ilimit; ++i)
381 {
382 index = *FETCH_LIST(p->wiredvars, i);
383 ExDebug("*4", "program %x, wired var %d\n", p, index);
384 pv = FETCH_LIST(p->vars, index);
385 if (pv == NULL)
386 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 004");
387 if (pv->gv == NULL)
388 {
389 pv->gv = _dxf_ExCreateGvar(GV_UNRESOLVED);
390 ExReference(pv->gv);
391 pv->refs++;
392 #ifdef CPV_DEBUG
393 if (pv->refs > pv->gv->object.refs)
394 printf("weird for some pvar\n");
395 #endif
396 }
397 ExDebug("*4", "wired var already has gv 1\n");
398 }
399
400 MARK_1("define wired vars");
401
402 /* Mark all outputs as required. */
403 for (i = 0, ilimit = SIZE_LIST(p->outputs); i < ilimit; ++i)
404 {
405 pr = FETCH_LIST(p->outputs, i);
406 if (pr == NULL)
407 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 002");
408 pv = FETCH_LIST(p->vars, pr->index);
409 if (pv == NULL)
410 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 003");
411 if (!pv->defined)
412 {
413 ExDebug("*1", "Marking output %d at index %d as required",
414 i, pr->index);
415 pv->required = REQUIRED;
416 }
417 }
418 MARK_1("require outputs");
419
420 ExFixConstantSwitch(p);
421
422
423 /* Put all outputs in global dictionary, remembering oneshot defaults */
424 for (i = 0, ilimit = SIZE_LIST(p->outputs); i < ilimit; ++i)
425 {
426 pr = FETCH_LIST(p->outputs, i);
427 if (pr == NULL)
428 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 002");
429 pv = FETCH_LIST(p->vars, pr->index);
430 if (pv == NULL)
431 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 003");
432 pv->gv->oneshot = pr->oneshot;
433 _dxf_ExVariableInsert(pr->name, _dxd_exGlobalDict, (EXObj) pv->gv);
434 /* put an extra reference on gvar to be deleted just after */
435 /* sending outputs to slaves */
436 ExReference(pv->gv);
437 pv->refs++;
438 }
439
440 MARK_1("define outputs");
441
442 /* Compute Cache recipes */
443 for (i = 0, ilimit = SIZE_LIST(p->funcs); i < ilimit; ++i)
444 {
445 _dxf_ExComputeRecipes(p, i);
446 }
447
448 #if 0
449 /* moved this into ComputeRecipes */
450 for (i = 0, ilimit = SIZE_LIST(p->vars); i < ilimit; ++i)
451 {
452 pv = FETCH_LIST(p->vars, i);
453 if(pv->gv)
454 pv->reccrc = pv->gv->reccrc;
455 }
456
457 #endif
458 MARK_1("compute recipes");
459
460
461 /*
462 * Loop thru all functions in graph and det. which are required
463 */
464 for (i = SIZE_LIST(p->funcs) - 1; i >= 0; --i)
465 ExProcessGraphFunc(p, i, 0);
466
467 MARK_1("process funcs");
468
469 if (p->origin == GO_BACKGROUND)
470 {
471 ExDebug("*1", "Sending BG msg to UI");
472 DXUIMessage("BG", "begin");
473 }
474 p->first_skipped = -1;
475 p->cursor = -1;
476 ExDoPreExecPreparation(p);
477
478 /* we used to delete unneccessary variables at this point but */
479 /* we are no longer evaluating the whole graph at once. */
480 /* With the changes for macros we only evaluate a macro if */
481 /* it is needed. Is it a problem to leave unused variables */
482 /* around until the program is deleted? I don't think they */
483 /* are using much space. */
484
485 ExDebug("*1", "Before ExDelete of pvar loop at end of graph execution");
486 for (i = 0, ilimit = SIZE_LIST(p->wiredvars); i < ilimit; ++i)
487 {
488 index = *FETCH_LIST(p->wiredvars, i);
489 pv = FETCH_LIST(p->vars, index);
490 ExDebug("*6", "var %d, count %d\n", index, pv->gv->object.refs);
491 ExDelete(pv->gv);
492 if (--pv->refs == 0)
493 pv->gv = NULL;
494 #ifdef CPV_DEBUG
495 if (pv->refs > pv->gv->object.refs)
496 printf("weird for deleting pvar\n");
497 #endif
498 }
499 MARK_1("delete vars");
500
501 p->cursor = -1;
502 ExStartModules(p);
503
504 }
505
ExCacheMacroResults(Program * p)506 void ExCacheMacroResults(Program *p)
507 {
508 gfunc *n;
509 gvar *gv;
510 int i, *ip, index;
511 ProgramVariable *pv;
512 double cost;
513
514 n = p->saved_gf;
515
516 if(n->ftype == F_MODULE)
517 return;
518
519 n->endtime = ExTime();
520 cost = (double) n->endtime - n->starttime;
521
522 if(n->func.subP->error && n->nout == 0 && !(n->flags & MODULE_SIDE_EFFECT)
523 )
524 _dxf_ExManageCacheTable(&n->mod_path, 0, 0);
525
526 for (i = 0; i < n->nout; ++i) {
527 ip = FETCH_LIST(n->outputs, i);
528 if (ip && *ip >= 0) {
529 pv = FETCH_LIST(p->vars, *ip);
530 if (pv == NULL)
531 _dxf_ExDie("Executive Inconsistency: _execGnode 003");
532 gv = pv->gv;
533
534 /* restore the saved cache tags */
535 index = SIZE_LIST(pv->cts) - 1;
536 pv->reccrc = *FETCH_LIST(pv->cts, index);
537 /* gvar may have been deleted if it's not needed anymore */
538 if(pv->gv)
539 pv->gv->reccrc = pv->reccrc;
540 DELETE_LIST(uint32, pv->cts, index);
541
542 if(gv->skip || n->func.subP->error)
543 continue;
544 if(n->flags & MODULE_CHANGES_STATE)
545 _dxf_ExSetGVarCost(gv, CACHE_PERMANENT);
546 else
547 _dxf_ExSetGVarCost(gv, cost);
548 if (_dxd_exCacheOn) {
549 if (pv->excache != CACHE_OFF && pv->cacheattr)
550 ExCacheNewGvar(gv);
551 else if (n->excache != CACHE_OFF &&
552 (pv->excache != CACHE_OFF || !pv->cacheattr))
553 ExCacheNewGvar(gv);
554 }
555 }
556 }
557 /*
558 * Delete inputs and outputs (outputs first), just in case someone passed
559 * an input through unchanged. If the output was generated in error, don't
560 * delete it (to be sure it sticks around for subsequent modules).
561 */
562 for (i = 0; i < n->nout; i++)
563 {
564 index = *FETCH_LIST(n->outputs, i);
565 if (index > -1)
566 {
567 pv = FETCH_LIST(p->vars, index);
568 ExDelete(pv->gv);
569 if (--pv->refs == 0) {
570 pv->gv = NULL;
571 ExDebug("*6","deleting %s output %d %d\n",
572 _dxf_ExGFuncPathToString(n),i,index);
573 }
574 pv->required = NOT_REQUIRED;
575 }
576 }
577 for (i = 0; i < n->nin; i++)
578 {
579 index = *FETCH_LIST(n->inputs, i);
580 if (index > -1)
581 {
582 pv = FETCH_LIST(p->vars, index);
583 ExDelete(pv->gv);
584 if (--pv->refs == 0) {
585 pv->gv = NULL;
586 ExDebug("*6","deleting %s input %d %d\n",
587 _dxf_ExGFuncPathToString(n),i,index);
588 }
589 }
590 }
591
592 DECR_RUNABLE
593 }
594
595 Error
ExQueueSubGraph(Program * p)596 ExQueueSubGraph(Program * p)
597 {
598 int i, ilimit, nfuncs;
599 int j, jlimit, index;
600 ProgramVariable *pv;
601 gfunc *gf;
602
603 _dxd_exContext->program = p;
604 _dxd_exContext->subp[p->subgraphId] = p;
605
606 for (i = 0, ilimit = SIZE_LIST(p->wiredvars); i < ilimit; ++i)
607 {
608 index = *FETCH_LIST(p->wiredvars, i);
609 ExDebug("*4", "program %x, wired var %d\n", p, index);
610 pv = FETCH_LIST(p->vars, index);
611 if (pv == NULL)
612 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 004");
613 if (pv->gv == NULL)
614 {
615 pv->gv = _dxf_ExCreateGvar(GV_UNRESOLVED);
616 ExReference(pv->gv);
617 pv->refs++;
618 #ifdef CPV_DEBUG
619 if (pv->refs > pv->gv->object.refs)
620 printf("weird for some pvar\n");
621 #endif
622 }
623 else {
624 ExReference(pv->gv);
625 pv->refs++;
626 }
627 }
628
629 MARK_1("define wired vars");
630
631 nfuncs = SIZE_LIST(p->funcs);
632
633 for (i = 0, ilimit = SIZE_LIST(p->funcs); i < ilimit; ++i)
634 {
635 gf = FETCH_LIST(p->funcs, i);
636 if(p->subgraphId == 1 && (gf->flags & MODULE_LOOP)) {
637 /* First time we set it send warning message */
638 if(*_dxd_extoplevelloop == FALSE && !_dxd_exRemoteSlave &&
639 *_dxd_exNSlaves > 0)
640 DXUIMessage ("WARNING MSGERRUP",
641 "Cannot distribute parts of loop, all modules will run on host %s", _dxd_exHostName);
642 *_dxd_extoplevelloop = TRUE;
643 }
644
645 /* This is not longer needed because UndefineGvar takes care of it*/
646 #if 0
647 /* GDA */
648 /*
649 * Any modules skipped due to a route on the last time through
650 * the loop must be reconsidered this time.
651 */
652
653 if (gf->required == ALREADY_RUN)
654 {
655 int j, jlimit;
656
657 for (j = 0, jlimit = SIZE_LIST(gf->inputs); j < jlimit; ++j)
658 {
659
660 int index = *FETCH_LIST(gf->inputs, j);
661 if (index >= 0)
662 {
663 pv = FETCH_LIST(p->vars, index);
664 if (pv && pv->gv && pv->gv->skip == GV_SKIPROUTE)
665 pv->gv->skip = GV_DONTSKIP;
666 }
667 }
668
669 if (IsRoute(gf))
670 gf->required = REQUIRED;
671 }
672
673 #endif
674 for (j = 0, jlimit = SIZE_LIST(gf->outputs); j < jlimit; ++j)
675 {
676 index = *FETCH_LIST(gf->outputs, j);
677 if (index >= 0)
678 {
679 pv = FETCH_LIST(p->vars, index);
680 if(!pv->gv)
681 _dxf_ExDie(
682 "Executive Inconsistency: missing gv structure for %dth variable, in function %s ", index, gf->name);
683 if(pv->gv->type == GV_UNRESOLVED)
684 pv->reccrc = pv->gv->reccrc = 0;
685 }
686 }
687
688 if(gf->required != NOT_SET)
689 gf->required = NOT_REQUIRED;
690 }
691
692 ExFixConstantSwitch(p);
693
694 /* Compute Cache recipes */
695 for (i = 0; i < nfuncs; ++i)
696 {
697 _dxf_ExComputeRecipes(p, i);
698 }
699
700 #if 0
701 /* moved this into ComputeRecipes */
702 /* Can this be moved into ComputeRecipes?????*/
703 for (i = 0, ilimit = SIZE_LIST(p->vars); i < ilimit; ++i)
704 {
705 pv = FETCH_LIST(p->vars, i);
706 if(pv->gv)
707 pv->reccrc = pv->gv->reccrc;
708 }
709
710 #endif
711 MARK_1("compute recipes");
712
713 /*
714 * Loop thru all functions in graph and det. which are required
715 */
716 for (i = nfuncs - 1; i >= 0; --i)
717 ExProcessGraphFunc(p, i, 0);
718
719 MARK_1("process funcs in subprogram");
720
721 p->first_skipped = -1;
722 p->cursor = -1;
723 ExDoPreExecPreparation(p);
724
725 ExDebug("*1", "Before ExDelete of pvar loop at end of graph execution");
726 for (i = 0, ilimit = SIZE_LIST(p->wiredvars); i < ilimit; ++i)
727 {
728 index = *FETCH_LIST(p->wiredvars, i);
729 pv = FETCH_LIST(p->vars, index);
730 ExDebug("*6", "var %d, count %d\n", index, pv->gv->object.refs);
731 ExDelete(pv->gv);
732 if (--pv->refs == 0)
733 pv->gv = NULL;
734 #ifdef CPV_DEBUG
735 if (pv->refs > pv->gv->object.refs)
736 printf("weird for deleting pvar\n");
737 #endif
738 }
739 MARK_1("delete vars");
740
741 ExStartModules(p);
742
743 return OK;
744 }
745
_QueueableStartModules(Pointer pp)746 static int _QueueableStartModules(Pointer pp)
747 {
748 Program *p = (Program *)pp;
749 ExStartModules(p);
750 return (0);
751 }
752
_QueueableStartModulesReset(Pointer pp)753 static int _QueueableStartModulesReset(Pointer pp)
754 {
755 Program *p = (Program *)pp;
756 p->cursor = -1;
757 p->outstandingRequests--;
758
759 ExStartModules(p);
760 return (0);
761 }
762
763
764 static void
ExStartModules(Program * p)765 ExStartModules(Program *p)
766 {
767 int i;
768 gfunc *gf;
769 int procId;
770 execArg *ta;
771 char pbuf[64];
772 int found = FALSE;
773 int past;
774 int ilimit;
775 ProgramVariable *pv;
776 ProgramRef *pr;
777 int nfuncs;
778 int oldCursor;
779 gvar *gv;
780
781 ExDebug("*1", "In ExStartModules with program %x\n",
782 _dxd_exContext->program);
783 /* check to see if program was deleted already */
784 /*
785 if(_dxd_exContext->program == NULL)
786 return;
787 */
788
789 nfuncs = SIZE_LIST(p->funcs);
790
791 past = p->cursor + 1 >= nfuncs;
792
793 ilimit = nfuncs;
794
795 oldCursor = p->cursor;
796 for (i = p->cursor + 1; i < ilimit; ++i)
797 {
798 if (p->cursor != oldCursor)
799 {
800 i = p->cursor + 1;
801 oldCursor = p->cursor;
802 }
803 gf = FETCH_LIST(p->funcs, i);
804 if(*_dxd_exBadFunc == FALSE && gf->ftype == F_MODULE &&
805 gf->func.module == m__badfunc &&
806 (_dxd_exRemoteSlave || *_dxd_exNSlaves > 0)) {
807 m__badfunc(NULL, NULL);
808 ExExecError(p, gf, ERROR_NOT_IMPLEMENTED, ERROR);
809 *_dxd_exKillGraph = TRUE;
810 *_dxd_exBadFunc = TRUE;
811 _dxf_ExDistributeMsg(DM_BADFUNC, NULL, 0, TOPEERS);
812 }
813 if (gf->required == REQUIRED)
814 {
815 /* for top level macro we shouldn't have a process */
816 /* group assignment and all machines will have to */
817 /* evaluate the top level macro. */
818 if((gf->ftype == F_MACRO && gf->procgroupid == NULL &&
819 p == _dxd_exContext->subp[0]) ||
820 ((ExRunOnThisProcessor(gf->procgroupid) ||
821 !strcmp(gf->name, "Trace"))
822 && ExCheckInputAvailability(p, gf, i)))
823 {
824 found = TRUE;
825 ta = (execArg *) DXAllocate(sizeof(execArg));
826 if (ta == NULL)
827 _dxf_ExDie("Executive Inconsistency: ExStartModules 001");
828
829 ta->p = p;
830 ta->gf = gf;
831 procId = ((gf->flags & MODULE_PIN) != 0 && DXProcessors(0) > 1) ?
832 EX_PIN_PROC :
833 0;
834 MARK_1("RQEnqueue");
835 if (!IsSwitch(gf) && !IsRoute(gf))
836 gf->required = RUNNING;
837 p->cursor = i;
838 _dxf_ExRQEnqueue(_execGnode, (Pointer) ta, 1, 0, procId, FALSE);
839 break;
840 }
841 }
842 }
843
844 if (!found || past)
845 {
846 if (p->first_skipped != -1)
847 {
848 if(p->cursor != (p->first_skipped -1)) {
849 if(p->cursor > -1) {
850 gfunc *dgf;
851 dgf = FETCH_LIST(p->funcs, p->first_skipped);
852 ExDebug("1", "Queueing StartModules with cursor at %s",
853 _dxf_ExGFuncPathToString(dgf));
854 }
855 }
856 p->cursor = p->first_skipped - 1;
857 ExDebug("5", "Should reset cursor to %d at this point", p->first_skipped);
858 p->first_skipped = -1;
859 _dxf_ExRQEnqueue(_QueueableStartModules, (Pointer) p,
860 1, 0, 0, FALSE);
861 return;
862 }
863 /* if this is a loop and we are not done, re-execute the loop */
864 if(p->loopctl.isdoneset)
865 p->loopctl.done = TRUE;
866 if(!p->loopctl.done) {
867 /* need to redo cache tags */
868 p->loopctl.first = FALSE;
869 p->loopctl.counter++;
870 MARK_1("rerun loop");
871 _dxf_ExRunOn(1, ExQueueSubGraph, (Pointer)p, 0);
872 return;
873 }
874
875 if(p->returnP) {
876 ExCleanupForState();
877 ExCacheMacroResults(p->returnP);
878 p->loopctl.first = TRUE;
879 p->loopctl.done = TRUE;
880 p->loopctl.isdoneset = FALSE;
881 p->loopctl.counter = 0;
882 _dxd_exContext->program = p->returnP;
883 if(p->error) {
884 DXLoopDone(1);
885 p->returnP->error = TRUE;
886 }
887 ExStartModules(p->returnP);
888 }
889 else
890 {
891 GDictSend pkg;
892
893 _gorigin origin = p->origin;
894 int graphId = p->graphId;
895 int error = p->error;
896 int frame = p->vcr.frame;
897 int nframe = p->vcr.nframe;
898 int stop = p->vcr.stop;
899 int kill = *_dxd_exKillGraph;
900 gvar *new_gvar;
901
902 /* Send all outputs to peers */
903 /* Make a seperate gvar for each oneshot. Oneshots can */
904 /* not share a gvar with another variable. */
905 /* If they share a gvar then the wrong variable might get */
906 /* reset after it is referenced once. */
907 for (i = 0, ilimit = SIZE_LIST (p->outputs); i < ilimit; ++i)
908 {
909 pr = FETCH_LIST(p->outputs, i);
910 pv = FETCH_LIST(p->vars, pr->index);
911 gv = pv->gv;
912 if(gv == NULL)
913 _dxf_ExDie("Executive Inconsistency: Null Gvar - cannot send output var to peers");
914 if(gv->oneshot) {
915 new_gvar = _dxf_ExCreateGvar(GV_UNRESOLVED);
916 _dxf_ExDefineGvar(new_gvar, gv->obj);
917 new_gvar->oneshot = gv->oneshot;
918 new_gvar->reccrc = gv->reccrc;
919 gv->oneshot = NULL;
920 _dxf_ExVariableInsertNoBackground(pr->name,
921 _dxd_exGlobalDict,
922 (EXObj) new_gvar);
923 }
924 if (gv->type != GV_UNRESOLVED) {
925 _dxf_ExCreateGDictPkg(&pkg, pr->name, &gv->object);
926 ExDebug("7", "sending cache for variable %s", pr->name);
927 _dxf_ExDistributeMsg(DM_INSERTGDICT, (Pointer)&pkg,
928 sizeof(GDictSend), TOSLAVES);
929 }
930 /* we put an extra ref count on gvar at beginning of */
931 /* _dxf_ExQueueGraph so the gvar would still be */
932 /* available here. */
933 ExDelete(gv);
934 pv->refs--;
935 DXFree ((Pointer) pr->name);
936 pr->name = NULL;
937 }
938
939 if (_dxd_exRemoteSlave)
940 {
941 if (!p->informedMaster)
942 _dxf_ExDistributeMsg(DM_GRAPHDONE, NULL, 0, TOMASTER);
943 p->informedMaster = TRUE;
944 if (p->deleted && p->runable == 0)
945 _dxf_ExGQDecrement(p);
946 }
947 else /* master, wait for children to finish */
948 {
949 if(nfuncs > 0 && !p->deleted && !p->waited) {
950 p->waited = TRUE;
951 _dxf_ExRunOn(1, _dxf_ExWaitOnSlaves, NULL, 0);
952 }
953 if (p->outstandingRequests == 0)
954 _dxf_ExGQDecrement(p);
955 }
956
957 switch (origin)
958 {
959 case GO_FOREGROUND:
960 ExDebug("*1", "Completing %d [%08x] FOREGROUND",
961 graphId, p);
962 break;
963
964 case GO_BACKGROUND:
965 DXUIMessage("BG", "end");
966 ExDebug("*1", "Completing %d [%08x] BACKGROUND",
967 graphId, p);
968 break;
969
970 case GO_VCR:
971 if (_dxd_exRemote && !error && !kill)
972 {
973 sprintf(pbuf, "frame %12d %12d", frame, nframe);
974 _dxf_ExSPack(PACK_INTERRUPT, graphId, pbuf, 31);
975 }
976 _dxf_ExVCRCallBack(graphId);
977
978 ExDebug("*1", "Completing %d [%08x] VCR frame %d %s",
979 graphId, p, frame, stop ? "STOP" : "");
980 break;
981
982 default:
983 ExDebug("*1", "Completing %d [%08x] ???",
984 graphId, p);
985 break;
986 }
987 return;
988 }
989 }
990 }
991
992 static void
ModBeginMsg(Program * p,gfunc * n,char * bell,int * len)993 ModBeginMsg(Program *p, gfunc *n, char *bell, int *len)
994 {
995
996 if (_dxd_exShowBells)
997 {
998 strcpy(bell, "begin ");
999 strcat(bell, _dxf_ExGFuncPathToString(n));
1000 *len = strlen(bell);
1001 _dxf_ExSPack(PACK_INTERRUPT, p->graphId, bell, *len);
1002 }
1003 if(_dxd_exRemoteSlave)
1004 DXDebug("*0", "Planning [%08x] %d::%s on %s", n,
1005 p->graphId, _dxf_ExGFuncPathToString(n), _dxd_exHostName);
1006 else
1007 DXDebug("*0", "Planning [%08x] %d::%s", n, p->graphId,
1008 _dxf_ExGFuncPathToString(n));
1009 }
1010
1011
1012 static void
ModEndMsg(Program * p,char * bell,int len)1013 ModEndMsg(Program *p, char *bell, int len)
1014 {
1015
1016 if (_dxd_exShowBells) {
1017 bell[0] = 'e';
1018 bell[1] = 'n';
1019 bell[2] = 'd';
1020 bell[3] = ' ';
1021 bell[4] = ' ';
1022 _dxf_ExSPack(PACK_INTERRUPT, p->graphId, bell, len);
1023 }
1024 }
1025
1026 /*
1027 * Once all of the inputs to a node are available, this routine does the
1028 * actual execution of the module code.
1029 */
1030 static int
_execGnode(Pointer ptr)1031 _execGnode(Pointer ptr)
1032 {
1033 execArg *ta = (execArg *) ptr;
1034 Program *p = ta->p;
1035 gfunc *n = ta->gf;
1036 int i;
1037 int index;
1038 gvar *gv;
1039 Error status = ERROR;
1040 ErrorCode code;
1041 int runStatus;
1042 int nin;
1043 int nout;
1044 int argsize;
1045 static int argsalloc = 0;
1046 static Object *args = NULL;
1047
1048 ProgramVariable *pv;
1049 int *ip;
1050 double cost;
1051 char bell[512];
1052 int len = 0;
1053 char buf[33];
1054 int skipping = FALSE;
1055 int ilimit;
1056 int nbr_inputs_inerror;
1057 int nbr_inputs_routeoff;
1058 int nbr_inputs_null;
1059 Context savedContext;
1060 int dpSendOtherProc = FALSE;
1061
1062 MARK_1("_execGnode");
1063
1064 DXFree((Pointer) ptr);
1065
1066 if (*_dxd_exKillGraph)
1067 {
1068 DXDebug("*0", "Killing [%08x] %d::%s", n, p->graphId,
1069 _dxf_ExGFuncPathToString(n));
1070 if(n->nout == 0 && !(n->flags & MODULE_SIDE_EFFECT))
1071 _dxf_ExManageCacheTable(&n->mod_path, 0, 0);
1072
1073 for (i = 0, ilimit = SIZE_LIST(n->outputs); i < ilimit; ++i)
1074 {
1075 ip = FETCH_LIST(n->outputs, i);
1076 if (ip && *ip >= 0)
1077 {
1078 pv = FETCH_LIST(p->vars, *ip);
1079 if (pv == NULL)
1080 _dxf_ExDie("Executive Inconsistency: _execGnode 005");
1081 pv->gv->skip = GV_SKIPERROR;
1082 _dxf_ExDefineGvar(pv->gv, NULL);
1083 }
1084 }
1085 p->loopctl.done = TRUE;
1086 p->loopctl.isdoneset = TRUE;
1087 }
1088 else
1089 {
1090 ExDebug("*1", "In execGnode for func :%s", _dxf_ExGFuncPathToString(n));
1091 if (IsSwitch(n))
1092 {
1093 if (ExFixSwitchSelector(p, n, TRUE, REQUIRED))
1094 {
1095 ExDoPreExecPreparation(p);
1096 p->cursor = -1;
1097 ExStartModules(p);
1098 return (OK);
1099 }
1100 else
1101 {
1102 if (_dxd_exEnableDebug)
1103 printf("Starting Module %s\n", _dxf_ExGFuncPathToString(n));
1104 /* you won't be able to see the light go green */
1105 /* since the messages are close together but */
1106 /* the UI can do something with the messages */
1107 /* to tell that this Switch has been run. */
1108 ModBeginMsg(p, n, bell, &len);
1109 n->required = ALREADY_RUN;
1110 ModEndMsg(p, bell, len);
1111 }
1112 goto module_cleanup;
1113 }
1114 if (IsRoute(n))
1115 {
1116
1117 if (ExFixRouteSelector(p, n, TRUE, REQUIRED))
1118 {
1119 ExDoPreExecPreparation(p);
1120 p->cursor = -1;
1121 ExStartModules(p);
1122 return (OK);
1123 }
1124 else
1125 {
1126 if (_dxd_exEnableDebug)
1127 printf("Starting Module %s\n", _dxf_ExGFuncPathToString(n));
1128 /* you won't be able to see the light go green */
1129 /* since the messages are close together but */
1130 /* the UI can do something with the messages */
1131 /* to tell that this Route has been run. */
1132 ModBeginMsg(p, n, bell, &len);
1133 n->required = ALREADY_RUN;
1134 ModEndMsg(p, bell, len);
1135 }
1136 goto module_cleanup;
1137 }
1138
1139 nin = n->nin;
1140 nout = n->nout;
1141
1142 /*---------------------------------------------------------------------*/
1143 /* See if module needs to be scheduled. The return from ExCheckDDI */
1144 /* will be FALSE if it does not need to be scheduled, and the input(s) */
1145 /* will have been properly passed thru to the receiving module(s) */
1146 /*---------------------------------------------------------------------*/
1147 if (n->flags & MODULE_REROUTABLE)
1148 {
1149 if (!ExCheckDDI(p, n))
1150 {
1151 goto module_cleanup;
1152 }
1153 }
1154
1155 /* Allocate arg-list if not enough has been allocated so far */
1156 argsize = (nin + nout + 1) * sizeof(Object);
1157 if (argsalloc <= argsize)
1158 {
1159 argsize = MAX(argsize, LOCAL_ARG_MAX);
1160 if (args != NULL)
1161 DXFree((Pointer) args);
1162 args = (Object *) DXAllocateLocal(argsize);
1163 if (args == NULL)
1164 _dxf_ExDie("_execGnode: can't allocate local memory");
1165 argsalloc = argsize;
1166 }
1167 ExZero(args, argsize);
1168
1169 /*
1170 * build up the vector of inputs
1171 */
1172 nbr_inputs_inerror = 0;
1173 nbr_inputs_routeoff = 0;
1174 nbr_inputs_null = 0;
1175 MARK_1("build input");
1176 for (i = 0; i < nin; i++)
1177 {
1178 index = *FETCH_LIST(n->inputs, i);
1179 if (index == -1)
1180 {
1181 args[i] = NULL;
1182 nbr_inputs_null++;
1183 }
1184 else
1185 {
1186 pv = FETCH_LIST(p->vars, index);
1187 gv = pv->gv;
1188 switch(gv->skip) {
1189 case GV_DONTSKIP:
1190 break;
1191 case GV_SKIPERROR:
1192 nbr_inputs_inerror++;
1193 break;
1194 case GV_SKIPROUTE:
1195 nbr_inputs_routeoff++;
1196 break;
1197 case GV_SKIPMACROEND:
1198 break;
1199 }
1200
1201 /*
1202 * If we shouldn't run after an error, mark outputs as
1203 * errors, and return. Otherwise, set the args array
1204 * appropriately, and remember if we were executed under
1205 * error conditions or not.
1206 */
1207 if (gv->skip && (n->flags & MODULE_ERR_CONT) == 0)
1208 {
1209 DXDebug("*0", "Skipping [%08x] %d::%s",
1210 n, p->graphId, _dxf_ExGFuncPathToString(n));
1211 for (i = 0, ilimit = SIZE_LIST(n->outputs); i < ilimit; ++i)
1212 {
1213 ip = FETCH_LIST(n->outputs, i);
1214 if (ip && *ip >= 0)
1215 {
1216 pv = FETCH_LIST(p->vars, *ip);
1217 if (pv == NULL)
1218 _dxf_ExDie("Executive Inconsistency: _execGnode 004");
1219 pv->gv->skip = gv->skip;
1220 _dxf_ExDefineGvar(pv->gv, NULL);
1221 }
1222 }
1223 goto error_continue;
1224 }
1225 else
1226 {
1227 skipping |= ((gv->skip == GV_SKIPERROR) || gv->disable_cache);
1228 if (gv == NULL || gv->skip)
1229 args[i] = NULL;
1230 else
1231 if (pv->dflt == NULL && gv->type == GV_UNRESOLVED)
1232 {
1233 ExDebug("*1", " _execGnode 001: [%2d] type = %2d %d::%s",
1234 i, gv->type, p->graphId, _dxf_ExGFuncPathToString(n));
1235 ExDebug("*1", " _execGnode 001: at input#:%d of %d with index#:%d",
1236 i, nin, index);
1237 _dxf_ExDie("Executive Inconsistency: _execGnode 001");
1238 }
1239 else
1240 {
1241 if (gv->obj == NULL && pv->dflt != NULL)
1242 _dxf_ExDefineGvar(gv, pv->dflt);
1243 args[i] = gv->obj;
1244
1245 #if CHECK_EXEC_OBJS
1246 _dxf_EXOCheck((EXO_Object) gv);
1247 #endif
1248 ExDebug("*1", " [%2d] type = %2d %d::%s",
1249 i, gv->type, p->graphId, _dxf_ExGFuncPathToString(n));
1250 }
1251 }
1252 }
1253 }
1254 ExDebug("*1", "Total inputs = %d. Nbr in error = %d, Nbr NULL = %d",
1255 n->nin, nbr_inputs_inerror, nbr_inputs_null);
1256 if (nbr_inputs_inerror + nbr_inputs_routeoff + nbr_inputs_null
1257 == n->nin)
1258 {
1259 if(nbr_inputs_inerror > 0)
1260 {
1261 ExDebug("*1", "No valid inputs: Skipping [%08x] %d::%s",
1262 n, p->graphId, _dxf_ExGFuncPathToString(n));
1263 DXWarning("#4690", _dxf_ExGFuncPathToString(n));
1264 DXLoopDone(1);
1265
1266 for (i = 0, ilimit = SIZE_LIST(n->outputs); i < ilimit; ++i)
1267 {
1268 ip = FETCH_LIST(n->outputs, i);
1269 if (ip && *ip >= 0)
1270 {
1271 pv = FETCH_LIST(p->vars, *ip);
1272 if (pv == NULL)
1273 _dxf_ExDie("Executive Inconsistency: _execGnode 004");
1274 pv->gv->skip = GV_SKIPERROR;
1275 _dxf_ExDefineGvar(pv->gv, NULL);
1276 }
1277 }
1278 goto error_continue;
1279 }
1280 if(nbr_inputs_routeoff > 0)
1281 {
1282 DXDebug("*0", "Skipping [%08x] %d::%s", n, p->graphId,
1283 _dxf_ExGFuncPathToString(n));
1284 ExDebug("*1", "inputs all routed off: Skipping [%08x] %d::%s",
1285 n, p->graphId, _dxf_ExGFuncPathToString(n));
1286
1287 for (i = 0, ilimit = SIZE_LIST(n->outputs); i < ilimit; ++i)
1288 {
1289 ip = FETCH_LIST(n->outputs, i);
1290 if (ip && *ip >= 0)
1291 {
1292 pv = FETCH_LIST(p->vars, *ip);
1293 if (pv == NULL)
1294 _dxf_ExDie("Executive Inconsistency: _execGnode 004");
1295 pv->gv->skip = GV_SKIPROUTE;
1296 _dxf_ExDefineGvar(pv->gv, NULL);
1297 }
1298 }
1299 goto error_continue;
1300 }
1301 }
1302 /* Make sure the error flag get passed through to the outputs
1303 * of MacroEnd.
1304 */
1305 if(nbr_inputs_inerror > 0 && (n->flags & MODULE_ERR_CONT) &&
1306 strcmp(n->name, "MacroEnd") == 0) {
1307 for (i = 0, ilimit = SIZE_LIST(n->outputs); i < ilimit; ++i)
1308 {
1309 ProgramVariable *inpv;
1310
1311 index = *FETCH_LIST(n->inputs, i+1);
1312 if (index == -1)
1313 continue;
1314 inpv = FETCH_LIST(p->vars, index);
1315 ip = FETCH_LIST(n->outputs, i);
1316 if (ip && *ip >= 0)
1317 {
1318 pv = FETCH_LIST(p->vars, *ip);
1319 if (pv == NULL)
1320 _dxf_ExDie("Executive Inconsistency: _execGnode 004");
1321 if(inpv->gv->skip == GV_SKIPERROR)
1322 pv->gv->skip = GV_SKIPERROR;
1323 }
1324 }
1325 }
1326
1327 /* DPSEND modules have a null func ptr, no need to send a message
1328 * to UI for DPSEND modules.
1329 */
1330
1331 if (n->ftype == F_MODULE && n->func.module != NULL)
1332 ModBeginMsg(p, n, bell, &len);
1333
1334 /* plan/execute the module */
1335
1336 DXResetError();
1337
1338 buf[0] = '>';
1339 buf[1] = ' ';
1340 strncpy(buf + 2, n->name, 30);
1341 buf[32] = '\0';
1342 if (_dxd_exMarkMask & 0x20)
1343 DXMarkTimeX(buf);
1344 else
1345 DXMarkTime(buf);
1346
1347 if(n->ftype == F_MODULE) {
1348 _dxfCopyContext(&savedContext, _dxd_exContext);
1349 _dxd_exCurrentFunc = n;
1350 }
1351
1352 runStatus = get_status();
1353 set_status(PS_RUN);
1354 n->starttime = ExTime();
1355
1356 /*
1357 * See if module is a "DPSEND" module generated for distributed
1358 * processing. If it is, call a ProcessDPSENDFunction. That function
1359 * determines if the target module's processgroup is running on the
1360 * same processor as the input, in which case the DPSEND is ignored.
1361 * Otherwise, a message is sent to the target processor. In both
1362 * cases, processing continues with the next module in the gfunc list.
1363 */
1364 if (n->ftype == F_MODULE && n->func.module == NULL &&
1365 strcmp(n->name, "DPSEND") == 0)
1366 {
1367 if (_dxd_exEnableDebug)
1368 printf("Starting Module %s\n", _dxf_ExGFuncPathToString(n));
1369 status = OK;
1370 dpSendOtherProc = ExProcessDPSENDFunction(p, n, &args[nin + 1]);
1371 goto after_module_scheduling;
1372 }
1373
1374 if ((!_dxd_exSkipExecution ||
1375 (strcmp(n->name, "Trace") == 0) ||
1376 (strcmp(n->name, "Usage") == 0)))
1377 {
1378 if(n->ftype == F_MACRO) {
1379 /* save cache tags for outputs */
1380 for (i = 0, ilimit = SIZE_LIST(n->outputs); i < ilimit; ++i)
1381 {
1382 ip = FETCH_LIST(n->outputs, i);
1383 if (ip && *ip >= 0)
1384 {
1385 pv = FETCH_LIST(p->vars, *ip);
1386 APPEND_LIST(uint32, pv->cts, pv->reccrc);
1387 }
1388 }
1389 n->func.subP->loopctl.first = TRUE;
1390 n->func.subP->loopctl.counter = 0;
1391 COPY_LIST(n->func.subP->vars, p->vars);
1392 n->func.subP->graphId = p->graphId;
1393 n->func.subP->returnP = p;
1394
1395 if(SIZE_LIST(n->func.subP->funcs) > 0) {
1396 p->saved_gf = n;
1397 /* This extra reference is to make sure that the
1398 * graph does not get deleted before returning to
1399 * this routine and cleaning up. This will happen
1400 * if the subgraph has no modules to run and is
1401 * at the top level.
1402 */
1403 INCR_RUNABLE
1404 MARK_1("queue sub graph");
1405 _dxf_ExRunOn(1, ExQueueSubGraph, (Pointer)n->func.subP, 0);
1406 status = OK;
1407 }
1408 else
1409 status = ERROR;
1410 goto error_continue;
1411 }
1412 else {
1413 if (_dxd_exEnableDebug)
1414 printf("Starting Module %s\n", _dxf_ExGFuncPathToString(n));
1415 status = (*n->func.module) (args, &args[nin + 1]);
1416 }
1417 }
1418 else
1419 {
1420 status = OK;
1421 }
1422
1423 after_module_scheduling:;
1424
1425 n->endtime = ExTime();
1426
1427 set_status(runStatus);
1428 if(n->ftype == F_MODULE) {
1429 _dxfCopyContext(_dxd_exContext, &savedContext);
1430 _dxd_exCurrentFunc = NULL;
1431 }
1432
1433 buf[0] = '<';
1434 if (_dxd_exMarkMask & 0x20)
1435 DXMarkTimeX(buf);
1436 else
1437 DXMarkTime(buf);
1438
1439 /* DPSEND modules have a null func ptr, no need to send this
1440 * message to UI since DPSEND modules don't turn green.
1441 */
1442 if (n->ftype == F_MODULE && n->func.module != NULL)
1443 ModEndMsg(p, bell, len);
1444
1445 /* clear cache tag */
1446 if(status == ERROR && n->nout == 0 && !(n->flags & MODULE_SIDE_EFFECT))
1447 _dxf_ExManageCacheTable(&n->mod_path, 0, 0);
1448
1449 /*
1450 * report any error in a meaningful manner.
1451 * If no error occurred, cache inputs with the "cache" attr in the
1452 * mdf for modules with REROUTABLE inputs
1453 */
1454 if(n->ftype == F_MODULE) {
1455 code = DXGetError();
1456 if (code != ERROR_NONE || status == ERROR) {
1457 DXLoopDone(1);
1458 ExExecError(p, n, code, status);
1459 }
1460 else
1461 {
1462 status = OK;
1463 if (n->flags & MODULE_REROUTABLE)
1464 ExCacheDDIInputs(p, n);
1465 }
1466 }
1467
1468 MARK_1("completing");
1469
1470 /*
1471 * For each output: if the function resulted in an error, mark our
1472 * outputs as coming from an error (warning if the Module returned
1473 * any outputs). else if the output was used, define the gvar and put
1474 * it in the cache. else the output wasn't used, delete it.
1475 */
1476 if (!dpSendOtherProc) for (i = 0; i < n->nout; ++i)
1477 {
1478 ip = FETCH_LIST(n->outputs, i);
1479 if (status == ERROR)
1480 {
1481 if (args[nin + 1 + i])
1482 DXWarning("#4700", n->name, i);
1483
1484 ip = FETCH_LIST(n->outputs, i);
1485 if (ip && *ip >= 0)
1486 {
1487 pv = FETCH_LIST(p->vars, *ip);
1488 if (pv == NULL)
1489 _dxf_ExDie("Executive Inconsistency: _execGnode 003");
1490 pv->gv->skip = GV_SKIPERROR;
1491 _dxf_ExDefineGvar(pv->gv, NULL);
1492 }
1493 }
1494 else /* if (status == OK) */
1495 {
1496 Class class = DXGetObjectClass(args[nin + 1 + i]);
1497 if (args[nin + 1 + i] != NULL &&
1498 ((int) class <= (int) CLASS_MIN ||
1499 (int) class >= (int) CLASS_MAX))
1500 {
1501 DXWarning("#4710", n->name, i);
1502 args[nin + 1 + i] = NULL;
1503 }
1504 cost = (double) n->endtime - n->starttime;
1505 if (ip && *ip >= 0)
1506 {
1507 pv = FETCH_LIST(p->vars, *ip);
1508 if (pv == NULL)
1509 _dxf_ExDie("Executive Inconsistency: _execGnode 002");
1510
1511 gv = pv->gv;
1512 gv->disable_cache = skipping;
1513
1514 _dxf_ExDefineGvar(gv, args[nin + 1 + i]);
1515 _dxf_ExSetGVarCost(gv, cost);
1516 DXSetObjectTag(gv->obj, gv->reccrc);
1517 if (_dxd_exCacheOn && !skipping)
1518 {
1519 if (pv->excache != CACHE_OFF && pv->cacheattr)
1520 ExCacheNewGvar(gv);
1521 else if (n->excache != CACHE_OFF &&
1522 (pv->excache != CACHE_OFF || !pv->cacheattr))
1523 ExCacheNewGvar(gv);
1524 }
1525 }
1526 else
1527 {
1528 DXReference(args[nin + 1 + i]);
1529 DXDelete(args[nin + 1 + i]);
1530 }
1531 }
1532 }
1533
1534 error_continue:;
1535 if (argsalloc > LOCAL_ARG_MAX)
1536 {
1537 DXFree((Pointer) args);
1538 args = NULL;
1539 argsalloc = 0;
1540 }
1541 }
1542 module_cleanup:
1543 ExDebug("*1", "At module_cleanup for %s ", _dxf_ExGFuncPathToString(n));
1544
1545 n->required = ALREADY_RUN;
1546 if((n->ftype == F_MACRO) && status == OK) {
1547 DECR_RUNABLE
1548 /* this is necessary when you have a main program with no */
1549 /* executable modules in it. */
1550 if(p->runable == 0 && p->deleted)
1551 ExStartModules(p);
1552 return OK;
1553 }
1554 /*
1555 * Delete inputs and outputs (outputs first), just in case someone passed
1556 * an input through unchanged. If the output was generated in error, don't
1557 * delete it (to be sure it sticks around for subsequent modules).
1558 */
1559 for (i = 0; i < n->nout; i++)
1560 {
1561 index = *FETCH_LIST(n->outputs, i);
1562 if (index > -1)
1563 {
1564 pv = FETCH_LIST(p->vars, index);
1565 if (!skipping && !pv->gv->skip && !pv->gv->disable_cache)
1566 {
1567 ExDelete(pv->gv);
1568 if (--pv->refs == 0) {
1569 pv->gv = NULL;
1570 ExDebug("*6","deleting %s output %d %d\n",
1571 _dxf_ExGFuncPathToString(n),i,index);
1572 }
1573 }
1574 if(!(n->flags & MODULE_PASSBACK))
1575 pv->required = NOT_REQUIRED;
1576 #ifdef CPV_DEBUG
1577 if (pv->refs > pv->gv->object.refs)
1578 printf("weird for deleted output pvar\n");
1579 #endif
1580 }
1581 }
1582 for (i = 0; i < n->nin; i++)
1583 {
1584 index = *FETCH_LIST(n->inputs, i);
1585 if (index > -1)
1586 {
1587 pv = FETCH_LIST(p->vars, index);
1588 ExDelete(pv->gv);
1589 if (--pv->refs == 0) {
1590 pv->gv = NULL;
1591 ExDebug("*6","deleting %s input %d %d\n",
1592 _dxf_ExGFuncPathToString(n),i,index);
1593 }
1594 #ifdef CPV_DEBUG
1595 if (pv->refs > pv->gv->object.refs)
1596 printf("weird for deleted input pvar\n");
1597 #endif
1598 }
1599 }
1600
1601 #ifdef CPV_DEBUG
1602 if (p->runable <= 0)
1603 printf("weird for p->runable\n");
1604 #endif
1605 DECR_RUNABLE
1606 #if 0
1607 if(p->runable == 0 && p->returnP && p->loopctl.done)
1608 ExCacheMacroResults(p->returnP);
1609 #endif
1610
1611 /* Kick off the next module(s) in the list, and clean up. */
1612 /* If we are skipping over a macro make sure we continue */
1613 /* with next module in this program. */
1614 if(n->ftype == F_MODULE || (n->ftype == F_MACRO && status == ERROR))
1615 ExStartModules(p);
1616
1617 MARK_1("done");
1618 return (OK);
1619 }
1620
1621
1622 static void
ExExecError(Program * p,gfunc * n,ErrorCode code,Error status)1623 ExExecError(Program *p, gfunc *n, ErrorCode code, Error status)
1624 {
1625 char buf[2048];
1626
1627 if (status != ERROR)
1628 DXWarning("#4720", p->graphId, _dxf_ExGFuncPathToString(n));
1629
1630 sprintf(buf, "%d::%s", p->graphId, _dxf_ExGFuncPathToString(n));
1631 DXPrintError(buf);
1632
1633 if (_dxf_ExVCRRunning())
1634 _dxf_ExVCRCommand(VCR_C_PAUSE, 0, 0);
1635
1636 p->error = TRUE;
1637 }
1638
1639 /*
1640 * get a new, unique graph identifier
1641 */
1642 int
_dxf_NextGraphId()1643 _dxf_NextGraphId()
1644 {
1645 int gid;
1646
1647 gid = ++(graph_id);
1648
1649 /* avoid wrapping around to 0 */
1650 if (gid == 0)
1651 gid = ++(graph_id);
1652
1653 return (gid);
1654 }
1655
1656 static void
ExFixConstantSwitch(Program * p)1657 ExFixConstantSwitch(Program *p)
1658 {
1659 int i, j, m, ilimit;
1660 gfunc *gf;
1661 ProgramVariable *pv;
1662
1663 /* Fix constant Switches */
1664 for (i = 0, ilimit = SIZE_LIST(p->funcs); i < ilimit; ++i)
1665 {
1666 gf = FETCH_LIST(p->funcs, i);
1667 if (IsSwitch(gf))
1668 {
1669 /* this will make computed switches have to run each time */
1670 /* through a loop, I think this is OK because they are quick */
1671 /* to calculate. The problem is to determine if the switch */
1672 /* value changed since the last iteration. Maybe I can be */
1673 /* smarter about this */
1674 if(!IsFastSwitch(gf)) {
1675 m = *FETCH_LIST(gf->outputs, 0);
1676 pv = FETCH_LIST(p->vars, m);
1677 if(pv->gv)
1678 _dxf_ExUndefineGvar(pv->gv);
1679 }
1680 /* if this is not the first time evaluating the switch */
1681 /* and it wasn't a FastSwitch the first time, then it */
1682 /* won't be a fast switch this time. */
1683 if(gf->required != NOT_SET && !IsFastSwitch(gf))
1684 continue;
1685 gf->flowtype &= ~FastSwitchFlag;
1686 m = *FETCH_LIST(gf->inputs, 0);
1687 if (m >= 0)
1688 {
1689 pv = FETCH_LIST(p->vars, m);
1690 if (pv->gv != NULL && pv->gv->type != GV_UNRESOLVED && !pv->gv->skip)
1691 {
1692 int sw, len;
1693 ProgramVariable *switchOvar;
1694 char bell[512];
1695 ModBeginMsg(p, gf, bell, &len);
1696 gf->flowtype |= FastSwitchFlag;
1697 if (pv->gv->obj == NULL)
1698 {
1699 if (pv->dflt)
1700 {
1701 if (DXExtractInteger(pv->dflt, &sw) == NULL)
1702 sw = 0;
1703 }
1704 else
1705 sw = 0;
1706 }
1707 else if (DXExtractInteger(pv->gv->obj, &sw) == NULL)
1708 {
1709 sw = 0;
1710 /* make this go through computed switch code to */
1711 /* produce an error. */
1712 gf->flowtype &= ~FastSwitchFlag;
1713 continue;
1714 }
1715
1716 if (sw > 0 && sw < gf->nin)
1717 {
1718 ProgramVariable *switchIvar;
1719 /* hook the output to the input */
1720 m = *FETCH_LIST(gf->outputs, 0);
1721 switchOvar = FETCH_LIST(p->vars, m);
1722 m = *FETCH_LIST(gf->inputs, sw);
1723 if (m < 0)
1724 {
1725 _dxf_ExDefineGvar(switchOvar->gv, NULL);
1726 ExReference(switchOvar->gv);
1727 switchOvar->refs++;
1728 }
1729 else
1730 {
1731 switchIvar = FETCH_LIST(p->vars, m);
1732 for (j = 0; j < switchOvar->refs; ++j)
1733 {
1734 ExReference(switchIvar->gv);
1735 ExDelete(switchOvar->gv);
1736 }
1737 ExReference(switchIvar->gv);
1738 ExReference(switchIvar->gv);
1739 switchOvar->gv = switchIvar->gv;
1740 switchIvar->refs++;
1741 switchOvar->refs++;
1742 }
1743 }
1744 else if (sw <= 0 || sw >= gf->nin)
1745 {
1746 /* define the output to be NULL. */
1747 m = *FETCH_LIST(gf->outputs, 0);
1748 switchOvar = FETCH_LIST(p->vars, m);
1749 _dxf_ExDefineGvar(switchOvar->gv, NULL);
1750 }
1751 ModEndMsg(p, bell, len);
1752 }
1753 }
1754 }
1755 }
1756 MARK_1("fix switches");
1757 }
1758
1759 /*
1760 * This routine determines if gf needs to be rerun, or is OK as is.
1761 * If this routine returns TRUE, then it marked another set of functions
1762 * as "required", and the graph has to be reevaluated. If it returns
1763 * FALSE, this gfunc is done.
1764 */
1765 static int
ExFixSwitchSelector(Program * p,gfunc * gf,int executionTime,int requiredFlag)1766 ExFixSwitchSelector(Program *p, gfunc *gf, int executionTime, int requiredFlag)
1767 {
1768 ProgramVariable *pv;
1769 int switchOut;
1770 int switchIn;
1771 int sw;
1772 int ret = FALSE;
1773 ProgramVariable *switchIvar;
1774 ProgramVariable *switchOvar;
1775 int i;
1776 int requiredWas;
1777
1778 /*
1779 * If this is not a computed switch,bind the correct input to its
1780 * output. If this is a computed switch, mark the 0th input to
1781 * the switch module as being required. Dependent modules will
1782 * be flagged at execution time (in execGnode) once the Switch
1783 * input is resolved.
1784 */
1785
1786 switchOut = *FETCH_LIST(gf->outputs, 0);
1787 switchOvar = FETCH_LIST(p->vars, switchOut);
1788 switchIn = *FETCH_LIST(gf->inputs, 0);
1789 pv = FETCH_LIST(p->vars, switchIn);
1790
1791 if (pv->gv == NULL)
1792 _dxf_ExDie("NULL gvar in ExFixSwitchSelector");
1793
1794 /*
1795 * if input selector (pv) is skipped, then set the skip
1796 * indicator in the output object as well
1797 */
1798 if (pv->gv->skip && switchOut >= 0)
1799 {
1800 DXDebug("*0", "Skipping [%08x] %d::%s", gf, p->graphId,
1801 _dxf_ExGFuncPathToString(gf));
1802 switchOvar->gv->skip = pv->gv->skip;
1803 if (pv->gv->disable_cache)
1804 switchOvar->gv->disable_cache = TRUE;
1805 _dxf_ExDefineGvar(switchOvar->gv, (Object) NULL);
1806 return(FALSE);
1807 }
1808
1809 /*
1810 * get the selector object. this if condition checks for all valid cases.
1811 */
1812 if (pv->gv->obj == NULL || DXExtractInteger(pv->gv->obj, &sw) != NULL)
1813 {
1814 if (pv->gv->obj == NULL)
1815 {
1816 if (pv->dflt == NULL ||
1817 DXExtractInteger(pv->dflt, &sw) == NULL)
1818 {
1819 sw = 0;
1820 }
1821 }
1822 if (sw <= 0 || sw >= gf->nin ||
1823 (switchIn = *FETCH_LIST(gf->inputs, sw)) < 0)
1824 {
1825 /* define the output as NULL, carrying on disable_cache value */
1826 ExDebug("*1", "Setting output to NULL in ExFixSwitchSelector");
1827
1828 if (pv->gv->disable_cache)
1829 switchOvar->gv->disable_cache = TRUE;
1830
1831 _dxf_ExDefineGvar(switchOvar->gv, (Object) NULL);
1832 ret = FALSE;
1833 }
1834 else
1835 {
1836 int fnbr = gf - p->funcs.vals;
1837 ExDebug("*1",
1838 "Setting output to input in ExFixSwitchSelector for %s",
1839 _dxf_ExGFuncPathToString(gf));
1840 switchIvar = FETCH_LIST(p->vars, switchIn);
1841 requiredWas = switchIvar->required;
1842 if (switchIvar->gv != NULL &&
1843 switchIvar->gv->type != GV_UNRESOLVED)
1844 {
1845 ret = FALSE; /* fixed the switch since a constant */
1846 if (pv->gv->disable_cache || switchIvar->gv->disable_cache)
1847 switchOvar->gv->disable_cache = TRUE;
1848 if (switchIvar->gv->skip)
1849 switchOvar->gv->skip = switchIvar->gv->skip;
1850 _dxf_ExDefineGvar(switchOvar->gv, switchIvar->gv->obj);
1851
1852 /* Mark switchIvar as potentially required */
1853 switchIvar->required = REQD_IFNOT_CACHED;
1854 for (i = fnbr - 1; i >= 0; --i)
1855 if (ExProcessGraphFunc(p, i, executionTime) &&
1856 ((p->first_skipped == -1 || p->first_skipped >= i)))
1857 p->first_skipped = i;
1858 }
1859 else
1860 {
1861 ret = TRUE; /* marked stuff required, rerun */
1862 /* Mark switchIvar as required */
1863 switchIvar->required = requiredFlag;
1864 for (i = fnbr - 1; i >= 0; --i)
1865 ExProcessGraphFunc(p, i, executionTime);
1866 }
1867 #ifdef CPV_DEBUG
1868 {
1869 gfunc *gf = FETCH_LIST(_dxd_exContext->program->funcs,fnbr);
1870 int i;
1871 for (i = 0; i < SIZE_LIST(gf->inputs); ++i)
1872 if (*FETCH_LIST(gf->inputs, i) == switchIn)
1873 printf("Send mark of input %d of %s required "
1874 "(0 based)\n",
1875 i, _dxf_ExGFuncPathToString(gf));
1876 }
1877 #endif
1878 if (requiredWas != switchIvar->required &&
1879 ExRunOnThisProcessor(gf->procgroupid))
1880 _dxf_ExSendPVRequired(p->graphId, p->subgraphId,
1881 fnbr, switchIn, switchIvar->required);
1882 }
1883 }
1884 else
1885 {
1886 /*
1887 * The only way we get to this code is if DXExtractInteger fails.
1888 */
1889 ExDebug("*1", "Switch selector is not in integer !!!");
1890 ExDebug("*1", "Setting output to NULL in ExFixSwitchSelector "
1891 "because of error");
1892
1893 ret = FALSE; /* ret OK since setting error... */
1894 _dxf_ExDefineGvar(switchOvar->gv, (Object) NULL);
1895 switchOvar->gv->skip = GV_SKIPERROR;
1896 DXSetError(ERROR_BAD_PARAMETER, "#10010", "switch value");
1897 ExExecError(p, gf, ERROR_BAD_PARAMETER, ERROR);
1898 }
1899 return (ret);
1900 }
1901 /*
1902 * This routine determines if gf needs to be rerun, or is OK as is.
1903 * If this routine returns TRUE, then it marked another set of functions
1904 * as "required", and the graph has to be reevaluated. If it returns
1905 * FALSE, this gfunc is done.
1906 */
1907 static int
ExFixRouteSelector(Program * p,gfunc * gf,int executionTime,int requiredFlag)1908 ExFixRouteSelector(Program * p, gfunc * gf, int executionTime, int requiredFlag)
1909 {
1910 ProgramVariable *pv;
1911 int switchOut;
1912 int switchIn;
1913 int single_route;
1914 int ret = FALSE;
1915 ProgramVariable *switchIvar;
1916 ProgramVariable *switchOvar;
1917 int i, ilimit;
1918 Object route_obj = NULL;
1919 int num_routeout;
1920 int *route_out = NULL;
1921 int output_kill[MAX_ROUTE_OUTPUTS];
1922 int fnbr;
1923 int mark_required = FALSE;
1924
1925 /*
1926 * If this is not a computed route, bind the correct input to its
1927 * output. If this is a computed switch, mark the 0th input to
1928 * the switch module as being required. Dependent modules will
1929 * be flagged at execution time (in execGnode) once the Route
1930 * input is resolved.
1931 */
1932
1933 switchIn = *FETCH_LIST(gf->inputs, 0);
1934 pv = FETCH_LIST(p->vars, switchIn);
1935
1936 if (pv->gv == NULL)
1937 _dxf_ExDie("NULL gvar in ExFixRouteSelector");
1938
1939 /*
1940 * if input selector (pv) is skipped, then set the skip
1941 * indicator in the output object as well
1942 */
1943 if (pv->gv->skip)
1944 {
1945 DXDebug("*0", "Skipping [%08x] %d::%s", gf, p->graphId,
1946 _dxf_ExGFuncPathToString(gf));
1947 for (i = 0, ilimit = SIZE_LIST(gf->outputs); i < ilimit; ++i)
1948 {
1949 switchOut = *FETCH_LIST(gf->outputs, i);
1950 if (switchOut >= 0)
1951 {
1952 switchOvar = FETCH_LIST(p->vars, switchOut);
1953 switchOvar->gv->skip = pv->gv->skip;
1954 if (pv->gv->disable_cache)
1955 switchOvar->gv->disable_cache = TRUE;
1956 _dxf_ExDefineGvar(switchOvar->gv, (Object) NULL);
1957 }
1958 }
1959 return(FALSE);
1960 }
1961
1962 for(i = 0; i < MAX_ROUTE_OUTPUTS; i++)
1963 output_kill[i] = TRUE;
1964
1965 if (pv->gv->obj == NULL)
1966 {
1967 if (pv->dflt == NULL)
1968 route_obj = NULL;
1969 else
1970 route_obj = pv->dflt;
1971 }
1972 else route_obj = pv->gv->obj;
1973
1974
1975 if (route_obj) {
1976 if (!DXQueryParameter(route_obj, TYPE_INT, 1, &num_routeout)) {
1977 DXSetError(ERROR_BAD_PARAMETER, "#10050", "Route selector");
1978 }
1979
1980 if (num_routeout <= 0) {
1981 DXSetError(ERROR_BAD_PARAMETER, "#10050", "Route selector");
1982 }
1983
1984 if(num_routeout == 1)
1985 route_out = &single_route;
1986 else
1987 route_out = (int *)DXAllocate(sizeof(int) * num_routeout);
1988 if(route_out == NULL)
1989 DXSetError(ERROR_NO_MEMORY, "#8360");
1990 else if (!DXExtractParameter(route_obj, TYPE_INT, 1,
1991 num_routeout, (Pointer)route_out)) {
1992 DXSetError(ERROR_BAD_PARAMETER, "#10050", "route selector");
1993 DXFree(route_out);
1994 route_out = NULL;
1995 }
1996 }
1997 else {
1998 num_routeout = 1;
1999 route_out = &single_route;
2000 *route_out = 0; /* all outputs will be shut off */
2001 }
2002
2003 if (route_out == NULL)
2004 {
2005 ExDebug("*1", "Setting output to NULL in ExFixRouteSelector "
2006 "because of error");
2007
2008 for (i = 0, ilimit = SIZE_LIST(gf->outputs); i < ilimit; ++i)
2009 {
2010 switchOut = *FETCH_LIST(gf->outputs, i);
2011 if (switchOut >= 0)
2012 {
2013 switchOvar = FETCH_LIST(p->vars, switchOut);
2014 switchOvar->gv->skip = GV_SKIPERROR;
2015 if (pv->gv->disable_cache)
2016 switchOvar->gv->disable_cache = TRUE;
2017 _dxf_ExDefineGvar(switchOvar->gv, (Object) NULL);
2018 }
2019 }
2020 ExExecError(p, gf, DXGetError(), ERROR);
2021 return(FALSE);
2022 }
2023
2024 if ((switchIn = *FETCH_LIST(gf->inputs, 1)) >= 0 ) {
2025 switchIvar = FETCH_LIST(p->vars, switchIn);
2026 for(i = 0; i < num_routeout; i++) {
2027 if(route_out[i] > 0 && route_out[i] <= gf->nout)
2028 output_kill[(route_out[i] - 1)] = FALSE;
2029 }
2030 }
2031 else
2032 switchIvar = NULL;
2033
2034 fnbr = gf - p->funcs.vals;
2035
2036 if (route_out[0] != 0 && (switchIvar->gv == NULL ||
2037 switchIvar->gv->type == GV_UNRESOLVED)) {
2038 ExDebug("*1", "In ExFixRouteSelector for %s, mark input 1 required",
2039 _dxf_ExGFuncPathToString(gf));
2040 /* Mark switchIvar as required */
2041 switchIvar->required = requiredFlag;
2042 for (i = fnbr - 1; i >= 0; --i)
2043 ExProcessGraphFunc(p, i, executionTime);
2044 if (ExRunOnThisProcessor(gf->procgroupid))
2045 _dxf_ExSendPVRequired(p->graphId, p->subgraphId, fnbr, switchIn,
2046 switchIvar->required);
2047 ret = TRUE;
2048 goto done;
2049 }
2050
2051 for (i = 0, ilimit = SIZE_LIST(gf->outputs); i < ilimit; ++i) {
2052 switchOut = *FETCH_LIST(gf->outputs, i);
2053 if(switchOut < 0)
2054 _dxf_ExDie("Route error: Can't get outputs for Route");
2055
2056 switchOvar = FETCH_LIST(p->vars, switchOut);
2057 if(output_kill[i]) {
2058 if (pv->gv->disable_cache ||
2059 (switchIvar && switchIvar->gv->disable_cache))
2060 switchOvar->gv->disable_cache = TRUE;
2061 if (switchIvar && switchIvar->gv->skip)
2062 switchOvar->gv->skip = switchIvar->gv->skip;
2063 else
2064 switchOvar->gv->skip = GV_SKIPROUTE;
2065 _dxf_ExDefineGvar(switchOvar->gv, (Object) NULL);
2066 }
2067 else {
2068 ExDebug("*1", "Setting output %d to input in ExFixRouteSelector "
2069 "for %s", i+1, _dxf_ExGFuncPathToString(gf));
2070 if (pv->gv->disable_cache || switchIvar->gv->disable_cache)
2071 switchOvar->gv->disable_cache = TRUE;
2072 else
2073 switchOvar->gv->disable_cache = FALSE;
2074 switchOvar->gv->skip = switchIvar->gv->skip;
2075 _dxf_ExDefineGvar(switchOvar->gv, switchIvar->gv->obj);
2076 mark_required = TRUE;
2077 }
2078 }
2079
2080 if(mark_required) {
2081 /* Mark switchIvar as potentially required */
2082 switchIvar->required = REQD_IFNOT_CACHED;
2083 for (i = fnbr - 1; i >= 0; --i)
2084 if (ExProcessGraphFunc(p, i, executionTime) &&
2085 ((p->first_skipped == -1 || p->first_skipped >= i)))
2086 p->first_skipped = i;
2087 if (ExRunOnThisProcessor(gf->procgroupid))
2088 _dxf_ExSendPVRequired(p->graphId, p->subgraphId, fnbr, switchIn,
2089 switchIvar->required);
2090 }
2091 ret = FALSE;
2092
2093 done:
2094 if(num_routeout > 1)
2095 DXFree(route_out);
2096 return(ret);
2097 }
2098
2099 static int
OKtoCache(ProgramVariable * pv,gfunc * gf)2100 OKtoCache(ProgramVariable *pv, gfunc *gf)
2101 {
2102 if (pv->excache == CACHE_OFF)
2103 return(FALSE);
2104 if (gf->excache == CACHE_OFF && !pv->cacheattr)
2105 return(FALSE);
2106 return(TRUE);
2107 }
2108
2109 /*
2110 * Search for all functs: If "SIDE_EFFECT" mark them as "required".
2111 * Mark their inputs as "required" if they aren't in the cache.
2112 * For all other modules except switches, cycle thru the outputs and
2113 * if they are required, mark their inputs as "required" if they aren't
2114 * in the cache.
2115 */
2116 static int
ExProcessGraphFunc(Program * p,int fnbr,int executionTime)2117 ExProcessGraphFunc(Program *p, int fnbr, int executionTime)
2118 {
2119 int index, i, j;
2120 int ilimit, jlimit;
2121 gfunc *gf;
2122 gvar *g;
2123 gvar *cachedGvar;
2124 int requiredFlag;
2125 int returnValue;
2126
2127 gf = FETCH_LIST(p->funcs, fnbr);
2128 if (!executionTime && ((gf->flags & MODULE_SIDE_EFFECT) ||
2129 (gf->nout == 0 && gf->tag_changed) ||
2130 (gf->flags & MODULE_LOOP)))
2131 {
2132 if (gf->required != REQUIRED && ExRunOnThisProcessor(gf->procgroupid))
2133 INCR_RUNABLE
2134 gf->required = REQUIRED;
2135 ExDebug("*1", "Marking func %s (# %d) as required ",
2136 _dxf_ExGFuncPathToString(gf), fnbr);
2137 for (j = 0, jlimit = SIZE_LIST(gf->inputs); j < jlimit; ++j)
2138 {
2139 index = *FETCH_LIST(gf->inputs, j);
2140 if (index != -1)
2141 {
2142 ProgramVariable *pv = FETCH_LIST(p->vars, index);
2143 if((gf->flags & MODULE_PASSBACK) && j != 0) {
2144 int out = *FETCH_LIST(gf->outputs, j-1);
2145 ProgramVariable *pv_out = FETCH_LIST(p->vars, out);
2146 if(pv_out->required == NOT_REQUIRED) {
2147 pv->required = NOT_REQUIRED;
2148 /* we have to mark the gv as skip otherwise the
2149 * module can't run at all. This works because it is
2150 * MODULE_ERR_CONT. */
2151 pv->gv->skip = GV_SKIPMACROEND;
2152 continue;
2153 }
2154 }
2155 g = pv->gv;
2156 if (pv->refs == 0 || !g)
2157 {
2158 pv->gv = _dxf_ExCreateGvar(GV_UNRESOLVED);
2159 ExReference(pv->gv);
2160 pv->refs++;
2161 #ifdef CPV_DEBUG
2162 if (pv->refs > pv->gv->object.refs)
2163 printf("weird for new in pvar\n");
2164 #endif
2165 pv->gv->reccrc = pv->reccrc;
2166 }
2167 else
2168 {
2169 if (g && g->type == GV_UNRESOLVED && _dxd_exCacheOn &&
2170 OKtoCache(pv, gf) &&
2171 (cachedGvar = _dxf_ExCacheSearch(pv->gv->reccrc)) != NULL)
2172 {
2173 _dxf_ExDefineGvar(pv->gv, cachedGvar->obj);
2174 ExDelete(cachedGvar);
2175 pv->required = REQD_IFNOT_CACHED;
2176 }
2177 else
2178 {
2179 pv->required = REQUIRED;
2180 ExDebug("*1", "Marking func %s input %d as required ",
2181 _dxf_ExGFuncPathToString(gf), j);
2182 }
2183 }
2184 }
2185 }
2186 return TRUE;
2187 } /* end of side-effect */
2188
2189 if (gf->required)
2190 {
2191 ExDebug("*1", "Func %s (# %d) already marked as %d",
2192 _dxf_ExGFuncPathToString(gf), fnbr, gf->required);
2193 if (gf->required == REQUIRED)
2194 return TRUE;
2195 else if (gf->required == RUNNING)
2196 return FALSE;
2197 }
2198
2199 /* Check to see if any outputs are required */
2200 requiredFlag = NOT_REQUIRED;
2201 returnValue = FALSE;
2202 for (j = 0, jlimit = SIZE_LIST(gf->outputs);
2203 j < jlimit && requiredFlag != REQUIRED;
2204 ++j)
2205 {
2206 index = *FETCH_LIST(gf->outputs, j);
2207 if (index != -1)
2208 {
2209 ProgramVariable *pv = FETCH_LIST(p->vars, index);
2210 if (pv->required)
2211 {
2212 if(pv->required == REQUIRED && pv->gv && pv->gv->skip == GV_SKIPMACROEND)
2213 pv->gv->skip = GV_DONTSKIP;
2214 for (i = 0, ilimit = SIZE_LIST(gf->outputs);
2215 i < ilimit;
2216 ++i)
2217 {
2218 index = *FETCH_LIST(gf->outputs, i);
2219 if (index != -1)
2220 {
2221 ProgramVariable *pv = FETCH_LIST(p->vars, index);
2222 g = pv->gv;
2223 if (pv->refs == 0 || !g)
2224 {
2225 pv->gv = _dxf_ExCreateGvar(GV_UNRESOLVED);
2226 ExReference(pv->gv);
2227 pv->refs++;
2228 pv->gv->reccrc = pv->reccrc;
2229 }
2230 }
2231 }
2232 /*
2233 * Check to see if this output (perhaps erroneously marked
2234 * required by the "Mark outputs" section) is in the cache
2235 */
2236 if (pv->required == REQUIRED)
2237 {
2238 if (pv->gv && pv->gv->type != GV_UNRESOLVED)
2239 {
2240 pv->required = REQD_IFNOT_CACHED;
2241 if (requiredFlag != REQUIRED)
2242 requiredFlag = REQD_IFNOT_CACHED;
2243 }
2244 else if (_dxd_exCacheOn && OKtoCache(pv, gf) &&
2245 (cachedGvar =
2246 _dxf_ExCacheSearch(pv->gv->reccrc)) != NULL)
2247 {
2248 pv->required = REQD_IFNOT_CACHED;
2249 if (requiredFlag != REQUIRED)
2250 requiredFlag = REQD_IFNOT_CACHED;
2251 ExDebug("*1",
2252 " output at index %d already cached for gfunc %s",
2253 index, _dxf_ExGFuncPathToString(gf));
2254 _dxf_ExDefineGvar(pv->gv, cachedGvar->obj);
2255 ExDelete(cachedGvar);
2256 }
2257 }
2258 if (gf->flags & MODULE_REACH && gf->required <= NOT_REQUIRED)
2259 requiredFlag = REQUIRED;
2260 else if (requiredFlag != REQUIRED)
2261 requiredFlag = pv->required;
2262 }
2263 }
2264 }
2265
2266 /* If any outputs were required */
2267 if (requiredFlag)
2268 {
2269 /* Ensure that all inputs have gvars */
2270 for (i = 0, ilimit = SIZE_LIST(gf->inputs);
2271 i < ilimit;
2272 ++i)
2273 {
2274 index = *FETCH_LIST(gf->inputs, i);
2275 if (index != -1)
2276 {
2277 ProgramVariable *pv = FETCH_LIST(p->vars, index);
2278 g = pv->gv;
2279 if (pv->refs == 0 || !g)
2280 {
2281 pv->gv = _dxf_ExCreateGvar(GV_UNRESOLVED);
2282 ExReference(pv->gv);
2283 pv->refs++;
2284 #ifdef CPV_DEBUG
2285 if (pv->refs > pv->gv->object.refs)
2286 printf("weird for new in pvar\n");
2287 #endif
2288 pv->gv->reccrc = pv->reccrc;
2289 }
2290 }
2291 }
2292
2293 /* Patch fast switches */
2294 if (IsFastSwitch(gf))
2295 {
2296 /* We know the next two conditionals will be true, but check
2297 * just the same */
2298 index = *FETCH_LIST(gf->inputs, 0);
2299 if (index != -1)
2300 {
2301 ProgramVariable *pv = FETCH_LIST(p->vars, index);
2302 if (pv->gv && pv->gv->type != GV_UNRESOLVED)
2303 {
2304 int sw;
2305 Object switch_obj;
2306
2307 if(pv->gv->obj == NULL)
2308 switch_obj = pv->dflt;
2309 else switch_obj = pv->gv->obj;
2310 if (DXExtractInteger(switch_obj, &sw) &&
2311 sw > 0 && sw < gf->nin)
2312 {
2313 index = *FETCH_LIST(gf->inputs, sw);
2314 if (index >= 0)
2315 {
2316 pv = FETCH_LIST(p->vars, index);
2317 if (pv->required != REQUIRED)
2318 pv->required = requiredFlag;
2319 }
2320 return FALSE;
2321 }
2322 }
2323 }
2324 }
2325
2326 /* If this module is really going to run here, update the program */
2327 if (requiredFlag == REQUIRED && gf->required != REQUIRED &&
2328 ExRunOnThisProcessor(gf->procgroupid))
2329 INCR_RUNABLE
2330 gf->required = requiredFlag;
2331 if (requiredFlag == REQUIRED)
2332 {
2333 returnValue = TRUE;
2334 ExDebug("*1", "Marking func %s (# %d) as REQUIRED",
2335 _dxf_ExGFuncPathToString(gf), fnbr);
2336 }
2337 else
2338 ExDebug("*1", "Marking func %s (# %d) as REQD_IFNOT_CACHED",
2339 _dxf_ExGFuncPathToString(gf), fnbr);
2340
2341 if (IsSwitch(gf) || IsRoute(gf))
2342 {
2343 /* if first input is unresolved, mark it as required,
2344 * else fix the switch
2345 */
2346 index = *FETCH_LIST(gf->inputs, 0);
2347 if (index != -1)
2348 {
2349 ProgramVariable *pv = FETCH_LIST(p->vars, index);
2350 g = pv->gv;
2351 if (requiredFlag == REQUIRED)
2352 {
2353 if (g->type != GV_UNRESOLVED)
2354 {
2355 if (pv->required != REQUIRED)
2356 pv->required = REQD_IFNOT_CACHED;
2357
2358 if (IsSwitch(gf) &&
2359 !ExFixSwitchSelector(p, gf, executionTime,
2360 requiredFlag))
2361 {
2362 gf->required = ALREADY_RUN;
2363 if (ExRunOnThisProcessor(gf->procgroupid))
2364 DECR_RUNABLE
2365 }
2366 else if (IsRoute(gf) &&
2367 !ExFixRouteSelector(p, gf, executionTime,
2368 requiredFlag))
2369 {
2370 gf->required = ALREADY_RUN;
2371 if (ExRunOnThisProcessor(gf->procgroupid))
2372 DECR_RUNABLE
2373 }
2374 }
2375 else if (_dxd_exCacheOn && OKtoCache(pv, gf) &&
2376 (cachedGvar =
2377 _dxf_ExCacheSearch(pv->gv->reccrc)) != NULL)
2378 {
2379 _dxf_ExDefineGvar(pv->gv, cachedGvar->obj);
2380 ExDelete(cachedGvar);
2381
2382 if (pv->required != REQUIRED)
2383 pv->required = REQD_IFNOT_CACHED;
2384
2385 if (IsSwitch(gf) &&
2386 !ExFixSwitchSelector(p, gf, executionTime,
2387 requiredFlag))
2388 {
2389 gf->required = ALREADY_RUN;
2390 if (ExRunOnThisProcessor(gf->procgroupid))
2391 DECR_RUNABLE
2392 }
2393 else if (IsRoute(gf) &&
2394 !ExFixRouteSelector(p, gf, executionTime,
2395 requiredFlag))
2396 {
2397 gf->required = ALREADY_RUN;
2398 if (ExRunOnThisProcessor(gf->procgroupid))
2399 DECR_RUNABLE
2400 }
2401 }
2402 else
2403 {
2404 if (pv->required != REQUIRED)
2405 pv->required = requiredFlag;
2406 }
2407 }
2408 else
2409 {
2410 if (pv->required != REQUIRED)
2411 pv->required = requiredFlag;
2412 }
2413 }
2414 }
2415 else
2416 {
2417 for (i = 0, ilimit = SIZE_LIST(gf->inputs);
2418 i < ilimit;
2419 ++i)
2420 {
2421 index = *FETCH_LIST(gf->inputs, i);
2422 if (index != -1)
2423 {
2424 ProgramVariable *pv = FETCH_LIST(p->vars, index);
2425 if((gf->flags & MODULE_PASSBACK) && j != 0) {
2426 int out = *FETCH_LIST(gf->outputs, j-1);
2427 ProgramVariable *pv_out = FETCH_LIST(p->vars, out);
2428 if(pv_out->required == NOT_REQUIRED) {
2429 pv->required = NOT_REQUIRED;
2430 /* we have to mark the gv as skip otherwise the
2431 * module can't run at all. This works because
2432 * it is MODULE_ERR_CONT. */
2433 pv->gv->skip = GV_SKIPMACROEND;
2434 continue;
2435 }
2436 }
2437 g = pv->gv;
2438 if (requiredFlag == REQUIRED)
2439 {
2440 if (g->type != GV_UNRESOLVED &&
2441 pv->required != REQUIRED)
2442 pv->required = REQD_IFNOT_CACHED;
2443 else if (_dxd_exCacheOn && OKtoCache(pv, gf) &&
2444 (cachedGvar =
2445 _dxf_ExCacheSearch(pv->gv->reccrc)) != NULL)
2446 {
2447 _dxf_ExDefineGvar(pv->gv, cachedGvar->obj);
2448 ExDelete(cachedGvar);
2449
2450 if (pv->required != REQUIRED)
2451 pv->required = REQD_IFNOT_CACHED;
2452 }
2453 else
2454 {
2455 if (pv->required != REQUIRED)
2456 pv->required = requiredFlag;
2457 }
2458 }
2459 else
2460 {
2461 if (pv->required != REQUIRED)
2462 pv->required = requiredFlag;
2463 }
2464 }
2465 } /* end of i (input) loop */
2466 }
2467 } /* end of output req'd cond */
2468 else {
2469 /* I believe this is to fix a problem with switches getting */
2470 /* defined as a constant switch the second time through a program */
2471 if(gf->required == NOT_SET)
2472 gf->required = NOT_REQUIRED;
2473 }
2474
2475 return returnValue;
2476 }
2477 /*----------------------------------------------------------------------*/
2478 /* For each required function in current program/graph, reference req'd */
2479 /* inputs and outputs. */
2480 /*----------------------------------------------------------------------*/
2481 static void
ExRefFuncIO(Program * p,int fnbr)2482 ExRefFuncIO(Program *p, int fnbr)
2483 {
2484 int j, jlimit;
2485 ProgramVariable *pv;
2486 gfunc *gf;
2487 int *var;
2488
2489 gf = FETCH_LIST(p->funcs, fnbr);
2490 if (gf == NULL)
2491 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 005");
2492 if (gf->required == REQUIRED)
2493 {
2494 for (j = 0, jlimit = SIZE_LIST(gf->inputs); j < jlimit; ++j)
2495 {
2496 var = FETCH_LIST(gf->inputs, j);
2497 if (var == NULL)
2498 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 006");
2499 if (*var != -1)
2500 {
2501 pv = FETCH_LIST(p->vars, *var);
2502 if (pv == NULL)
2503 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 007");
2504 if (pv->gv != NULL)
2505 {
2506 ExReference(pv->gv);
2507 pv->refs++;
2508 #ifdef CPV_DEBUG
2509 if (pv->refs > pv->gv->object.refs)
2510 printf("weird for input pvar\n");
2511 #endif
2512 }
2513 }
2514 }
2515 for (j = 0, jlimit = SIZE_LIST(gf->outputs); j < jlimit; ++j)
2516 {
2517 var = FETCH_LIST(gf->outputs, j);
2518 if (var == NULL)
2519 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 006");
2520 if (*var != -1)
2521 {
2522 pv = FETCH_LIST(p->vars, *var);
2523 if (pv == NULL)
2524 _dxf_ExDie("Executive Inconsistency: _dxf_ExQueueGraph 008");
2525 if (pv->gv != NULL)
2526 {
2527 ExReference(pv->gv);
2528 pv->refs++;
2529 /* Put an extra reference on outputs of side effect
2530 and async modules. Now that we can reclaim inter.
2531 results a Switch could cause something upstream to
2532 be run again because it was run once and then
2533 it's output was discarded because at the time it
2534 didn't seem like we would need it.
2535 */
2536 if(p->loopctl.first && (gf->flags &
2537 (MODULE_SIDE_EFFECT | MODULE_ASYNC | MODULE_ASYNCLOCAL))) {
2538 ExReference(pv->gv);
2539 pv->refs++;
2540 }
2541 #ifdef CPV_DEBUG
2542 if (pv->refs > pv->gv->object.refs)
2543 printf("weird for output pvar\n");
2544 #endif
2545 }
2546 }
2547 }
2548 } /* end of gf required */
2549 }
2550 /*-----------------------------------------------------------------*/
2551 /* For each input, get associated mdf input attributes */
2552 /* If the cache attribute is set to 2 for a given input, check to */
2553 /* see if it has changed from the previous iteration. If no inputs */
2554 /* with the cache:2 attribute have changed, simply reroute the */
2555 /* input(s) with the direroute:n attribute set through to the */
2556 /* output(s) identified by the value of the direroute attribute, */
2557 /* and mark the module as not needing scheduling (by returning */
2558 /* (FALSE). */
2559 /*-----------------------------------------------------------------*/
2560 static int
ExCheckDDI(Program * p,gfunc * gf)2561 ExCheckDDI(Program * p, gfunc * gf)
2562 {
2563 int i, ilimit;
2564 int *ip, *op, *input_p, *pvar_p;
2565 ReRouteMap *rmap;
2566 ProgramVariable *inpv, *outpv;
2567 int input_changed = FALSE;
2568 Object temp_obj, cached_obj;
2569 char *temp_str;
2570 int tmp;
2571 gvar *cachedGvar;
2572
2573 if(SIZE_LIST(gf->cache_ddi) == 0)
2574 input_changed = TRUE; /* force re-scheduling if no inputs with
2575 * cache attrs found */
2576
2577 for (i = 0, ilimit = SIZE_LIST(gf->cache_ddi); i < ilimit; ++i) {
2578 input_p = FETCH_LIST(gf->cache_ddi, i);
2579 if (!input_p || *input_p < 0)
2580 _dxf_ExDie(
2581 "Executive Inconsistency: _ExCheckDDI - bad index to variable");
2582
2583 pvar_p = FETCH_LIST(gf->inputs, *input_p);
2584 if (!pvar_p || *pvar_p < 0)
2585 _dxf_ExDie(
2586 "Executive Inconsistency: _ExCheckDDI bad index to variable");
2587
2588 inpv = FETCH_LIST(p->vars, *pvar_p);
2589 if (inpv == NULL)
2590 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 001");
2591
2592 ExDebug("8",
2593 "Checking cache in ExCheckDDI for obj with label/key: %s/%d",
2594 _dxf_ExGFuncPathToString(gf), *input_p);
2595
2596 if (inpv->gv && inpv->gv->obj != NULL) {
2597 cached_obj = inpv->gv->obj;
2598 ExDebug("8", " obj to be cached is inpv->gv->obj ");
2599 }
2600 else {
2601 if (inpv->obj != NULL)
2602 cached_obj = inpv->obj;
2603 else
2604 cached_obj = inpv->dflt;
2605 }
2606
2607 temp_obj = DXGetCacheEntry(_dxf_ExGFuncPathToCacheString(gf), *input_p, 0);
2608 if(!temp_obj) {
2609 ExDebug("8", "Input obj with label/key: %s/%d not found in cache",
2610 _dxf_ExGFuncPathToCacheString(gf), *input_p);
2611 input_changed = TRUE;
2612 break;
2613 }
2614 else
2615 DXDelete(temp_obj); /* we don't want an extra reference on this */
2616 if(temp_obj != cached_obj) {
2617 if(!cached_obj) {
2618 temp_str = DXGetString((String) temp_obj);
2619 if(temp_str && !strcmp(temp_str, "NULL"));
2620 continue;
2621 ExDebug("8", "Input obj with label/key: %s/%d changed",
2622 _dxf_ExGFuncPathToCacheString(gf), *input_p);
2623 }
2624 input_changed = TRUE;
2625 break;
2626 }
2627 }
2628
2629 /*
2630 * route input(s) thru appropriate output(s) as indicated by direroute
2631 * attr.
2632 * Value is stored in reroute_index
2633 */
2634 if (!input_changed) {
2635 for (i = 0, ilimit = SIZE_LIST(gf->reroute); i < ilimit; ++i) {
2636 rmap = FETCH_LIST(gf->reroute, i);
2637 if(rmap == NULL)
2638 _dxf_ExDie(
2639 "Executive Inconsistency: _ExCheckDDI - bad reroute information");
2640 op = FETCH_LIST(gf->outputs, rmap->output_n);
2641 if (op == NULL || *op < 0)
2642 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 002");
2643 outpv = FETCH_LIST(p->vars, *op);
2644 if (outpv == NULL)
2645 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 003");
2646 ip = FETCH_LIST(gf->inputs, rmap->input_n);
2647 if (ip == NULL || *ip < 0)
2648 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 004");
2649 inpv = FETCH_LIST(p->vars, *ip);
2650 if (inpv == NULL)
2651 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 005");
2652 /* is this possible ??? */
2653 if (inpv->gv && inpv->gv->type == GV_UNRESOLVED) {
2654 if(_dxd_exCacheOn && OKtoCache(inpv, gf) &&
2655 (cachedGvar = _dxf_ExCacheSearch(inpv->gv->reccrc)) != NULL) {
2656 ExDebug("8", "Routing input# %d thru output# %d",
2657 rmap->input_n, rmap->output_n);
2658 ExDebug("8", " (input gv unresolved)");
2659 _dxf_ExDefineGvar(outpv->gv, cachedGvar->obj);
2660 ExDelete(cachedGvar);
2661 }
2662 else {
2663 /* if we can't reroute output then we need to rerun */
2664 /* the module */
2665 input_changed = TRUE;
2666 }
2667 }
2668 else {
2669 if(rmap->output_n >= 0 && rmap->output_n < gf->nout) {
2670 _dxf_ExDefineGvar(outpv->gv, inpv->gv->obj);
2671 ExDebug("8",
2672 "Routing input# %d (obj %08x) w/ tag 0x%08x thru output# %d",
2673 rmap->input_n, outpv->gv->obj, outpv->gv->reccrc,
2674 rmap->output_n);
2675 DXExtractInteger(inpv->gv->obj, &tmp);
2676 ExDebug("8","Value of object being passed thru is %d", tmp);
2677 }
2678 else {
2679 /* pks 03/01/94 */
2680 /* this used to be FALSE but I can't imagine why! */
2681 input_changed = TRUE;
2682 }
2683 }
2684 }
2685 if(SIZE_LIST(gf->reroute) == 0) {
2686 /* need to retrieve last outputs from cache */
2687 for (i = 0, ilimit = SIZE_LIST(gf->outputs); i < ilimit; ++i) {
2688 op = FETCH_LIST(gf->outputs, i);
2689 if (op == NULL || *op < 0)
2690 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 002");
2691 outpv = FETCH_LIST(p->vars, *op);
2692 if (outpv == NULL)
2693 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 003");
2694 if(_dxd_exCacheOn && OKtoCache(outpv, gf) &&
2695 (cachedGvar = _dxf_ExCacheSearch(outpv->gv->reccrc))!=NULL) {
2696 ExDebug("8", "Routing output# %d from cache", i);
2697 _dxf_ExDefineGvar(outpv->gv, cachedGvar->obj);
2698 ExDelete(cachedGvar);
2699 }
2700 else {
2701 /* if we can't reroute output then we need to rerun */
2702 /* the module */
2703 input_changed = TRUE;
2704 }
2705 }
2706 } /* no reroute list */
2707 }
2708 else {
2709 /* input has changed, put an extra reference on rerouted outputs. */
2710 /* This fixes the problem of a DDI running twice in once execution */
2711 /* if its output was thrown out and later a switch needed its */
2712 /* output causing it to reexeute. */
2713 for (i = 0, ilimit = SIZE_LIST(gf->reroute); i < ilimit; ++i) {
2714 rmap = FETCH_LIST(gf->reroute, i);
2715 if(rmap == NULL)
2716 _dxf_ExDie(
2717 "Executive Inconsistency: _ExCheckDDI - bad reroute information");
2718 op = FETCH_LIST(gf->outputs, rmap->output_n);
2719 if (op == NULL || *op < 0)
2720 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 002");
2721 outpv = FETCH_LIST(p->vars, *op);
2722 if (outpv == NULL)
2723 _dxf_ExDie("Executive Inconsistency: _ExCheckDDI 003");
2724 ExReference(outpv->gv);
2725 outpv->refs++;
2726 }
2727 }
2728 return (input_changed); /* module scheduling required if input
2729 * changes exist */
2730 }
2731 static int
ExCacheDDIInputs(Program * p,gfunc * gf)2732 ExCacheDDIInputs(Program *p, gfunc *gf)
2733 {
2734 int i, ilimit;
2735 int *pvar_p, *input_p;
2736 ProgramVariable *inpv;
2737 Object cached_obj;
2738
2739 for (i = 0, ilimit = SIZE_LIST(gf->cache_ddi); i < ilimit; ++i) {
2740 input_p = FETCH_LIST(gf->cache_ddi, i);
2741 if (!input_p || *input_p < 0)
2742 _dxf_ExDie(
2743 "Executive Inconsistency: _ExCheckDDI - bad index to variable");
2744
2745 pvar_p = FETCH_LIST(gf->inputs, *input_p);
2746 if (!pvar_p || *pvar_p < 0)
2747 _dxf_ExDie(
2748 "Executive Inconsistency: _ExCheckDDI bad index to variable");
2749
2750 inpv = FETCH_LIST(p->vars, *pvar_p);
2751 if (inpv == NULL)
2752 _dxf_ExDie("Executive Inconsistency: _ExCacheDDI 001");
2753
2754 ExDebug("8",
2755 "Checking cache in ExCacheDDIInputs for obj with label/key: %s/%d",
2756 _dxf_ExGFuncPathToCacheString(gf), *input_p);
2757
2758 if (inpv->gv->obj != NULL) {
2759 cached_obj = inpv->gv->obj;
2760 ExDebug("8", " obj to be cached is inpv->gv->obj ");
2761 }
2762 else {
2763 if (inpv->obj != NULL)
2764 cached_obj = inpv->obj;
2765 else
2766 cached_obj = inpv->dflt;
2767 }
2768 if (!cached_obj)
2769 cached_obj = (Object) DXNewString("NULL");
2770
2771 if(!DXSetCacheEntry(cached_obj,CACHE_PERMANENT,
2772 _dxf_ExGFuncPathToCacheString(gf),*input_p,0))
2773 return (FALSE);
2774 }
2775 return (TRUE);
2776 }
2777 static void
ExDoPreExecPreparation(Program * p)2778 ExDoPreExecPreparation(Program *p)
2779 {
2780 int i, ilimit;
2781
2782 /*
2783 * If we're caching, we must leave the cache disabled until we've looked
2784 * up and referenced all function inputs
2785 */
2786
2787 if (_dxd_exCacheOn)
2788 _dxf_ExReclaimDisable();
2789
2790 /* For each required function, reference all inputs, and outputs */
2791 if (p->cursor == -1)
2792 ilimit = SIZE_LIST(p->funcs);
2793 else
2794 ilimit = p->cursor;
2795
2796 for (i = 0; i < ilimit; ++i)
2797 ExRefFuncIO(p, i);
2798
2799 if (_dxd_exCacheOn)
2800 _dxf_ExReclaimEnable();
2801
2802 MARK_1("ref inputs");
2803 }
2804 /*
2805 * Function to process DPSEND module - either passes input thru
2806 * to output if target module's process group is being run by the
2807 * same processor that is running the source module, or sends a msg
2808 * to the target processor that includes the required object and its
2809 * cache tag.
2810 * Module Inputs are:
2811 * tgprocid
2812 * srcprocid
2813 * tgfuncnbr
2814 * tginputnbr
2815 * inputobj
2816 */
2817 static int
ExProcessDPSENDFunction(Program * p,gfunc * gf,Object * DPSEND_obj)2818 ExProcessDPSENDFunction(Program *p, gfunc *gf, Object *DPSEND_obj)
2819 {
2820 ProgramVariable *pv, *inpv;
2821 int tgfuncnbr, tginputnbr;
2822 char *tgprocid = NULL;
2823 char *srcprocid = NULL;
2824 int index, outdex;
2825
2826 ExDebug("*1", "In ExProcessDPSENDFunction");
2827 index = *FETCH_LIST(gf->inputs, 0);
2828 pv = FETCH_LIST(p->vars, index);
2829 if (pv->gv != NULL && pv->gv->type != GV_UNRESOLVED && pv->gv->obj != NULL)
2830 {
2831 DXExtractString(pv->gv->obj, &tgprocid);
2832 ExDebug("*1", "tgprocid for gfunc %s is %s", _dxf_ExGFuncPathToCacheString(gf), tgprocid);
2833 }
2834 else
2835 ExDebug("*1", "tgprocid for gfunc %s is NULL or UNRESOLVED!!");
2836
2837 index = *FETCH_LIST(gf->inputs, 1);
2838 pv = FETCH_LIST(p->vars, index);
2839 if (pv->gv != NULL && pv->gv->type != GV_UNRESOLVED && pv->gv->obj != NULL)
2840 {
2841 DXExtractString(pv->gv->obj, &srcprocid);
2842 ExDebug("*1", "srcprocid for gfunc %s is %s", _dxf_ExGFuncPathToCacheString(gf), srcprocid);
2843 }
2844 else
2845 ExDebug("*1", "srcprocid for gfunc %s is NULL or UNRESOLVED!!");
2846
2847 index = *FETCH_LIST(gf->inputs, 2);
2848 pv = FETCH_LIST(p->vars, index);
2849 if (pv->gv != NULL && pv->gv->type != GV_UNRESOLVED && pv->gv->obj != NULL)
2850 {
2851 DXExtractInteger(pv->gv->obj, &tgfuncnbr);
2852 ExDebug("*1", "tgfuncnbr for gfunc %s is %d", _dxf_ExGFuncPathToCacheString(gf), tgfuncnbr);
2853 }
2854 else
2855 ExDebug("*1", "tgfuncnbr for gfunc %s is NULL or UNRESOLVED!!");
2856
2857 index = *FETCH_LIST(gf->inputs, 3);
2858 pv = FETCH_LIST(p->vars, index);
2859 if (pv->gv != NULL && pv->gv->type != GV_UNRESOLVED && pv->gv->obj != NULL)
2860 {
2861 DXExtractInteger(pv->gv->obj, &tginputnbr);
2862 ExDebug("*1", "tginputnbr for gfunc %s is %d", _dxf_ExGFuncPathToCacheString(gf), tginputnbr);
2863 }
2864 else
2865 ExDebug("*1", "tginputnbr for gfunc %s is NULL or UNRESOLVED!!");
2866
2867 /* Pass input object to output */
2868 index = *FETCH_LIST(gf->inputs, 4); /* input 4 is the object to be passed
2869 * to output */
2870 inpv = FETCH_LIST(p->vars, index);
2871 outdex = *FETCH_LIST(gf->outputs, 0); /* output 0 is the object to
2872 * be sent */
2873 pv = FETCH_LIST(p->vars, outdex);
2874 if (inpv->gv->skip)
2875 {
2876 ExDebug("*1", "DPSEND input object being passed thru is in error");
2877 }
2878 pv->gv->disable_cache = inpv->gv->disable_cache;
2879 pv->gv->skip = inpv->gv->skip;
2880 _dxf_ExDefineGvar(pv->gv, inpv->gv->obj); /* to send to target
2881 * processor */
2882 *DPSEND_obj = inpv->gv->obj;/* updates object array upon return */
2883
2884
2885 if (!ExRunOnThisProcessor(tgprocid)) {
2886 qsr_args *args;
2887 args = DXAllocate(sizeof(qsr_args));
2888 if(args == NULL)
2889 _dxf_ExDie("Can't allocate space to process distributed send");
2890 args->procid = tgprocid,
2891 args->pv = pv;
2892 args->index = outdex;
2893 _dxf_ExRunOn(1, QueueSendRequest, args, 0);
2894 DXFree(args);
2895 return(OK);
2896 }
2897
2898 return (FALSE);
2899 }
2900
QueueSendRequest(qsr_args * args)2901 static int QueueSendRequest(qsr_args *args)
2902 {
2903 char *host = NULL;
2904 int limit, k;
2905 char *procid = args->procid;
2906 ProgramVariable *pv = args->pv;
2907 int varindex = args->index;
2908 SlavePeers *spindex=NULL;
2909
2910 if (procid != NULL)
2911 host = _dxf_ExGVariableGetStr(procid);
2912 if (procid != NULL && host != NULL)
2913 {
2914 for (k = 0, limit = SIZE_LIST(_dxd_slavepeers); k < limit; ++k)
2915 {
2916 spindex = FETCH_LIST(_dxd_slavepeers, k);
2917 if (spindex->sfd >= 0 && !strcmp(spindex->peername, host))
2918 break;
2919 }
2920 } /* procid != NULL && host != NULL */
2921 else
2922 { /* should only get here if we are a slave */
2923 /* no process group assigned, assume this is running on master */
2924 /* master peer will always be first in table */
2925 spindex = FETCH_LIST(_dxd_slavepeers, 0);
2926 }
2927 _dxf_ExReqDPSend(pv, varindex, spindex);
2928 return (OK);
2929 }
2930
2931 /*--------------------------------------------------------------------*/
2932 /* Determines if this module should be running on this processor */
2933 /*--------------------------------------------------------------------*/
2934 static int
ExRunOnThisProcessor(char * procid)2935 ExRunOnThisProcessor(char *procid)
2936 {
2937 char *prochost = NULL;
2938 int i;
2939 dphosts *index, dphostent;
2940 int ret;
2941
2942 if(*_dxd_exBadFunc == TRUE && *_dxd_exKillGraph == TRUE)
2943 return(TRUE);
2944
2945 if(*_dxd_extoplevelloop) {
2946 if (_dxd_exRemoteSlave)
2947 return(FALSE);
2948 else return(TRUE);
2949 }
2950
2951 if (procid)
2952 prochost = _dxf_ExGVariableGetStr(procid);
2953 if (procid == NULL || prochost == NULL)
2954 {
2955 if (!_dxd_exRemoteSlave)
2956 {
2957 return (TRUE);
2958 }
2959 else
2960 {
2961 return (FALSE);
2962 }
2963 }
2964
2965 DXlock (&_dxd_dphostslock, 0);
2966
2967 for(i = 0; i < SIZE_LIST(*_dxd_dphosts); i++) {
2968 index = FETCH_LIST(*_dxd_dphosts, i);
2969 if(strcmp(index->name, prochost) == 0) {
2970 ret = index->islocal;
2971 DXunlock(&_dxd_dphostslock, 0);
2972 return(ret);
2973 }
2974 }
2975
2976 /* hostname not found in table, add it */
2977 dphostent.name = (char *)DXAllocate(strlen(prochost) + 1);
2978 strcpy(dphostent.name, prochost);
2979
2980 if((_dxd_exRemoteSlave && !strcmp(_dxd_exHostName, prochost))
2981 || (!_dxd_exRemoteSlave && _dxfHostIsLocal(prochost)))
2982 dphostent.islocal = TRUE;
2983 else
2984 dphostent.islocal = FALSE;
2985 APPEND_LIST(dphosts, *_dxd_dphosts, dphostent);
2986
2987 DXunlock(&_dxd_dphostslock, 0);
2988 return(dphostent.islocal);
2989 }
2990
2991 /*
2992 * Determines if all of module's inputs are available.
2993 * NRB: Unsure if following tests are accurate.
2994 */
2995 static int
ExCheckInputAvailability(Program * p,gfunc * n,int fnbr)2996 ExCheckInputAvailability(Program *p, gfunc *n, int fnbr)
2997 {
2998 int index, i;
2999 ProgramVariable *pv;
3000 gvar *gv;
3001 ProgramVariable *switchPv=NULL;
3002 int sw;
3003 int switchIn;
3004
3005 if (*_dxd_exKillGraph)
3006 return(TRUE);
3007
3008 for (i = 0; i < n->nin; i++)
3009 {
3010 index = *FETCH_LIST(n->inputs, i);
3011 if (index >= 0)
3012 {
3013 pv = FETCH_LIST(p->vars, index);
3014 gv = pv->gv;
3015 if ((IsRoute(n) || IsSwitch(n)) && i == 0)
3016 switchPv = pv;
3017 if (gv == NULL || (gv->skip && (n->flags & MODULE_ERR_CONT) != 0))
3018 continue;
3019 if ((pv->dflt == NULL || (pv->dflt != NULL && pv->is_output))
3020 && gv->type == GV_UNRESOLVED)
3021 {
3022 if (IsSwitch(n) && i > 0)
3023 {
3024 if (switchPv->gv)
3025 {
3026 if(switchPv->gv->obj == NULL)
3027 {
3028 if (switchPv->dflt)
3029 {
3030 if(DXExtractInteger(switchPv->dflt, &sw)== NULL)
3031 continue;
3032 }
3033 }
3034 else
3035 {
3036 if(DXExtractInteger(switchPv->gv->obj, &sw) == NULL)
3037 continue;
3038 }
3039 if (i != sw)
3040 continue;
3041 if (pv->required != REQUIRED)
3042 continue;
3043 }
3044 /* Otherwise, no inputs are required except the 0th */
3045 else
3046 continue;
3047 }
3048 if (IsRoute(n) && i > 0)
3049 {
3050 if (switchPv->gv)
3051 {
3052 if(switchPv->gv->obj == NULL)
3053 {
3054 if (switchPv->dflt)
3055 {
3056 if(DXExtractInteger(switchPv->dflt, &sw)== NULL)
3057 continue;
3058 }
3059 }
3060 else
3061 {
3062 if(DXExtractInteger(switchPv->gv->obj, &sw) == NULL)
3063 continue;
3064 }
3065 if (i <= 0 || i >= n->nout ||
3066 *FETCH_LIST(n->outputs,i) < 0)
3067 continue;
3068 switchIn = *FETCH_LIST(n->inputs, 1);
3069 if (switchIn < 0)
3070 continue;
3071 pv = FETCH_LIST(p->vars, switchIn);
3072 /* Otherwise, no inputs are required except the 0th */
3073 if (pv->required != REQUIRED)
3074 continue;
3075 }
3076 else
3077 continue;
3078 }
3079 if (p->first_skipped == -1 || p->first_skipped >= fnbr)
3080 p->first_skipped = fnbr;
3081 ExDebug("5",
3082 "Input %d at index %d for gfunc %s/%d not yet available",
3083 i, index, _dxf_ExGFuncPathToString(n), fnbr);
3084 return (FALSE);
3085 }
3086 }
3087 }
3088 return (TRUE);
3089 }
3090
3091 void
_dxf_ExMarkVarRequired(int gid,int sgid,int fnbr,int pvar,int requiredFlag)3092 _dxf_ExMarkVarRequired(int gid, int sgid, int fnbr, int pvar, int requiredFlag)
3093 {
3094 int i;
3095 ProgramVariable *pv;
3096 Program *subp;
3097
3098 if (_dxd_exContext->program == NULL)
3099 return;
3100 if (_dxd_exContext->program->graphId != gid)
3101 return;
3102
3103
3104 pv = FETCH_LIST(_dxd_exContext->program->vars, pvar);
3105 if (pv == NULL) {
3106 DXUIMessage("ERROR", "Missing variable in program");
3107 *_dxd_exKillGraph = TRUE;
3108 return;
3109 }
3110 if (pv->required == REQUIRED ||
3111 (pv->required == REQD_IFNOT_CACHED &&
3112 requiredFlag == REQD_IFNOT_CACHED))
3113 return;
3114
3115 pv->required = requiredFlag;
3116
3117 #ifdef CPV_DEBUG
3118 {
3119 gfunc *gf = FETCH_LIST(_dxd_exContext->program->funcs, fnbr);
3120 int i;
3121 for (i = 0; i < SIZE_LIST(gf->inputs); ++i)
3122 if (*FETCH_LIST(gf->inputs, i) == pvar)
3123 printf("Mark input %d of %s requires (0 based)\n",
3124 i, _dxf_ExGFuncPathToString(gf));
3125 }
3126 #endif
3127
3128 subp = _dxd_exContext->subp[sgid];
3129 /* if we haven't evaluated this macro yet just return */
3130 if(subp == NULL)
3131 return;
3132
3133 for (i = fnbr - 1; i >= 0; --i)
3134 ExProcessGraphFunc(subp, i, TRUE);
3135
3136 subp->cursor = -1;
3137 ExDoPreExecPreparation(subp);
3138 subp->outstandingRequests++;
3139 _dxf_ExRQEnqueue(_QueueableStartModulesReset,
3140 (Pointer) subp, 1, 0, 0, FALSE);
3141 }
3142
3143 int
_dxf_ExPrintProgram(Program * p)3144 _dxf_ExPrintProgram(Program *p)
3145 {
3146 int i;
3147 gfunc *gf;
3148 static char *reqnames[] =
3149 {"NOT_SET",
3150 "NOT_REQUIRED",
3151 "REQUIRED",
3152 "ALREADY_RUN",
3153 "REQD_IFNOT_CACHED",
3154 "RUNNING"};
3155 printf("%d Functions:\n", SIZE_LIST(p->funcs));
3156 for (i = 0; i < SIZE_LIST(p->funcs); ++i)
3157 {
3158 gf = FETCH_LIST(p->funcs, i);
3159 if(gf->ftype == F_MACRO && gf->func.subP) {
3160 printf("macro %s ", gf->name);
3161 _dxf_ExPrintProgram(gf->func.subP);
3162 }
3163 else
3164 printf(
3165 "%c%c %3d: %s: required: %s, procgroupid: %s, flags: 0x%08x\n",
3166 p->cursor+1 == i? '>': ' ',
3167 p->first_skipped != -1 && p->first_skipped == i? '*': ' ',
3168 i,
3169 _dxf_ExGFuncPathToString(gf),
3170 reqnames[gf->required+1],
3171 gf->procgroupid? gf->procgroupid: "(NULL)",
3172 gf->flags);
3173 }
3174 return (0);
3175 }
3176
3177 int
_dxf_ExPrintProgramIO(Program * p)3178 _dxf_ExPrintProgramIO(Program *p)
3179 {
3180 int i, j, index;
3181 gfunc *gf;
3182
3183 printf("%d Functions:\n", SIZE_LIST(p->funcs));
3184 for (i = 0; i < SIZE_LIST(p->funcs); ++i)
3185 {
3186 gf = FETCH_LIST(p->funcs, i);
3187 printf("%c%c %3d: %s: in: ",
3188 p->cursor+1 == i? '>': ' ',
3189 p->first_skipped != -1 && p->first_skipped == i? '*': ' ',
3190 i, _dxf_ExGFuncPathToString(gf));
3191 for (j = 0; j < SIZE_LIST(gf->inputs); ++j) {
3192 index = *FETCH_LIST(gf->inputs, j);
3193 if(index != -1) printf("%d ", index);
3194 }
3195 printf(" out: ");
3196 for (j = 0; j < SIZE_LIST(gf->outputs); ++j) {
3197 index = *FETCH_LIST(gf->outputs, j);
3198 if(index != -1) printf("%d ", index);
3199 }
3200 printf("\n");
3201 if(gf->ftype == F_MACRO && gf->func.subP) {
3202 printf("macro %s ", gf->name);
3203 _dxf_ExPrintProgramIO(gf->func.subP);
3204 }
3205 }
3206 return (0);
3207 }
3208
DXLoopDone(int done)3209 void DXLoopDone(int done)
3210 {
3211 if(done)
3212 _dxd_exContext->program->loopctl.isdoneset = TRUE;
3213 _dxd_exContext->program->loopctl.done = done;
3214 }
3215
DXLoopFirst()3216 int DXLoopFirst()
3217 {
3218 return(_dxd_exContext->program->loopctl.first);
3219 }
3220
DXSaveForId(char * modid)3221 void DXSaveForId(char *modid)
3222 {
3223 APPEND_LIST(char *, _dxd_exContext->program->foreach_id, modid);
3224 }
3225
ExCleanupForState()3226 static void ExCleanupForState()
3227 {
3228 int i;
3229 char *modid;
3230
3231 for(i = SIZE_LIST(_dxd_exContext->program->foreach_id) - 1; i >= 0; --i) {
3232 modid = *FETCH_LIST(_dxd_exContext->program->foreach_id, i);
3233 DXSetCacheEntryV(NULL, 0, modid, 0, 0, NULL);
3234 DXFree(modid);
3235 }
3236 FREE_LIST(_dxd_exContext->program->foreach_id);
3237 }
3238
_dxf_ExIsExecuting()3239 int _dxf_ExIsExecuting()
3240 {
3241 if (_dxd_exContext->program == NULL)
3242 return FALSE;
3243 else return TRUE;
3244 }
3245
DXPrintCurrentModule(char * string)3246 int DXPrintCurrentModule(char *string)
3247 {
3248 DXMessage("%s: %s", string, _dxf_ExGFuncPathToString(_dxd_exCurrentFunc));
3249 return (0);
3250 }
3251
3252