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(&ltime);  /* 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