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 
9 #include <dxconfig.h>
10 
11 
12 #include <dx/dx.h>
13 #include "graphqueue.h"
14 #include "config.h"
15 #include "pmodflags.h"
16 #include "utils.h"
17 #include "log.h"
18 #include "packet.h"
19 #include "cache.h"
20 #include "_variable.h"
21 #include "evalgraph.h"
22 
23 typedef struct gq_elem
24 {
25     struct gq_elem	*next;		/* linked list of elements */
26     Program		*func;		/* root node of graph */
27 } gq_elem;
28 
29 static lock_type	*gq_sem;
30 static gq_elem		*gq_head;
31 static gq_elem		*gq_tail;
32 static gq_elem		**gq_curr;
33 static int		have_lock = 0;
34 
35 void	_dxf_ExGQPrint (char *s);
36 
37 #define	GQ_NULL(_x)	if (_x == NULL) return (ERROR);
38 
39 /*
40  * Initialize the structures and semaphores for the graph queue.
41  */
_dxf_ExGQInit(int nprocs)42 Error _dxf_ExGQInit (int nprocs)
43 {
44     if ((gq_sem = (lock_type *) DXAllocate (sizeof (lock_type))) == NULL)
45 	return (ERROR);
46 
47     if (DXcreate_lock (gq_sem, "graph queue") != OK)
48 	return (ERROR);
49 
50     gq_curr	= (gq_elem **) DXAllocate (sizeof (gq_elem *));
51 
52     GQ_NULL (gq_curr);
53 
54     gq_head = NULL;
55     gq_tail = NULL;
56 
57     *gq_curr = NULL;
58 
59     return (OK);
60 }
61 
62 /*
63  * Insert an entry into the graph queue.
64  */
_dxf_ExGQEnqueue(Program * func)65 void _dxf_ExGQEnqueue (Program *func)
66 {
67     gq_elem	*elem;
68 
69     if (func == NULL)
70 	return;
71 
72     if ((elem = (gq_elem *) DXAllocate (sizeof (gq_elem))) == NULL)
73 	_dxf_ExDie ("_dxf_ExGQEnqueue:  can't DXAllocate");
74 
75     elem->func  = func;
76     elem->next  = NULL;
77 
78     DXlock (gq_sem, 0);
79 
80 	if (gq_head)
81 	    (gq_tail)->next = elem;		/* add to end */
82 	else
83 	    gq_head = elem;			/* new list */
84 
85 	gq_tail = elem;
86 
87     DXunlock (gq_sem, 0);
88 
89     DXDebug ("*1", "[%08x] IN  to gq  %d", func, func->graphId);
90 }
91 
92 /*
93  * Remove the next entry from the graph queue if there is an available
94  * execution slot for it.  Also make note of any node which have the
95  * MODULE_SEQUENCED flag set and make sure that two of them don't fire
96  * at the same time.
97  */
98 
_dxf_ExGQDequeue()99 Program *_dxf_ExGQDequeue ()
100 {
101     gq_elem	*elem;
102     gq_elem	*tofree = NULL;
103     Program	*func;
104 
105     /*
106      * Quick outs.
107      */
108 
109     if (gq_head == NULL)
110 	return (NULL);
111 
112     /*
113      * Only bother doing this if we have an open graph slot
114      */
115 
116     if (*gq_curr != NULL && SIZE_LIST(gq_head->func->funcs) != 0)
117 	return (NULL);
118 
119     DXsyncmem ();
120 
121     if (! DXtry_lock (gq_sem, 0))
122 	return (NULL);
123 
124     /*
125      * Almost as quick outs
126      */
127 
128     if (((elem = gq_head) == NULL)	||	/* nothing to do	*/
129 	(*gq_curr != NULL &&
130 	    SIZE_LIST(gq_head->func->funcs) != 0)) /* someone slipped in */
131     {
132 	DXunlock (gq_sem, 0);
133 	return (NULL);
134     }
135 
136     gq_head = elem->next;
137 
138     if (gq_tail == elem)			/* last one */
139 	gq_tail = NULL;
140 
141     if (*gq_curr == NULL)
142 	*gq_curr = elem;
143     else
144 	tofree = elem;
145 
146     DXunlock (gq_sem, 0);
147 
148     /*
149      * This can be outside of the lock since we are the one who set it and
150      * everyone else is just reading it.
151      */
152 
153     func = elem->func;
154     if (tofree != 0)
155 	DXFree ((Pointer)tofree);
156 
157     if (func)
158 	DXDebug ("*1", "[%08x] OUT of gq  %d", func, func->graphId);
159 
160     if (SIZE_LIST(func->funcs) == 0) {
161 	ExMarkTime(8, "enq assign");
162     }
163     else {
164 	ExMarkTime(8, "enq module");
165     }
166 
167     return (func);
168 }
169 
170 /* return pointer to currently running program */
_dxf_ExGQCurrent()171 Program *_dxf_ExGQCurrent ()
172 {
173     if (*gq_curr == NULL)
174         return (NULL);
175     return((*gq_curr)->func);
176 }
177 
ExResetGraphKill()178 static void ExResetGraphKill ()
179 {
180     *_dxd_exKillGraph = FALSE;
181 }
182 
183 /*
184  * Called when a graph (program) has completed.  Blow the graph away and
185  * note that none is running. Slave will call this with NULL program,
186  * just delete current.
187  */
188 
_dxf_ExGQDecrement(Program * p)189 void _dxf_ExGQDecrement (Program *p)
190 {
191     Program     *delete = NULL;
192     Pointer     tofree  = NULL;
193     gq_elem     *curr   = NULL;
194     int         more    = FALSE;
195 
196     DXlock (gq_sem, 0);
197 
198     if ((*gq_curr == NULL) || (p && (*gq_curr)->func != p))
199     {
200 	DXunlock (gq_sem, 0);
201         if(p)
202 	{
203 	    if (p->runable > 0)
204 		p->deleted = TRUE;
205             else {
206                 /* only the master has to send a complete message to UI */
207                 if(!_dxd_exRemoteSlave)
208                     _dxf_ExSPack(PACK_COMPLETE, p->graphId, "Complete", 8);
209                 _dxf_ExGraphDelete (p);
210             }
211 	}
212 	return;
213     }
214     curr   = *gq_curr;
215 
216     /*
217      * Graph is complete, free it
218      */
219     ExMarkTime(8, "deq module");
220 
221     delete = curr->func;
222     tofree = (Pointer) curr;
223 
224     more = (gq_head != NULL) ? TRUE : FALSE;
225 
226 
227     if (delete->runable > 0)
228     {
229 	delete->deleted = TRUE;
230 	goto unlock;
231     }
232 
233     DXFree (tofree);
234 
235     /* Don't tell the user that his assignements are complete, but do
236      * tell the ui that the request was completed.
237      */
238     if (SIZE_LIST (delete->funcs) > 0)
239     {
240 	DXDebug ("*0", "graph %d completed", delete->graphId);
241     }
242     /* only the master has to send a complete message to UI */
243     if(!_dxd_exRemoteSlave)
244         _dxf_ExSPack (PACK_COMPLETE, delete->graphId, "Complete", 8);
245     _dxf_ExGraphDelete (delete);
246 
247     if (! more)
248 	ExResetGraphKill ();
249 unlock:
250     *gq_curr = NULL;
251     DXunlock (gq_sem, 0);
252 
253 }
254 
255 
256 /*
257  * Determine if the specified graph is executing.
258  */
259 int
_dxf_ExGQRunning(int graphId)260 _dxf_ExGQRunning (int graphId)
261 {
262     int		status;
263 
264     if (! have_lock)
265 	DXlock (gq_sem, 0);
266 
267     status = *gq_curr != NULL;
268 
269     if (! have_lock)
270 	DXunlock (gq_sem, 0);
271 
272     return (status);
273 }
274 
275 /*
276  * Determine if all graphs have completed execution
277  */
278 int
_dxf_ExGQAllDone(void)279 _dxf_ExGQAllDone (void)
280 {
281     int status;
282 
283     /*
284      * Avoid the lock if possible
285      */
286 
287     if (gq_head)
288 	return (FALSE);
289 
290     if (*gq_curr)
291 	return (FALSE);
292 
293     DXlock (gq_sem, 0);
294 
295     status = (*gq_curr == NULL	&&
296 	      (! gq_head));
297 
298     DXunlock (gq_sem, 0);
299 
300     return (status);
301 }
302 
303 
_dxf_ExGQPrint(char * s)304 void _dxf_ExGQPrint (char *s)
305 {
306     gq_elem	*e;
307 
308     printf ("%s: head = %p, tail = %p, Q = ", s, gq_head, gq_tail);
309     for (e = gq_head; e; e = e->next)
310 	printf ("%p ", e);
311     printf ("\n");
312 
313     printf ("curr = ");
314     printf ("%p ", *gq_curr);
315     printf ("\n");
316 }
317