Index: /trunk/Ohana/src/opihi/include/dvo1.h
===================================================================
--- /trunk/Ohana/src/opihi/include/dvo1.h	(revision 4683)
+++ /trunk/Ohana/src/opihi/include/dvo1.h	(revision 4684)
@@ -1,7 +1,3 @@
-# include "external.h"
-# include "shell.h"
-# include "dvomath.h"
-# include "convert.h"
-# include "display.h"
+# include "opihi.h"
 # include "data.h"
 
Index: /trunk/Ohana/src/opihi/include/pclient.h
===================================================================
--- /trunk/Ohana/src/opihi/include/pclient.h	(revision 4683)
+++ /trunk/Ohana/src/opihi/include/pclient.h	(revision 4684)
@@ -1,7 +1,3 @@
-# include "external.h"
-# include "shell.h"
-# include "dvomath.h"
-# include "convert.h"
-# include "display.h"
+# include "opihi.h"
 # include <sys/types.h>
 # include <sys/wait.h>
Index: /trunk/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 4683)
+++ /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 4684)
@@ -1,7 +1,3 @@
-# include "external.h"
-# include "shell.h"
-# include "dvomath.h"
-# include "convert.h"
-# include "display.h"
+# include "opihi.h"
 # include <sys/types.h>
 # include <sys/wait.h>
Index: /trunk/Ohana/src/opihi/include/scheduler.h
===================================================================
--- /trunk/Ohana/src/opihi/include/scheduler.h	(revision 4683)
+++ /trunk/Ohana/src/opihi/include/scheduler.h	(revision 4684)
@@ -1,7 +1,3 @@
-# include "external.h"
-# include "shell.h"
-# include "dvomath.h"
-# include "convert.h"
-# include "display.h"
+# include "opihi.h"
 # include <sys/types.h>
 # include <sys/wait.h>
@@ -11,4 +7,5 @@
   JOB_BUSY, 
   JOB_EXIT, 
+  JOB_HUNG,
   JOB_CRASH,
   JOB_PENDING,
@@ -113,30 +110,36 @@
 
 /* scheduler prototypes */
-void InitTasks ();
-void ListTasks ();
-Task *FindTask (char *name);
-Task *CreateTask (char *name);
-void SetCurrentTask (char *name);
-char *GetCurrentTask ();
-int DeleteTask (Task *task);
-Task *NextTask ();
-int TaskHash (char *input);
-int ShowTask (char *name);
+
 char *memstr (char *m1, char *m2, int n);
 
+void InitTasks ();
+Task *NextTask ();
+Task *FindTask (char *name);
+void ListTasks (int verbose);
+int ShowTask (char *name);
+int FreeTask (Task *task);
+Task *CreateTask (char *name);
+int ValidateTask (Task *task);
+int RegisterNewTask ();
+int DeleteNewTask ();
+Task *GetNewTask ();
+void SetTaskTimer (struct timeval *timer);
+double GetTaskTimer (struct timeval start);
+void InitTaskTimers ();
+int TaskHash (char *input);
+
+int NextJobID ();
+int InitJobIDs ();
+int FreeJobID (int ID);
+
+void InitJobs ();
 Job *NextJob ();
-void InitJobs ();
-int NextJobID ();
+Job *FindJob (int JobID);
 void ListJobs ();
-Job *FindJob (int JobID);
 Job *CreateJob (Task *task);
-void SetCurrentJob (char *name);
-char *GetCurrentJob ();
 int SubmitJob (Job *job);
 int CheckJob (Job *job);
 int DeleteJob (Job *job);
 void FreeJob (Job *job);
-void SetTaskTimer (struct timeval *timer);
-double GetTaskTimer (struct timeval start);
 
 int CheckJobs ();
Index: /trunk/Ohana/src/opihi/pantasks/CheckJobs.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/CheckJobs.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/CheckJobs.c	(revision 4684)
@@ -12,16 +12,5 @@
   while ((job = NextJob ()) != NULL) {
 
-    /* check for timeout - only local jobs timeout here */
-    if ((job[0].mode == JOB_LOCAL) && (GetTaskTimer(job[0].start) >= job[0].task[0].timeout_period)) {
-      if (VerboseMode()) fprintf (stderr, "timeout on %s\n", job[0].task[0].name);
-      /* run task[0].timeout macro, if it exists */
-      if (job[0].task[0].timeout != NULL) {
-	exec_loop (job[0].task[0].timeout);
-      }
-      DeleteJob (job);
-      continue;
-    }
-
-    /* check poll period (ready to run again?) */
+    /* check poll period (ready to ask for status?) */
     if (GetTaskTimer(job[0].last) < job[0].task[0].poll_period) continue;
 
@@ -74,4 +63,23 @@
     }
 
+    /* check for timeout - (local jobs only) 
+       we only check timeout after a poll (forces at least one poll)
+     */
+    if (job[0].mode == JOB_LOCAL) {
+      if (GetTaskTimer(job[0].start) < job[0].task[0].timeout_period) continue;
+      if (VerboseMode()) fprintf (stderr, "timeout on %s\n", job[0].task[0].name);
+      if (!KillLocalJob (job)) {
+	job[0].state = JOB_HUNG;
+	if (VerboseMode()) fprintf (stderr, "child process %d is hung, cannot kill\n", job[0].pid);
+	continue;
+      }
+      /* run task[0].timeout macro, if it exists */
+      if (job[0].task[0].timeout != NULL) {
+	exec_loop (job[0].task[0].timeout);
+      }
+      DeleteJob (job);
+      continue;
+    }
+
     /* reset polling clock */
     SetTaskTimer (&job[0].last);
@@ -79,2 +87,24 @@
   return (TRUE);
 }
+
+/* 
+
+  job / task timeline:
+
+  task:
+  0           exec     
+  start       create
+  task clock  new job
+
+  job:
+  0           1xpoll     2xpoll     3xpoll
+  start       check      check      check 
+  job clock   status     status     status
+
+  .           .          .          timeout
+                                    run
+				    timeout
+
+  must be at least one poll before timeout 
+  (timeout >= poll)
+*/
Index: /trunk/Ohana/src/opihi/pantasks/CheckTasks.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/CheckTasks.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/CheckTasks.c	(revision 4684)
@@ -19,6 +19,4 @@
     if (task[0].Nmax && (task[0].Njobs >= task[0].Nmax)) continue;
 
-    SetCurrentTask (task[0].name);
-
     /* ready to run? : run task.exec macro */
     if (task[0].exec != NULL) {
@@ -26,7 +24,4 @@
       if (!status) continue;
     }
-
-    /* is task valid?  check state of task.(argc, argv) */
-    /*** ADD CODE HERE ***/
 
     /* construct job from task */
Index: /trunk/Ohana/src/opihi/pantasks/ControllerOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/ControllerOps.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/ControllerOps.c	(revision 4684)
@@ -58,4 +58,5 @@
   if (p != NULL) {
     fprintf (stderr, "unknown job %d\n", job[0].pid);
+    FreeIOBuffer (&buffer);
     return (FALSE);
   }
@@ -384,3 +385,18 @@
 
 
+int KillControllerJob (Job *job) {
+
+  int status;
+  char cmd[128];
+  IOBuffer buffer;
+
+  sprintf (cmd, "kill %d", job[0].pid);
+  InitIOBuffer (&buffer, 0x100);
+  status = ControllerCommand (cmd, CONTROLLER_PROMPT, &buffer);
+
+  /** need to interpret output message & free things **/
+  FreeIOBuffer (&buffer);
+  return (TRUE);
+}
+
 /* memstr returns a view, not an allocated string : don't free */
Index: /trunk/Ohana/src/opihi/pantasks/JobIDOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/JobIDOps.c	(revision 4684)
+++ /trunk/Ohana/src/opihi/pantasks/JobIDOps.c	(revision 4684)
@@ -0,0 +1,40 @@
+# include "scheduler.h"
+
+# define MAX_N_JOBS 1000
+static char *JobIDList;
+static int   JobIDPtr;
+
+int InitJobIDs () {
+
+  JobIDPtr = 0;
+  ALLOCATE (JobIDList, char, MAX_N_JOBS);
+  bzero (JobIDList, MAX_N_JOBS*sizeof(char));
+  return (TRUE);
+}  
+
+/* return next unique ID, recycle every MAX_N_JOBS */
+int NextJobID () {
+
+  int Ntry;
+
+  JobIDPtr ++;
+  if (JobIDPtr >= MAX_N_JOBS) JobIDPtr = 0;
+
+  Ntry = 0;
+  while (JobIDList[JobIDPtr]) {
+    Ntry ++;
+    JobIDPtr ++;
+    if (JobIDPtr >= MAX_N_JOBS) JobIDPtr = 0;
+    if (Ntry == MAX_N_JOBS) return (-1);
+  }
+  JobIDList[JobIDPtr] = TRUE;
+  return (JobIDPtr);
+}
+
+int FreeJobID (int JobID) {
+
+  if (JobID < 0) return (FALSE);
+  if (JobID >= MAX_N_JOBS) return (FALSE);
+
+  JobIDList[JobID] = FALSE;
+}
Index: /trunk/Ohana/src/opihi/pantasks/JobOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/JobOps.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/JobOps.c	(revision 4684)
@@ -1,16 +1,18 @@
 # include "scheduler.h"
 
-# define MAX_N_JOBS 1000
-static char *JobIDList;
-static int   JobIDPtr = 0;
+static Job **jobs;
+static int   Njobs;
+static int   NJOBS;
 
-static char dot[] = ".";
+/* counter marking job being visited by the run loop */
+static int   ActiveJob;
 
-static Job *jobs;
-static int  Njobs;
-static int  NJOBS;
-
-static char *JobName = dot;
-static int   CurrentJob = 0;
+/* set up the jobs list */
+void InitJobs () {
+  NJOBS = 20;
+  Njobs = 0;
+  ALLOCATE (jobs, Job *, NJOBS);
+  ActiveJob = -1;
+}
 
 /* provide a mechanism to loop over the list of jobs */
@@ -19,52 +21,12 @@
   Job *job;
 
-  if (CurrentJob >= Njobs) {
-    CurrentJob = 0;
+  ActiveJob ++;
+  if (ActiveJob < 0) ActiveJob = 0;
+  if (ActiveJob >= Njobs) {
+    ActiveJob = -1;
     return (NULL);
   }
-
-  job = &jobs[CurrentJob];
-  CurrentJob ++;
+  job = jobs[ActiveJob];
   return (job);
-}
-
-void InitJobs () {
-  NJOBS = 20;
-  Njobs = 0;
-  ALLOCATE (jobs, Job, NJOBS);
-  JobName = dot;
-
-  ALLOCATE (JobIDList, char, MAX_N_JOBS);
-  bzero (JobIDList, MAX_N_JOBS*sizeof(char));
-}
-
-/* return next unique ID, recycle every MAX_N_JOBS */
-int NextJobID () {
-
-  int Ntry;
-
-  JobIDPtr ++;
-  if (JobIDPtr >= MAX_N_JOBS) JobIDPtr = 0;
-
-  Ntry = 0;
-  while (JobIDList[JobIDPtr]) {
-    Ntry ++;
-    JobIDPtr ++;
-    if (JobIDPtr >= MAX_N_JOBS) JobIDPtr = 0;
-    if (Ntry == MAX_N_JOBS) return (-1);
-  }
-  JobIDList[JobIDPtr] = TRUE;
-  return (JobIDPtr);
-}
-
-/* list known jobs */
-void ListJobs () {
-
-  int i;
-
-  for (i = 0; i < Njobs; i++) {
-    fprintf (stderr, "%d: %-15s %5d %20s (%x)\n", Njobs, jobs[i].task[0].name, jobs[i].JobID, jobs[i].argv[0], jobs[i].argv);
-  }
-  return;
 }
 
@@ -76,6 +38,6 @@
   /* return job with matching JobID */
   for (i = 0; i < Njobs; i++) {
-    if (jobs[i].JobID == JobID) {
-      return (&jobs[i]);
+    if (jobs[i][0].JobID == JobID) {
+      return (jobs[i]);
     }
   }
@@ -83,14 +45,33 @@
 }  
 
+/* list known jobs */
+void ListJobs () {
+
+  int i;
+
+  if (Njobs == 0) {
+    fprintf (stderr, "no defined jobs\n");
+    return;
+  }
+
+  for (i = 0; i < Njobs; i++) {
+    fprintf (stderr, "%d: %-15s %5d %20s (%x)\n", Njobs, jobs[i][0].task[0].name, jobs[i][0].JobID, jobs[i][0].argv[0], jobs[i][0].argv);
+  }
+  return;
+}
+
 /* make a new job from a task */
 Job *CreateJob (Task *task) {
   
   int i;
+  Job *job;
+  
+  ALLOCATE (job, Job, 1);
 
-  jobs[Njobs].JobID = NextJobID ();
-  jobs[Njobs].pid = 0;
-  jobs[Njobs].mode = JOB_LOCAL;
+  job[0].JobID = NextJobID ();
+  job[0].pid = 0;
+  job[0].mode = JOB_LOCAL;
   if (task[0].host != NULL) {
-    jobs[Njobs].mode = JOB_CONTROLLER;
+    job[0].mode = JOB_CONTROLLER;
   }
 
@@ -99,10 +80,10 @@
    *  we allocate one extra element, with value 0 to be passed to execvp
    */
-  jobs[Njobs].argc = task[0].argc;
-  ALLOCATE (jobs[Njobs].argv, char *, MAX (task[0].argc + 1, 1));
+  job[0].argc = task[0].argc;
+  ALLOCATE (job[0].argv, char *, MAX (task[0].argc + 1, 1));
   for (i = 0; i < task[0].argc; i++) {
-    jobs[Njobs].argv[i] = strcreate (task[0].argv[i]);
+    job[0].argv[i] = strcreate (task[0].argv[i]);
   }
-  jobs[Njobs].argv[i] = 0;
+  job[0].argv[i] = 0;
 
   /* other data from the task is needed by the job 
@@ -111,5 +92,5 @@
      be applied to the existing jobs */
 
-  jobs[Njobs].task = task;
+  job[0].task = task;
   
   /* if we decide we need to be able to dynamically set task qualities
@@ -117,10 +98,11 @@
      entries to these quantites in the job structure */
 
+  jobs[Njobs] = job;
   Njobs ++;
   if (Njobs == NJOBS) {
     NJOBS += 20;
-    REALLOCATE (jobs, Job, NJOBS);
+    REALLOCATE (jobs, Job *, NJOBS);
   }
-  return (&jobs[Njobs-1]);
+  return (jobs[Njobs-1]);
 }
 
@@ -130,8 +112,6 @@
 
   if (job == NULL) return;
-
-  if ((job[0].JobID >= 0) || (job[0].JobID < MAX_N_JOBS)) {
-    JobIDList[job[0].JobID] = FALSE;
-  }
+  
+  FreeJobID (job[0].JobID);
 
   for (i = 0; i < job[0].argc; i++) {
@@ -142,12 +122,5 @@
 }
 
-void SetCurrentJob (char *name) {
-  JobName = name;
-}
-
-char *GetCurrentJob () {
-  return (JobName);
-}
-
+/** are we deleting the active job?? **/
 int DeleteJob (Job *job) {
 
@@ -156,5 +129,5 @@
   Nm = -1;
   for (i = 0; i < Njobs; i++) {
-    if (job == &jobs[i]) {
+    if (job == jobs[i]) {
       Nm = i;
       break;
@@ -166,12 +139,13 @@
   }
 
-  FreeJob (&jobs[Nm]);
+  FreeJob (jobs[Nm]);
   for (i = Nm + 1; i < Njobs; i++)
     jobs[i - 1] = jobs[i];
   Njobs --;
 
-  CurrentJob --;
-  CurrentJob = MAX (CurrentJob, 0);
-
+  /* adjust active job number */
+  if (ActiveJob >= Nm) {
+    ActiveJob --;
+  }
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/pantasks/LocalJob.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/LocalJob.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/LocalJob.c	(revision 4684)
@@ -102,4 +102,6 @@
   int result, waitstatus;
 
+  fprintf (stderr, "checking on %d\n", job[0].pid);
+
   /* check local job status */
   result = waitpid (job[0].pid, &waitstatus, WNOHANG);
@@ -135,4 +137,5 @@
 	exit (1);
       }
+      fprintf (stderr, "waited for %d\n", result);
       
       if (WIFEXITED(waitstatus)) {
@@ -151,2 +154,31 @@
   return;
 }
+
+int KillLocalJob (Job *job) {
+
+  int i, result, waitstatus;
+
+  if (job[0].state != JOB_BUSY) return (TRUE);
+
+  /* send SIGTERM signal to job */
+  kill (job[0].pid, SIGTERM);
+  result = 0;
+  for (i = 0; (i < 10) && (result == 0); i++) {
+    usleep (10000);  /* 10 ms is min */
+    result = waitpid (job[0].pid, &waitstatus, WNOHANG);
+  }
+  if (result) return (TRUE);
+
+  /* send SIGKILL signal to job */
+  kill (job[0].pid, SIGKILL);
+  result = 0;
+  for (i = 0; (i < 10) && (result == 0); i++) {
+    usleep (10000);  /* 10 ms is min */
+    result = waitpid (job[0].pid, &waitstatus, WNOHANG);
+  }
+  if (result) return (TRUE);
+
+  /* total failure, don't reset */
+  return (FALSE);
+}
+
Index: /trunk/Ohana/src/opihi/pantasks/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 4684)
@@ -35,4 +35,5 @@
 $(SDIR)/LocalJob.$(ARCH).o \
 $(SDIR)/JobOps.$(ARCH).o \
+$(SDIR)/JobIDOps.$(ARCH).o \
 $(SDIR)/TaskOps.$(ARCH).o \
 $(SDIR)/IOBufferOps.$(ARCH).o \
Index: /trunk/Ohana/src/opihi/pantasks/TaskOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/TaskOps.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/TaskOps.c	(revision 4684)
@@ -1,44 +1,66 @@
-# include "opihi.h"
 # include "scheduler.h"
 
-static char dot[] = ".";
-
-static Task *tasks;
-static int   Ntasks;
-static int   NTASKS;
-
-static char *TaskName = dot;
-
-static int   CurrentTask = 0;
-
-/* provide a mechanism to loop over the list of tasks */
-Task *NextTask () {
-  
-  Task *task;
-
-  if (CurrentTask >= Ntasks) {
-    CurrentTask = 0;
-    return (NULL);
-  }
-
-  task = &tasks[CurrentTask];
-  CurrentTask ++;
-  return (task);
-}
-
+static Task **tasks;
+static int    Ntasks;
+static int    NTASKS;
+
+/* counter marking task being visited by the run loop */
+static int   ActiveTask;
+
+/* temporary holder for a new task */
+static Task *NewTask = NULL;
+
+/* set up the task list system */
 void InitTasks () {
   NTASKS = 20;
   Ntasks = 0;
-  ALLOCATE (tasks, Task, NTASKS);
-  TaskName = dot;
-}
+  ALLOCATE (tasks, Task *, NTASKS);
+  ActiveTask = -1;
+}
+
+/* provide a mechanism to loop over the list of tasks */
+Task *NextTask () {
+  
+  Task *task;
+
+  /* move to the next task and return it */
+  ActiveTask ++;
+  if (ActiveTask < 0) ActiveTask = 0;
+  if (ActiveTask >= Ntasks) {
+    ActiveTask = -1;
+    return (NULL);
+  }
+  task = tasks[ActiveTask];
+  return (task);
+}
+
+/* return task with given name */
+Task *FindTask (char *name) {
+
+  int i;
+
+  /* try for an exact match first */
+  for (i = 0; i < Ntasks; i++) {
+    if (!strcmp (tasks[i][0].name, name)) {
+      return (tasks[i]);
+    }
+  }
+  return (NULL);
+}  
 
 /* list known tasks */
-void ListTasks () {
+void ListTasks (int verbose) {
 
   int i, valid;
 
+  if (Ntasks == 0) {
+    fprintf (stderr, "no defined tasks\n");
+    return;
+  }
+
+  fprintf (stderr, "Task Status\n");
+  fprintf (stderr, "  name            Njobs  command\n");
   for (i = 0; i < Ntasks; i++) {
-    valid = CheckTimeRanges (tasks[i].ranges, tasks[i].Nranges);
+    valid = CheckTimeRanges (tasks[i][0].ranges, tasks[i][0].Nranges);
     if (valid) {
       fprintf (stderr, "+ ");
@@ -46,5 +68,18 @@
       fprintf (stderr, "- ");
     }
-    fprintf (stderr, "%-15s %4d %20s\n", tasks[i].name, tasks[i].Njobs, tasks[i].argv[0]);
+    fprintf (stderr, "%-15s %4d   %-20s\n", tasks[i][0].name, tasks[i][0].Njobs, tasks[i][0].argv[0]);
+    if (verbose) {
+      fprintf (stderr, "    spawn period: %f, polling period: %f, timeout period: %f\n", 
+	       tasks[i][0].poll_period, tasks[i][0].poll_period, tasks[i][0].poll_period);
+      if (tasks[i][0].host != NULL) {
+	if (tasks[i][0].host_required) {
+	  fprintf (stderr, "    host %s (required)\n", tasks[i][0].host);
+	} else {
+	  fprintf (stderr, "    host %s (desired)\n", tasks[i][0].host);
+	}
+      } else {
+	fprintf (stderr, "    task runs locally\n");
+      }      
+    }
   }
   return;
@@ -94,65 +129,126 @@
 }
 
-/* return task with given name */
-Task *FindTask (char *name) {
-
+/* make a new named task */
+int FreeTask (Task *task) {
+  
   int i;
 
-  /* try for an exact match first */
-  for (i = 0; i < Ntasks; i++) {
-    if (!strcmp (tasks[i].name, name)) {
-      return (&tasks[i]);
-    }
-  }
-  return (NULL);
-}  
+  if (task == NULL) return (FALSE);
+  
+  if (task[0].name != NULL) free (task[0].name);
+  if (task[0].host != NULL) free (task[0].host);
+  if (task[0].argv != NULL) {
+    for (i = 0; i < task[0].argc; i++) {
+      free (task[0].argv[i]);
+    }
+    free (task[0].argv);
+  }
+  if (task[0].exec != NULL) {
+    FreeMacro (task[0].exec);
+    free (task[0].exec);
+  }
+  if (task[0].crash != NULL) {
+    FreeMacro (task[0].crash);
+    free (task[0].crash);
+  }
+  if (task[0].timeout != NULL) {
+    FreeMacro (task[0].timeout);
+    free (task[0].timeout);
+  }
+  for (i = 0; i < task[0].Nexit; i++) {
+    if (task[0].exit[i] != NULL) {
+      FreeMacro (task[0].exit[i]);
+    }
+    free (task[0].exit[i]);
+  }
+  free (task[0].exit);
+
+  if (task[0].ranges != NULL) {
+    free (task[0].ranges);
+  }
+  return (TRUE);
+}
+
+/**** new task functions ***/
 
 /* make a new named task */
 Task *CreateTask (char *name) {
   
-  tasks[Ntasks].name = strcreate (name);;
-
-  tasks[Ntasks].host = NULL;
-  tasks[Ntasks].host_required = FALSE;
-
-  tasks[Ntasks].argc = 0;
-  tasks[Ntasks].argv = NULL;
-
-  tasks[Ntasks].exec = NULL;
-  tasks[Ntasks].crash = NULL;
-  tasks[Ntasks].timeout = NULL;
-
-  tasks[Ntasks].Nexit = 0;
-  tasks[Ntasks].NEXIT = 10;
-  ALLOCATE (tasks[Ntasks].exit, Macro *, tasks[Ntasks].NEXIT);
+  ALLOCATE (NewTask, Task, 1);
+
+  NewTask[0].name = strcreate (name);;
+
+  NewTask[0].host = NULL;
+  NewTask[0].host_required = FALSE;
+
+  NewTask[0].argc = 0;
+  NewTask[0].argv = NULL;
+
+  NewTask[0].exec = NULL;
+  NewTask[0].crash = NULL;
+  NewTask[0].timeout = NULL;
+
+  NewTask[0].Nexit = 0;
+  NewTask[0].NEXIT = 10;
+  ALLOCATE (NewTask[0].exit, Macro *, NewTask[0].NEXIT);
   /* don't free tasks[0].exit, keep at least 1 allocated */
 
-  tasks[Ntasks].exec_period = 1.0;
-  tasks[Ntasks].poll_period = 1.0;
-  tasks[Ntasks].timeout_period = 1.0;
-
-  tasks[Ntasks].Nranges = 0;
-  ALLOCATE (tasks[Ntasks].ranges, TimeRange, 1);
+  NewTask[0].exec_period = 1.0;
+  NewTask[0].poll_period = 1.0;
+  NewTask[0].timeout_period = 1.0;
+
+  NewTask[0].Nranges = 0;
+  ALLOCATE (NewTask[0].ranges, TimeRange, 1);
 
   /* init task timer (is reset by 'run') */  
-  gettimeofday (&tasks[Ntasks].last, (void *) NULL);
-  tasks[Ntasks].Njobs = 0;
-  tasks[Ntasks].Nmax = 0;  /* default value means 'no limit' */
-
+  gettimeofday (&NewTask[0].last, (void *) NULL);
+  NewTask[0].Njobs = 0;
+  NewTask[0].Nmax = 0;  /* default value means 'no limit' */
+
+  return (NewTask);
+}
+
+int ValidateTask (Task *task) {
+
+  if (task[0].argc == 0) {
+    fprintf (stderr, "task command not defined\n");
+    return (FALSE);
+  }
+  if (task[0].argv == NULL) {
+    fprintf (stderr, "task command arguments not defined (programming error)\n");
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+int RegisterNewTask () {
+  
+  int N;
+
+  N = Ntasks;
   Ntasks ++;
   if (Ntasks == NTASKS) {
     NTASKS += 20;
-    REALLOCATE (tasks, Task, NTASKS);
-  }
-  return (&tasks[Ntasks-1]);
-}
-
-void SetCurrentTask (char *name) {
-  TaskName = name;
-}
-
-char *GetCurrentTask () {
-  return (TaskName);
-}
+    REALLOCATE (tasks, Task *, NTASKS);
+  }
+  tasks[N] = NewTask;
+  NewTask = NULL;
+  return (TRUE);
+}
+
+int DeleteNewTask () {
+  if (NewTask != NULL) {
+    FreeTask (NewTask);
+    free (NewTask);
+    NewTask = NULL;
+  }
+  return (TRUE);
+}
+
+Task *GetNewTask () {
+  return (NewTask);
+}
+
+/*** task timer functions ***/
 
 double GetTaskTimer (struct timeval start) {
Index: /trunk/Ohana/src/opihi/pantasks/kill.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/kill.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/kill.c	(revision 4684)
@@ -12,6 +12,20 @@
   JobID = atoi (argv[1]);
 
-  /* not yet implemented */
+  job = FindJob (JobID);
 
+  if (job[0].mode == JOB_LOCAL) {
+    if (!KillLocalJob (job)) {
+      job[0].state = JOB_HUNG;
+      if (VerboseMode()) fprintf (stderr, "child process %d is hung, cannot kill\n", job[0].pid);
+      return (FALSE);
+    }
+  } else {
+    if (!KillControllerJob (job)) {
+      job[0].state = JOB_HUNG;
+      if (VerboseMode()) fprintf (stderr, "child process %d is hung, cannot kill\n", job[0].pid);
+      return (FALSE);
+    }
+  }    
+    
   fprintf (stderr, "this function is not yet implemented\n");
   return (TRUE);
Index: /trunk/Ohana/src/opihi/pantasks/scheduler.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/scheduler.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/scheduler.c	(revision 4684)
@@ -1,3 +1,2 @@
-# include "opihi.h"
 # include "scheduler.h"
 
@@ -46,4 +45,5 @@
   InitTasks ();
   InitJobs ();
+  InitJobIDs ();
 
   rl_readline_name = opihi_name;
Index: /trunk/Ohana/src/opihi/pantasks/status.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/status.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/status.c	(revision 4684)
@@ -8,5 +8,5 @@
     fprintf (stderr, "scheduler is running\n");
   }
-  ListTasks ();
+  ListTasks (FALSE);
   ListJobs ();
 
Index: /trunk/Ohana/src/opihi/pantasks/task.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/task.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/task.c	(revision 4684)
@@ -14,5 +14,11 @@
   if (N = get_argument (argc, argv, "-list")) {
     remove_argument (N, &argc, argv);
-    ListTasks ();
+    ListTasks (FALSE);
+    return (TRUE);
+  }
+
+  if (N = get_argument (argc, argv, "-longlist")) {
+    remove_argument (N, &argc, argv);
+    ListTasks (TRUE);
     return (TRUE);
   }
@@ -34,5 +40,6 @@
     task = CreateTask (argv[1]);
   }
-  SetCurrentTask (argv[1]);
+  /* temporary task is saved statically 
+     add to list after definition is complete */
 
   /* read in task from appropriate source (keyboard or list) until end */
@@ -71,4 +78,10 @@
 	   have been defined.  delete the task if not */
 	free (input);
+	/* validate the new task: all mandatory elements defined? */ 
+	if (!ValidateTask (task)) {
+	  DeleteNewTask ();
+	  return (FALSE);
+	}
+	RegisterNewTask ();
 	return (TRUE);
 	break;
@@ -92,5 +105,6 @@
     }
   }
-  return (TRUE);
+  /* cannot ever reach here */
+  return (FALSE);
 }
 
Index: /trunk/Ohana/src/opihi/pantasks/task_command.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/task_command.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/task_command.c	(revision 4684)
@@ -4,5 +4,4 @@
 
   int i;
-  char *taskname;
   Task *task;
 
@@ -13,12 +12,7 @@
   }
 
-  taskname = GetCurrentTask ();
-  if (taskname == NULL) {
+  task = GetNewTask ();
+  if (task == NULL) {
     fprintf (stderr, "ERROR: not defining or running a task\n");
-    return (FALSE);
-  }
-  task = FindTask (taskname);
-  if (task == NULL) {
-    fprintf (stderr, "ERROR: current task not found??\n");
     return (FALSE);
   }
Index: /trunk/Ohana/src/opihi/pantasks/task_host.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/task_host.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/task_host.c	(revision 4684)
@@ -22,12 +22,7 @@
   }
 
-  taskname = GetCurrentTask ();
-  if (taskname == NULL) {
+  task = GetNewTask ();
+  if (task == NULL) {
     fprintf (stderr, "ERROR: not defining or running a task\n");
-    return (FALSE);
-  }
-  task = FindTask (taskname);
-  if (task == NULL) {
-    fprintf (stderr, "ERROR: current task not found??\n");
     return (FALSE);
   }
Index: /trunk/Ohana/src/opihi/pantasks/task_macros.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/task_macros.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/task_macros.c	(revision 4684)
@@ -6,5 +6,5 @@
 
   int i, N, NLINES, done, depth, ThisList;
-  char *taskname, *input;
+  char *input;
   Macro *macro;
   Task *task;
@@ -22,12 +22,7 @@
   }
 
-  taskname = GetCurrentTask ();
-  if (taskname == NULL) {
+  task = GetNewTask ();
+  if (task == NULL) {
     fprintf (stderr, "ERROR: not defining or running a task\n");
-    return (FALSE);
-  }
-  task = FindTask (taskname);
-  if (task == NULL) {
-    fprintf (stderr, "ERROR: current task not found??\n");
     return (FALSE);
   }
Index: /trunk/Ohana/src/opihi/pantasks/task_nmax.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/task_nmax.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/task_nmax.c	(revision 4684)
@@ -4,16 +4,10 @@
 
   Task *task;
-  char *taskname;
 
   if (argc != 2) goto usage;
 
-  taskname = GetCurrentTask ();
-  if (taskname == NULL) {
+  task = GetNewTask ();
+  if (task == NULL) {
     fprintf (stderr, "ERROR: not defining or running a task\n");
-    return (FALSE);
-  }
-  task = FindTask (taskname);
-  if (task == NULL) {
-    fprintf (stderr, "ERROR: current task not found??\n");
     return (FALSE);
   }
Index: /trunk/Ohana/src/opihi/pantasks/task_periods.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/task_periods.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/task_periods.c	(revision 4684)
@@ -5,5 +5,4 @@
   int N, Poll, Exec, Timeout;
   float PollValue, ExecValue, TimeoutValue;
-  char *taskname;
   Task *task;
 
@@ -38,12 +37,7 @@
   }
 
-  taskname = GetCurrentTask ();
-  if (taskname == NULL) {
+  task = GetNewTask ();
+  if (task == NULL) {
     fprintf (stderr, "ERROR: not defining or running a task\n");
-    return (FALSE);
-  }
-  task = FindTask (taskname);
-  if (task == NULL) {
-    fprintf (stderr, "ERROR: current task not found??\n");
     return (FALSE);
   }
Index: /trunk/Ohana/src/opihi/pantasks/task_trange.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/task_trange.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pantasks/task_trange.c	(revision 4684)
@@ -6,5 +6,4 @@
   Task *task;
   TimeRange range;
-  char *taskname;
 
   /* add a -reset option? 
@@ -24,12 +23,7 @@
   if (argc != 3) goto usage;
 
-  taskname = GetCurrentTask ();
-  if (taskname == NULL) {
+  task = GetNewTask ();
+  if (task == NULL) {
     fprintf (stderr, "ERROR: not defining or running a task\n");
-    return (FALSE);
-  }
-  task = FindTask (taskname);
-  if (task == NULL) {
-    fprintf (stderr, "ERROR: current task not found??\n");
     return (FALSE);
   }
Index: /trunk/Ohana/src/opihi/pcontrol/delete.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/delete.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pcontrol/delete.c	(revision 4684)
@@ -39,2 +39,7 @@
   return (TRUE);
 }
+
+/**** at the moment, this function requires the job to be in the correct state
+      to be deleted.  This should be changed to kill, then delete job if it is 
+      not in the correct state 
+****/
Index: /trunk/Ohana/src/opihi/pcontrol/kill.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/kill.c	(revision 4683)
+++ /trunk/Ohana/src/opihi/pcontrol/kill.c	(revision 4684)
@@ -12,10 +12,15 @@
   JobID = atoi (argv[1]);
 
+  /* XXX this function should only fail if a process is hung */
   job = PullJob (JobID, PCONTROL_JOB_BUSY);
   if (job == NULL) {
     fprintf (stderr, "job %s not BUSY\n", argv[1]);
+    /* make output message more readable by scheduler */
     return (FALSE);
   }
+
+  /* XXX - check on success / failure of kill */
   KillJob (job);
+
   return (TRUE);
 }
