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