/***********************************************************************/ /* Open Visualization Data Explorer */ /* (C) Copyright IBM Corp. 1989,1999 */ /* ALL RIGHTS RESERVED */ /* This code licensed under the */ /* "IBM PUBLIC LICENSE - Open Visualization Data Explorer" */ /***********************************************************************/ #include #include #include #include "graph.h" #include "_variable.h" #include "vcr.h" #include "sysvars.h" #include "log.h" #include "packet.h" #include "rq.h" #include "distp.h" #define MIN(x,y) ((x) < (y)? (x): (y)) #define MAX(x,y) ((x) > (y)? (x): (y)) typedef enum { VCR_M_STOP = 0, VCR_M_PAUSE, VCR_M_STEP, VCR_M_PLAY } vcr_mode; typedef struct { lock_type lock; /* vcr semaphore */ int dir; /* current direction */ vcr_mode mode; /* play mode */ int loop; /* loop step/play */ int palin; /* palindrome step/play */ int flip; /* palindrome has flipped */ int steps; int ngraphs; /* number of outstanding graphs */ int graphId; /* Id of most recent graph */ int nframe; /* what we think next frame is */ struct node *tree; /* parse tree to execute */ Program *graph; int change; } _vcr; #define VCR_DEFAULT_START 1 #define VCR_DEFAULT_END 100 #define VCR_DEFAULT_DELTA 1 #define VCR_DEFAULT_NEXT VCR_DEFAULT_START #define VCR_DEFAULT_FRAME VCR_DEFAULT_START static _vcr *vcr = NULL; static EXDictionary vcr_dict; typedef struct { int s_frame; int e_frame; int n_frame; int d_frame; int c_frame; } VCRState; static VCRState now = { /* The frame that has a graph. */ VCR_DEFAULT_START, VCR_DEFAULT_END, VCR_DEFAULT_NEXT, VCR_DEFAULT_DELTA, VCR_DEFAULT_FRAME }; static VCRState old = { /* The frame that is currently running. */ VCR_DEFAULT_START, VCR_DEFAULT_END, VCR_DEFAULT_NEXT, VCR_DEFAULT_DELTA, VCR_DEFAULT_FRAME }; static VCRState prior = { /* The frame that's on the screen. */ VCR_DEFAULT_START, VCR_DEFAULT_END, VCR_DEFAULT_NEXT, VCR_DEFAULT_DELTA, VCR_DEFAULT_FRAME }; typedef struct { int comm; long arg1; int arg2; } VCRCommandTaskArg; /* * Externally visible functions. */ Error _dxf_ExInitVCR (EXDictionary dict); void _dxf_ExCleanupVCR (void); int _dxf_ExInitVCRVars (void); void _dxf_ExVCRCommand (int comm, long arg1, int arg2); /* * Static functions. */ static void ExVCRSet (char *var, int val); static int ExVCRGet (char *name); static void ExVCRLoad (void); static void ExVCRAdvance (void); /* * Extern functions. */ extern gvar *create_gvar (_gvtype type); /*************************************************************************/ /* * Top level initialization of the VCR by the executive. */ Error _dxf_ExInitVCR (EXDictionary dict) { int size; vcr_dict = dict; size = sizeof (_vcr); if (vcr) _dxf_ExCleanupVCR (); if ((vcr = (_vcr *) DXAllocate (size)) == NULL) return (ERROR); memset (vcr, NULL, size); if (DXcreate_lock (&vcr->lock, "vcr lock") != OK) { DXFree ((Pointer) vcr); vcr = NULL; return (ERROR); } _dxf_ExInitVCRVars (); vcr->change = TRUE; vcr->graph = NULL; return (OK); } /* * Cleanup function. */ void _dxf_ExCleanupVCR () { if (vcr == NULL) return; DXdestroy_lock (&vcr->lock); DXFree ((Pointer) vcr); vcr = NULL; } int _dxf_ExVCRRunning () { int ret; /* a quick out */ if (vcr->mode != VCR_M_STOP && vcr->mode != VCR_M_PAUSE) return (TRUE); if (! DXtry_lock (&vcr->lock, 0)) /* Someone else has it */ return (TRUE); /* now really make sure */ ret = (vcr->mode != VCR_M_STOP && vcr->mode != VCR_M_PAUSE); DXunlock (&vcr->lock, 0); return (ret); } int _dxf_ExVCRCallBack (int n) { vcr_mode mode; int ngraphs; DXlock (&vcr->lock, 0); ngraphs = --(vcr->ngraphs); mode = vcr->mode; ExDebug ("5", "_dxf_ExVCRCallBack,%d: if ngraphs(%d) == 0 && mode (%d) == %d or %d\n _dxf_ExSPack \"stop\"", __LINE__, ngraphs, mode, VCR_M_STOP, VCR_M_PAUSE); if ((ngraphs == 0) && (mode == VCR_M_STOP || mode == VCR_M_PAUSE)) { _dxf_ExSPack (PACK_INTERRUPT, n, "stop", 4); } DXunlock (&vcr->lock, 0); return (1); } /* * Resets the VCR and its associated variables back to its initial state. */ int _dxf_ExInitVCRVars () { /* Initialize the global variables used by the VCR */ ExVCRSet (VCR_ID_START, VCR_DEFAULT_START); ExVCRSet (VCR_ID_END, VCR_DEFAULT_END); ExVCRSet (VCR_ID_DELTA, VCR_DEFAULT_DELTA); ExVCRSet (VCR_ID_NEXT, VCR_DEFAULT_NEXT); ExVCRSet (VCR_ID_FRAME, VCR_DEFAULT_FRAME); /* Initialize the internal variables used by the VCR */ vcr->dir = VCR_D_FORWARD; vcr->mode = VCR_M_STOP; vcr->loop = FALSE; vcr->palin = FALSE; vcr->flip = FALSE; vcr->steps = 0; /* Clean up any prior incarnations */ if (vcr->tree) _dxf_ExPDestroyNode (vcr->tree); vcr->tree = NULL; return (OK); } /* * Sets a specific variable with the given integer value. */ static void ExVCRSet (char *var, int val) { gvar *gv; Array arr; GDictSend pkg; /* Make sure we remember what the next frame is */ if (! strcmp (var, VCR_ID_NEXT)) vcr->nframe = val; arr = DXNewArray (TYPE_INT, CATEGORY_REAL, 0); DXAddArrayData (arr, 0, 1, (Pointer) &val); gv = _dxf_ExCreateGvar (GV_UNRESOLVED); _dxf_ExDefineGvar(gv, (Object) arr); gv->cost = 1.0; _dxf_ExVariableInsert (var, vcr_dict, (EXO_Object) gv); _dxf_ExCreateGDictPkg(&pkg, var, gv); _dxf_ExDistributeMsg(DM_INSERTGDICT, (Pointer)&pkg, 0, TOSLAVES); } /* * Retrieves the specified value from the environment, converting it to * integer as necessary. */ static int ExVCRGet (char *var) { gvar *gv; Array arr; int val = 0; if ((gv = (gvar *) _dxf_ExVariableSearch (var, vcr_dict)) == NULL) return (0); arr = (Array) gv->obj; DXExtractInteger ((Object) arr, &val); ExDelete (gv); return (val); } /* * Loads the local copies of the VCR's frame variables from the environment. */ static void ExVCRLoad () { now.s_frame = ExVCRGet (VCR_ID_START); now.e_frame = ExVCRGet (VCR_ID_END); now.n_frame = ExVCRGet (VCR_ID_NEXT); now.d_frame = ExVCRGet (VCR_ID_DELTA); now.c_frame = now.n_frame; if (now.d_frame < 1) { now.d_frame = (now.d_frame == 0) ? 1 : - now.d_frame; ExVCRSet (VCR_ID_DELTA, now.d_frame); } now.n_frame = (now.n_frame < now.s_frame) ? now.s_frame : now.n_frame; now.n_frame = (now.n_frame > now.e_frame) ? now.e_frame : now.n_frame; } /* * Advances the VCR one frame */ static void ExVCRAdvance () { int n; n = now.n_frame + (now.d_frame * vcr->dir * (vcr->flip ? -1 : 1)); /* We are still within the valid region, this was a simple advance */ if (n >= now.s_frame && n <= now.e_frame) { now.n_frame = n; return; } /* Now we have to decide what to do based upon the state of the VCR */ if (n > now.e_frame) { if (vcr->loop) { if (vcr->palin) { vcr->flip = ! vcr->flip; n = now.n_frame + (now.d_frame * vcr->dir * (vcr->flip ? -1 : 1)); } else { n = now.s_frame; } } else /* no vcr->loop */ { if (vcr->palin) { if (vcr->flip) { vcr->flip = FALSE; vcr->mode = VCR_M_STOP; n = now.e_frame; } else { vcr->flip = ! vcr->flip; n = now.n_frame + (now.d_frame * vcr->dir * (vcr->flip ? -1 : 1)); } } else { n = now.s_frame; vcr->mode = VCR_M_STOP; } } } else /* n < now.s_frame */ { if (vcr->loop) { if (vcr->palin) { vcr->flip = ! vcr->flip; n = now.n_frame + (now.d_frame * vcr->dir * (vcr->flip ? -1 : 1)); } else { n = now.e_frame; } } else /* no vcr->loop */ { if (vcr->palin) { if (vcr->flip) { vcr->flip = FALSE; vcr->mode = VCR_M_STOP; n = now.s_frame; } else { vcr->flip = ! vcr->flip; n = now.n_frame + (now.d_frame * vcr->dir * (vcr->flip ? -1 : 1)); } } else { n = now.e_frame; vcr->mode = VCR_M_STOP; } } } now.n_frame = (n < now.s_frame) ? now.s_frame : ((n > now.e_frame) ? now.e_frame : n); return; } static int VCRCommandTask(Pointer pArg) { VCRCommandTaskArg *arg = (VCRCommandTaskArg*)pArg; _dxf_ExVCRCommand (arg->comm, arg->arg1, arg->arg2); DXFree (pArg); return (OK); } /* * VCR command interpreter. Sets the values of the VCR's internal data * structure. */ void _dxf_ExVCRCommand (int comm, long arg1, int arg2) { struct node *oldtree = NULL; vcr_mode mode; if (exJID != 1) { VCRCommandTaskArg *arg = (VCRCommandTaskArg *)DXAllocate (sizeof (VCRCommandTaskArg)); if (arg == NULL) _dxf_ExDie ("_dxf_ExVCRCommand: can't allocate"); arg->comm = comm; arg->arg1 = arg1; arg->arg2 = arg2; _dxf_ExRQEnqueue (VCRCommandTask, (Pointer) arg, 1, 0, 1, FALSE); return; } if (vcr == NULL) return; DXlock (&vcr->lock, 0); /* In most cases we want to delete the next graph that is queued */ /* because we are changing the VCR and the next graph to run */ /* will probably be different from the one currently running. */ /* This has a bad effect though if we are reading a script through */ /* stdin. At the end of the script we receive and EOF which will */ /* call VCRCommand to turn off looping. In this case we do not */ /* wish to delete the next graph element. */ if(! *_dxd_exTerminating) { if (vcr->graph != NULL) _dxf_ExGraphDelete (vcr->graph); vcr->graph = NULL; } /* The one that I want to advance past is the one on the screen. */ now = old; switch (comm) { case VCR_C_STOP: ExDebug ("1", "VCR VCR_C_STOP"); mode = vcr->mode; vcr->mode = VCR_M_STOP; vcr->flip = FALSE; vcr->steps = 0; if (mode != VCR_M_STOP && mode != VCR_M_PAUSE) { if (!_dxf_ExGQAllDone()) { _dxf_ExExecCommandStr ("kill"); ExDebug ("1", "Killing frame %d", old.c_frame); old = prior; } ExDebug ("5", "_dxf_ExVCRCommand,%d: if ngraphs(%d) == 0 _dxf_ExSPack \"stop\"", __LINE__, vcr->ngraphs); if (vcr->ngraphs == 0) { _dxf_ExSPack (PACK_INTERRUPT, vcr->graphId, "stop", 4); } now = old; ExVCRSet (VCR_ID_FRAME, now.c_frame); ExVCRSet (VCR_ID_NEXT, now.n_frame); } break; case VCR_C_PAUSE: ExDebug ("1", "VCR VCR_C_PAUSE"); mode = vcr->mode; vcr->mode = VCR_M_PAUSE; if (mode != VCR_M_STOP && mode != VCR_M_PAUSE) { if (!_dxf_ExGQAllDone()) { _dxf_ExExecCommandStr ("kill"); ExDebug ("1", "Killing frame %d", old.c_frame); old = prior; } ExDebug ("5", "_dxf_ExVCRCommand,%d: if ngraphs(%d) == 0 _dxf_ExSPack \"stop\"", __LINE__, vcr->ngraphs); if (vcr->ngraphs == 0) _dxf_ExSPack (PACK_INTERRUPT, vcr->graphId, "stop", 4); now = old; ExVCRSet (VCR_ID_FRAME, now.c_frame); ExVCRSet (VCR_ID_NEXT, now.n_frame); } break; case VCR_C_PLAY: if (! vcr->tree) break; ExDebug ("1", "VCR VCR_C_PLAY"); vcr->mode = VCR_M_PLAY; vcr->flip = FALSE; vcr->steps = 0; break; case VCR_C_STEP: if (! vcr->tree) break; ExDebug ("1", "VCR VCR_C_STEP"); mode = vcr->mode; vcr->steps += vcr->dir; vcr->mode = vcr->steps ? VCR_M_STEP : VCR_M_STOP; ExDebug ("5", "_dxf_ExVCRCommand,%d: if ngraphs(%d) == 0 && mode (%d) == %d or %d\n _dxf_ExSPack \"stop\"", __LINE__, vcr->ngraphs, mode, VCR_M_STOP, VCR_M_PAUSE); if (vcr->ngraphs == 0 && mode != VCR_M_STOP && mode != VCR_M_PAUSE) _dxf_ExSPack (PACK_INTERRUPT, vcr->graphId, "stop", 4); break; case VCR_C_DIR: ExDebug ("1", "VCR VCR_C_DIR"); if (vcr->dir == (int)arg1) break; vcr->dir = (int)arg1; /* vcr->flip = FALSE; */ /* * Only reposition the current position if the user hasn't * explicitly done it by changing @nextframe. */ ExVCRLoad (); if (vcr->nframe == now.n_frame) { ExVCRAdvance (); ExVCRAdvance (); ExVCRSet (VCR_ID_NEXT, now.n_frame); } break; case VCR_C_FLAG: ExDebug ("1", "VCR VCR_C_FLAG"); switch ((int)arg1) { case VCR_F_LOOP: vcr->loop = arg2; break; case VCR_F_PALIN: vcr->palin = arg2; if(vcr->flip) { vcr->flip = FALSE; /* * Only reposition the current position if the user * hasn't explicitly done it by changing @nextframe. */ ExVCRLoad (); if (vcr->nframe == now.n_frame) { ExVCRAdvance (); ExVCRAdvance (); ExVCRSet (VCR_ID_NEXT, now.n_frame); } } break; } break; case VCR_C_TREE: ExDebug ("1", "VCR VCR_C_TREE"); oldtree = vcr->tree; vcr->tree = (struct node *) arg1; break; } DXunlock (&vcr->lock, 0); if (oldtree) _dxf_ExPDestroyNode (oldtree); } void _dxf_ExVCRRedo(void) { if(_dxd_exRemoteSlave) { _dxf_ExDistributeMsg(DM_VCRREDO, NULL, 0, TOPEER0); return; } if (vcr == NULL || vcr->tree == NULL) return; if (vcr->graph != NULL) { _dxf_ExGraphDelete(vcr->graph); vcr->graph = NULL; } vcr->change = TRUE; } void _dxf_ExVCRChange(void) { if (vcr == NULL || vcr->tree == NULL) return; vcr->change = TRUE; } void _dxf_ExVCRChangeReset(void) { if (vcr == NULL || vcr->tree == NULL) return; vcr->change = FALSE; } int _dxf_ExCheckVCR (EXDictionary dict, int multiProc) { Program *graph; int doGraph; int ret; VCRState lastGraph; multiProc = TRUE; /* for debugging */ /* Early outs */ if (vcr == NULL) return (0); if (vcr->tree == NULL) return (0); if ((!multiProc || vcr->graph == NULL) && (vcr->mode == VCR_M_STOP || vcr->mode == VCR_M_PAUSE)) return (0); if (! DXtry_lock (&vcr->lock, 0)) /* Someone else has it */ return (0); if (vcr->mode != VCR_M_STOP && vcr->mode != VCR_M_PAUSE) { /* something still running */ if ((multiProc && vcr->graph == NULL) || (!multiProc && _dxf_ExGQAllDone ())) { ExVCRLoad (); /* Load vars from dict */ switch (vcr->mode) { case VCR_M_STEP: ExVCRAdvance (); vcr->steps += (vcr->steps < 0) ? 1 : -1; if (vcr->steps == 0) vcr->mode = VCR_M_STOP; break; case VCR_M_PLAY: ExVCRAdvance (); break; } doGraph = TRUE; } /* Else if they've changed something since the last graph, * incorporate the changes (and if they've changed @nextframe, chane * @frame and redo the graph. */ else if (multiProc && vcr->change) { lastGraph = now; ExVCRLoad(); /* If they changed anything, reset next and readvance * to make sure that everything is still OK. * If they changed "next", do the one they want. */ if (now.s_frame != lastGraph.s_frame || now.e_frame != lastGraph.e_frame || now.d_frame != lastGraph.d_frame || now.n_frame != lastGraph.c_frame) { if (now.n_frame == lastGraph.n_frame) now.n_frame = lastGraph.c_frame; now.c_frame = now.n_frame; switch (vcr->mode) { case VCR_M_STEP: ExVCRAdvance (); vcr->steps += (vcr->steps < 0) ? 1 : -1; if (vcr->steps == 0) vcr->mode = VCR_M_STOP; break; case VCR_M_PLAY: ExVCRAdvance (); break; } } doGraph = TRUE; if (vcr->graph != NULL) _dxf_ExGraphDelete (vcr->graph); vcr->graph = NULL; } else doGraph = FALSE; if (doGraph) { ExVCRSet (VCR_ID_FRAME, now.c_frame); ExVCRSet (VCR_ID_NEXT, now.n_frame); vcr->change = FALSE; _dxf_ExGraphInit (); if ((vcr->graph = graph = _dxf_ExGraph (vcr->tree)) != NULL) { graph->origin = GO_VCR; graph->vcr.frame = now.c_frame; graph->vcr.nframe = now.n_frame; graph->vcr.stop = (vcr->mode == VCR_M_STOP) ? TRUE : FALSE; } ExDebug ("1", "VCR Creating graph %x for frame %3d", graph, now.c_frame); } } /* If we have a graph to do, and there is none being done, do this * graph, and indicate that we're working on the old now, and we're * done with the old old. */ if (_dxf_ExGQAllDone() && vcr->graph) { vcr->ngraphs++; vcr->graphId = vcr->graph->graphId; /* we are the master, send a copy of the parse tree * to all slaves */ _dxf_ExSendParseTree(vcr->tree); _dxf_ExGQEnqueue (vcr->graph); ExDebug ("1", "VCR Enqueuing graph 0x%x for frame %3d", vcr->graph, now.c_frame); prior = old; old = now; vcr->graph = NULL; ret = TRUE; } else ret = FALSE; DXunlock (&vcr->lock, 0); return (ret); }