In developing a C prototype in DX, I discovered that Rubbersheet
doesn't work with CallModule.  In 4.1.0 it just hangs.  Attached is a patch
to fix this bug.

     Some 50 other modules in this prototype worked fine, but Rubbersheet
didn't.  The reason is that Rubbersheet's task routine creates a sub task
group with new tasks, and libdx's incarnation of task.c was a bit broken
for handling this case.  It looks like libdx handled this scenario at some
point.

     At any rate, the attached patch is a minimalist fix to bring DXcallm's
task.c back in-line with what it "appears" the original intent was.  It
might be more robust and straightforward to rework this module so it
maintains a task group stack like dxexec's task.c, but I don't have the
time right now.

                           --------------------

     For those that use CallModule, I'll outline the problem.  For normal,
master task groups (top-level on the stack):

     - DXCreateTaskGroup clears out 'ti' (the ready-to-run task list),
       resets the number of unfinished tasks (undone) to 0, and resets the
       task group error status
     - DXAddTask slips new tasks onto 'lti' (master tasks to run later)
     - DXExecuteTaskGroup moves the master tasks from lti to ti and
       executes them

     For slave task groups (not top-level on the stack), several problems
occur.  Namely, DXCreateTaskGroup shouldn't reset undone to 0 (the master
task that creating this task group is still running) or the ready-to-run
master task list, and DXExecuteTaskGroup had forgotten how to recognize and
process slave tasks.

     To fix these problems, I've reworked the callm task logic to do what
it appears was originally intended.  That is:

     - DXCreateTaskGroup doesn't clear out all master tasks each time it
       executes.

       ...so now DXAddTask does what it was supposed to, adding "extra"
       tasks (tasks associated with a slave task group) to the
       ti->first / ti->last list, and incrementing the "undone" task count.

     - And with tweaks, DXExecuteTask group now again recognizes and deals
       with the presence of extra (slave) tasks added in a slave task group
       while a master task is executing.

-- 
Randall Hopper (mailto:[EMAIL PROTECTED])
EPA Scientific Visualization Center
US EPA MD/24 ERC-1A; RTP, NC 27711
--- src/exec/libdx/ORIG/task.c  Mon May 10 11:45:47 1999
+++ src/exec/libdx/task.c       Tue Aug  8 13:39:57 2000
@@ -172,6 +172,8 @@
            return NULL;
        if (!DXcreate_lock(&(ti->done_flag), "done flag"))
            return NULL;
+       if (!DXcreate_lock(&(ti->extra_lock), "extra tasks lock"))
+           return NULL;
 
        /* initialize them */
        DXlock(&(ti->done_flag), 0);    /* DXunlock to signal all tasks done */
@@ -181,12 +183,14 @@
        lti.alloc = 1000;
        lti.tasks = (struct task *)
            DXAllocateLocal(lti.alloc * sizeof(struct task));
+
+        /*  One-time initialization  */
+       ti->tasks = NULL;
+       ti->ntasks = 0;
+       ti->undone = 0;
     }
 
     /* initialize */
-    ti->tasks = NULL;
-    ti->ntasks = 0;
-    ti->undone = 0;
     ti->rc = OK;
 
     return OK;
@@ -338,6 +342,7 @@
 {
     static int been_here = 0, nopin = 0;
     int i;
+    int master;
 
     if (!been_here) {                  /* create workers */
 
@@ -387,29 +392,38 @@
 
     }
 
-    if (lti.ntasks==0)
-       return OK;
-
     DXMarkTime("start parallel");
 
-    /* sort the tasks and copy them to global memory */
-    tasksort(lti.tasks, lti.ntasks);
-    ti->tasks = (struct task *) DXAllocate(lti.ntasks * sizeof(struct task));
-    if (!ti->tasks)
-       return ERROR;
-    memcpy(ti->tasks, lti.tasks, lti.ntasks * sizeof(struct task));
-
-    ti->ntasks = lti.ntasks;           /* number of tasks */
-    ti->undone = lti.ntasks;           /* number of tasks not yet done */
-    lti.ntasks = 0;                    /* no more tasks here */
+    /* If master task group, sort the tasks and copy them to global memory */
+    if (lti.ntasks > 0) {
+       master = 1;
+       tasksort(lti.tasks, lti.ntasks);
+       ti->tasks = (struct task *) DXAllocate(lti.ntasks * sizeof(struct 
task));
+       if (!ti->tasks)
+           return ERROR;
+       memcpy(ti->tasks, lti.tasks, lti.ntasks * sizeof(struct task));
+       
+       ti->ntasks = lti.ntasks;        /* number of tasks */
+       ti->undone = lti.ntasks;        /* number of tasks not yet done */
+       lti.ntasks = 0;                 /* no more tasks here */
+    }
+    else if (ti->first)
+       master = 0;
+    else
+       return OK;                      /* No tasks to start  */
+
     DXunlock(&(ti->task_lock), 0);     /* start task execution */
-    while (ti->ntasks > 0) {           /* while there are tasks to be done, */
+    while (ti->ntasks > 0 || ti->first){/* while there are new tasks to 
start,*/
        one_task(0);                    /* do a task, but don't block */
        DXqflush();                     /* flush its messages, if any */
     }
-    DXlock(&(ti->done_flag), 0);               /* wait for all tasks done */
-    DXFree((Pointer)ti->tasks);                /* free allocated task storage 
*/
-    ti->tasks = NULL;                  /* just in case */
+
+    /*  If master, wait for all tasks to finish  */
+    if (master) {
+       DXlock(&(ti->done_flag), 0);    /* wait for all tasks done */
+       DXFree((Pointer)ti->tasks);     /* free allocated task storage */
+       ti->tasks = NULL;               /* just in case */
+    }
     DXMarkTime("end parallel");                /* timing */
     return ti->rc;                     /* return error if anyone failed */
 }    

Reply via email to