Index: /trunk/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 4762)
+++ /trunk/Ohana/src/opihi/include/pcontrol.h	(revision 4763)
@@ -168,2 +168,4 @@
 int VerboseMode ();
 int StartJob (Job *job);
+void gotsignal (int signum);
+int HarvestHost (int pid);
Index: /trunk/Ohana/src/opihi/include/psched.h
===================================================================
--- /trunk/Ohana/src/opihi/include/psched.h	(revision 4762)
+++ /trunk/Ohana/src/opihi/include/psched.h	(revision 4763)
@@ -167,4 +167,5 @@
 CommandF *FindControllerCommand (char *cmd);
 int QuitController ();
+int StopController ();
 int VerboseMode ();
 int KillLocalJob (Job *job);
@@ -175,3 +176,4 @@
 int CheckControllerStatus ();
 int TestElapsedCheck ();
+void gotsignal (int signum);
 
Index: /trunk/Ohana/src/opihi/include/shell.h
===================================================================
--- /trunk/Ohana/src/opihi/include/shell.h	(revision 4762)
+++ /trunk/Ohana/src/opihi/include/shell.h	(revision 4763)
@@ -58,4 +58,7 @@
 int           is_list               	PROTO((char *line));
 int           is_loop               	PROTO((char *line));
+int           is_task               	PROTO((char *line));
+int           is_task_exit             	PROTO((char *line));
+int           is_task_exec             	PROTO((char *line));
 int           is_macro_create       	PROTO((char *line));
 void          InitLists                 PROTO(());
Index: /trunk/Ohana/src/opihi/lib.shell/ListOps.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/ListOps.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/lib.shell/ListOps.c	(revision 4763)
@@ -126,4 +126,42 @@
 }
 
+int is_task (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  status = !strcmp (comm, "task");
+  free (comm);
+  return (status);
+}
+
+int is_task_exit (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  status = !strcmp (comm, "task.exit");
+  free (comm);
+  return (status);
+}
+
+int is_task_exec (char *line) {
+
+  int status;
+  char *comm;
+
+  comm = thisword (line);
+  if (comm == (char *) NULL) return (FALSE);
+
+  status = !strcmp (comm, "task.exec");
+  free (comm);
+  return (status);
+}
 
 int is_list (char *line) {
@@ -135,4 +173,7 @@
   status |= is_for_loop (line);
   status |= is_loop (line);
+  status |= is_task (line);
+  status |= is_task_exit (line);
+  status |= is_task_exec (line);
 
   return (status);
Index: /trunk/Ohana/src/opihi/lib.shell/opihi.c
===================================================================
--- /trunk/Ohana/src/opihi/lib.shell/opihi.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/lib.shell/opihi.c	(revision 4763)
@@ -19,4 +19,5 @@
 
     line = readline (prompt);
+
     if (line == NULL) { 
       
Index: /trunk/Ohana/src/opihi/pantasks/CheckController.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/CheckController.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/CheckController.c	(revision 4763)
@@ -38,5 +38,6 @@
   gettimeofday (&stop, (void *) NULL);
   dtime = DTIME (stop, start);
-  if (VerboseMode()) fprintf (stderr, "check stack %f\n", dtime);
+  if (VerboseMode()) fprintf (stderr, "check exit stack %f\n", dtime);
+  /* if (Njobs) fprintf (stderr, "check exit stack %f\n", dtime); */
   gettimeofday (&start, (void *) NULL);
 
@@ -61,5 +62,6 @@
   gettimeofday (&stop, (void *) NULL);
   dtime = DTIME (stop, start);
-  if (VerboseMode()) fprintf (stderr, "check %d jobs %f\n", i, dtime);
+  /* if (VerboseMode()) fprintf (stderr, "clear %d exit jobs %f\n", i, dtime); */
+  gettimeofday (&start, (void *) NULL);
 
   if (TestElapsedCheck()) return (TRUE);
@@ -85,4 +87,9 @@
   }
 
+  gettimeofday (&stop, (void *) NULL);
+  dtime = DTIME (stop, start);
+  /* if (VerboseMode()) fprintf (stderr, "check crash stack %f\n", dtime); */
+  gettimeofday (&start, (void *) NULL);
+
   p = buffer.buffer;
   for (i = 0; (i < Njobs) && !TestElapsedCheck(); i++) {
@@ -104,4 +111,8 @@
   }
   FreeIOBuffer (&buffer);
+
+  gettimeofday (&stop, (void *) NULL);
+  dtime = DTIME (stop, start);
+  /* if (VerboseMode()) fprintf (stderr, "clear %d crash jobs %f\n", i, dtime); */
   return (TRUE);
 }
Index: /trunk/Ohana/src/opihi/pantasks/CheckJobs.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/CheckJobs.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/CheckJobs.c	(revision 4763)
@@ -17,9 +17,9 @@
     switch (status) {
       case JOB_PENDING:
-	if (VerboseMode()) fprintf (stderr, "job %s (%d) pending\n", job[0].task[0].name, job[0].JobID);
+	/* if (VerboseMode()) fprintf (stderr, "job %s (%d) pending\n", job[0].task[0].name, job[0].JobID); */
 	break;
 
       case JOB_BUSY:
-	if (VerboseMode()) fprintf (stderr, "job %s (%d) busy\n", job[0].task[0].name, job[0].JobID);
+	/* if (VerboseMode()) fprintf (stderr, "job %s (%d) busy\n", job[0].task[0].name, job[0].JobID); */
 	break;
 
Index: /trunk/Ohana/src/opihi/pantasks/CheckSystem.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/CheckSystem.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/CheckSystem.c	(revision 4763)
@@ -9,5 +9,5 @@
   gettimeofday (&start, (void *) NULL);
 
-  if (Ncheck < 5) {
+  if (Ncheck < 20) {
     CheckTasks ();
     CheckJobs ();
Index: /trunk/Ohana/src/opihi/pantasks/ControllerOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/ControllerOps.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/ControllerOps.c	(revision 4763)
@@ -25,5 +25,5 @@
   gettimeofday (&stop, (void *) NULL);
   dtime = DTIME (stop, start);
-  if (VerboseMode()) fprintf (stderr, "check job status %f\n", dtime);
+  /* if (VerboseMode()) fprintf (stderr, "check job status %f\n", dtime); */
 
   if ((job[0].state == JOB_EXIT) || (job[0].state == JOB_CRASH)) {
@@ -32,8 +32,17 @@
     gettimeofday (&stop, (void *) NULL);
     dtime = DTIME (stop, start);
-    if (VerboseMode()) fprintf (stderr, "get stdout %f\n", dtime);
-
+    /* if (VerboseMode()) fprintf (stderr, "get stdout %f\n", dtime); */
+
+    gettimeofday (&start, (void *) NULL);
     GetJobOutput ("stderr", job[0].pid, &job[0].stderr, job[0].stderr_size);
+    gettimeofday (&stop, (void *) NULL);
+    dtime = DTIME (stop, start);
+    /* if (VerboseMode()) fprintf (stderr, "get stderr %f\n", dtime); */
+
+    gettimeofday (&start, (void *) NULL);
     DeleteControllerJob (job);
+    gettimeofday (&stop, (void *) NULL);
+    dtime = DTIME (stop, start);
+    /* if (VerboseMode()) fprintf (stderr, "delete job %f\n", dtime); */
   }  
   return (TRUE);
@@ -138,5 +147,5 @@
   if (status == -1) return (CONTROLLER_HUNG);
 
-  if (VerboseMode()) fprintf (stderr, "message received (GetJobOutput : %s)\n", cmd);  
+  /* if (VerboseMode()) fprintf (stderr, "message received (GetJobOutput : %s)\n", cmd);   */
   /* drop extra bytes from pcontrol (not pclient:job) */
   buffer[0].Nbuffer = Nstart + Nbytes;
@@ -328,10 +337,8 @@
   FlushIOBuffer (buffer);
 
-  if (VerboseMode()) fprintf (stderr, "send: %s\n", cmd);
-
   /* send command, is pipe still open? */
   status = write_fmt (stdin_cntl, "%s\n", cmd);
   if ((status == -1) && (errno == EPIPE)) {
-    ControllerStatus = FALSE;
+    StopController ();
     if (VerboseMode()) fprintf (stderr, "controller is down\n");
     return (FALSE);
@@ -347,9 +354,10 @@
   }
   if (status ==  0) {
-    ControllerStatus = FALSE;
+    StopController ();
     if (VerboseMode()) fprintf (stderr, "controller is down\n");
     return (FALSE);
   }
   if (status == -1) {
+    StopController ();
     if (VerboseMode()) fprintf (stderr, "controller is not responding\n");
     return (FALSE);
@@ -362,5 +370,5 @@
     bzero (buffer[0].buffer + buffer[0].Nbuffer, buffer[0].Nalloc - buffer[0].Nbuffer);
   }
-  if (VerboseMode()) fprintf (stderr, "message received, %d cycles\n", i);
+  /* if (VerboseMode()) fprintf (stderr, "message received, %d cycles\n", i); */
   return (TRUE);
 }
@@ -428,5 +436,5 @@
 int QuitController () {
 
-  int i, status, waitstatus, result;
+  int status;
   char cmd[128];
   IOBuffer buffer;
@@ -436,6 +444,18 @@
   sprintf (cmd, "quit");
   InitIOBuffer (&buffer, 0x100);
-  status = ControllerCommand (cmd, CONTROLLER_PROMPT, &buffer);
-  FreeIOBuffer (&buffer);
+  status = ControllerCommand (cmd, "", &buffer);
+  FreeIOBuffer (&buffer);
+
+  /* the quit command does not return a prompt, so we always 
+     get an error on the controller here */
+  StopController ();
+  return (TRUE);
+}
+
+int StopController () {
+
+  int i, waitstatus, result;
+
+  if (!ControllerStatus) return (TRUE);
 
   ControllerStatus = FALSE;
@@ -451,5 +471,4 @@
   FreeIOBuffer (&stdout_buffer);
   FreeIOBuffer (&stderr_buffer);
-
-  return (TRUE);
-}
+  return (TRUE);
+}
Index: /trunk/Ohana/src/opihi/pantasks/Makefile
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/Makefile	(revision 4763)
@@ -51,4 +51,5 @@
 $(SDIR)/controller_status.$(ARCH).o \
 $(SDIR)/controller_output.$(ARCH).o \
+$(SDIR)/controller_pulse.$(ARCH).o \
 $(SDIR)/task.$(ARCH).o \
 $(SDIR)/task_host.$(ARCH).o \
Index: /trunk/Ohana/src/opihi/pantasks/controller.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/controller.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/controller.c	(revision 4763)
@@ -6,4 +6,5 @@
 int controller_check   PROTO((int, char **));
 int controller_output  PROTO((int, char **));
+int controller_pulse   PROTO((int, char **));
 
 static Command controller_cmds[] = {
@@ -13,4 +14,5 @@
   {"status", controller_status, "check controller status"},
   {"output", controller_output, "print controller output"},
+  {"pulse",  controller_pulse,  "set controller pulse"},
 };
 
Index: /trunk/Ohana/src/opihi/pantasks/controller_host.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/controller_host.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/controller_host.c	(revision 4763)
@@ -22,2 +22,8 @@
   return (TRUE);
 }
+
+/* should I keep an internal host table so I can reload the 
+   hosts if the controller exits?
+
+   alternatively, that could be a user-level choice
+*/
Index: /trunk/Ohana/src/opihi/pantasks/controller_pulse.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/controller_pulse.c	(revision 4763)
+++ /trunk/Ohana/src/opihi/pantasks/controller_pulse.c	(revision 4763)
@@ -0,0 +1,23 @@
+# include "psched.h"
+
+int controller_pulse (int argc, char **argv) {
+
+  int status;
+  char command[1024];
+  IOBuffer buffer;
+
+  if (argc != 2) {
+    fprintf (stderr, "USAGE: controller pulse (usec)\n");
+    return (FALSE);
+  }
+
+  /* start controller connection (if needed) */
+  StartController ();
+
+  sprintf (command, "pulse %d", atoi(argv[1]));
+  InitIOBuffer (&buffer, 0x100);
+  status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
+  if (status) fwrite (buffer.buffer, 1, buffer.Nbuffer, stderr);
+  FreeIOBuffer (&buffer);
+  return (TRUE);
+}
Index: /trunk/Ohana/src/opihi/pantasks/controller_status.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/controller_status.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/controller_status.c	(revision 4763)
@@ -22,7 +22,10 @@
   InitIOBuffer (&buffer, 0x100);
   status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
-  if (status) fwrite (buffer.buffer, 1, buffer.Nbuffer, stderr);
+  if (status) {
+    fwrite (buffer.buffer, 1, buffer.Nbuffer, stderr);
+  } else {
+    fprintf (stderr, "controller is down\n");
+  }
   FreeIOBuffer (&buffer);
   return (TRUE);
-
 }
Index: /trunk/Ohana/src/opihi/pantasks/psched.c
===================================================================
--- /trunk/Ohana/src/opihi/pantasks/psched.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pantasks/psched.c	(revision 4763)
@@ -41,4 +41,7 @@
 
   signal (SIGINT, SIG_IGN);
+  signal (SIGPIPE, gotsignal);
+  signal (SIGTSTP, gotsignal);
+  signal (SIGTTIN, gotsignal);
   return;
 }
@@ -57,2 +60,7 @@
   return;
 }
+
+void gotsignal (int signum) {
+  fprintf (stderr, "got signal : %d\n", signum);
+  return;
+}
Index: /trunk/Ohana/src/opihi/pclient/ChildOps.c
===================================================================
--- /trunk/Ohana/src/opihi/pclient/ChildOps.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pclient/ChildOps.c	(revision 4763)
@@ -1,3 +1,7 @@
 # include "pclient.h"
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stropts.h>
 
 static int Nbad = 0;
@@ -29,18 +33,21 @@
   struct timeval now;
 
-  /* this is really lame : check if we are calling too quickly 
-     this is unneeded: pclient.c rl_keyboard_input_timeout limits
-     the rate 
-  gettimeofday (&now, NULL);
-  dtime = DTIME (now, last);
+  /* runaway test - if pcontrol is killed, pclient starts running away.  this test is a bit
+     dangerous: the choice of dtime probably depends on the processor and the value provided to
+     pclient.c:rl_set_keyboard_input_timeout (1000); note that we cannot use getppid == 1 as a test
+     because the parent of pclient is the ssh process on the pclient host, not pcontrol.  in any
+     case, the opihi shell catches if the ssh dies using getppid
+   */
+  gettimeofday (&now, (void *) NULL);
+  dtime = 1e6*DTIME (now, last);
+  if (dtime < 100) {
+    Nbad ++;
+    if (Nbad > 10) {
+      fprintf (stderr, "runaway!\n");
+      exit (2);
+    }
+  }
+  if (dtime > 950) Nbad = 0;
   last = now;
-  if (dtime < 0.0001) Nbad ++;
-  if (dtime > 0.01) Nbad = 0;
-  if (Nbad > 10) exit (2);
-  */
-
-  /* this is a bit lame : we must exit if calling process exits */
-  ppid = getppid();
-  if (ppid == 1) exit (2);
 
   CheckChildStatus ();
Index: /trunk/Ohana/src/opihi/pclient/pclient.c
===================================================================
--- /trunk/Ohana/src/opihi/pclient/pclient.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pclient/pclient.c	(revision 4763)
@@ -21,4 +21,5 @@
   rl_event_hook = CheckChild;
   rl_set_keyboard_input_timeout (1000); 
+  /* 1 ms seems to be the minimum valid number */
 
   set_str_variable ("HISTORY", opihi_history);
Index: /trunk/Ohana/src/opihi/pcontrol/CheckBusyJob.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/CheckBusyJob.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/CheckBusyJob.c	(revision 4763)
@@ -20,4 +20,5 @@
   switch (status) {
     case PCLIENT_DOWN:
+      HarvestHost (host[0].pid);
       UnlinkJobAndHost (job);
       PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
Index: /trunk/Ohana/src/opihi/pcontrol/CheckDoneHost.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/CheckDoneHost.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/CheckDoneHost.c	(revision 4763)
@@ -14,9 +14,11 @@
   switch (status) {
     case PCLIENT_DOWN:
-      /** do we need to close the connection? **/
+      if (VerboseMode()) fprintf (stderr, "host %s is down\n", host[0].hostname);
+      /* DONE host does not have an incomplete job */
+      HarvestHost (host[0].pid);
       PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
-      if (VerboseMode()) fprintf (stderr, "host %s is down\n", host[0].hostname);
       FreeIOBuffer (&buffer);
       return (FALSE);
+      /** do we need to close the connection? **/
 
     case PCLIENT_HUNG:
Index: /trunk/Ohana/src/opihi/pcontrol/CheckHost.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/CheckHost.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/CheckHost.c	(revision 4763)
@@ -13,19 +13,11 @@
     case 0:
       if (VerboseMode()) fprintf (stderr, "host %s is down\n", host[0].hostname);
-
-      /* if host has a job, job is dead, push to Pending */
-      if (host[0].stack == PCONTROL_HOST_BUSY) {
-	job = (Job *) host[0].job;
-	if (job != NULL) {
-	  N = FindJob (job[0].JobID, PCONTROL_JOB_BUSY);
-	  if (N < 0) {
-	    fprintf (stderr, "programming error: job is not found in BUSY list\n");
-	    exit (2);
-	  }
-	  job[0].host = NULL; /* unlink host & job */
-	  PutJob (job, PCONTROL_JOB_PENDING, STACK_BOTTOM);
-	}
+      /* if host has a job, job is dead, return to Pending */
+      job = (Job *) host[0].job;
+      if (job != NULL) {
+	UnlinkJobAndHost (job);
+	PutJob (job, PCONTROL_JOB_PENDING, STACK_BOTTOM);
       }
-      host[0].job = NULL;
+      HarvestHost (host[0].pid);
       PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
       FreeIOBuffer (&buffer);
Index: /trunk/Ohana/src/opihi/pcontrol/CheckSystem.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/CheckSystem.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/CheckSystem.c	(revision 4763)
@@ -1,7 +1,10 @@
 # include "pcontrol.h"
 
-static Npass = 0;
+static struct timeval lastlive = {0, 0};
 
 int CheckSystem () {
+
+  struct timeval now;
+  float dtime;
 
   /* we want to give each block a maximum allowed time */
@@ -14,14 +17,14 @@
   CheckDownHosts(0.100); /* launch the host */
 
+  /* always allow at least one test */
   /* most tests require about 2ms per host.  
      CheckDoneJobs must depend on the size of the output buffer */
 
-  /* this is a waste of cycles: no need to do this every loop */
-  if (Npass > 20) {
+  gettimeofday (&now, (void *) NULL);
+  dtime = DTIME (now, lastlive);
+  if (dtime > 1.0) {
     CheckLiveHosts(0.040);
-    Npass = 0;
-  } else {
-    Npass ++;
-  }
+    lastlive = now;
+  } 
 
   if (0) { 
Index: /trunk/Ohana/src/opihi/pcontrol/KillJob.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/KillJob.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/KillJob.c	(revision 4763)
@@ -18,7 +18,8 @@
   switch (status) {
     case PCLIENT_DOWN:
+      HarvestHost (host[0].pid);
       UnlinkJobAndHost (job);
+      PutJob (job, PCONTROL_JOB_PENDING, STACK_BOTTOM);
       PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
-      PutJob (job, PCONTROL_JOB_PENDING, STACK_BOTTOM);
       FreeIOBuffer (&buffer);
       return (FALSE);
Index: /trunk/Ohana/src/opihi/pcontrol/ResetJob.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/ResetJob.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/ResetJob.c	(revision 4763)
@@ -20,6 +20,8 @@
   switch (status) {
     case PCLIENT_DOWN:
-      /*** different behavior for ANYHOST, WANTHOST, NEEDHOST ***/
+      /*** different behavior for ANYHOST, WANTHOST, NEEDHOST? ***/
       fprintf (stderr, "host %s is down\n", host[0].hostname);
+      HarvestHost (host[0].pid);
+      PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
       FreeIOBuffer (&buffer);
       return (FALSE);
Index: /trunk/Ohana/src/opihi/pcontrol/StartJob.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/StartJob.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/StartJob.c	(revision 4763)
@@ -88,4 +88,5 @@
   job[0].host = NULL;
   host[0].job = NULL;
+  HarvestHost (host[0].pid);
   PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
   PutJob (job, PCONTROL_JOB_PENDING, STACK_BOTTOM);
Index: /trunk/Ohana/src/opihi/pcontrol/StopHosts.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/StopHosts.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/StopHosts.c	(revision 4763)
@@ -29,6 +29,4 @@
 int StopHost (Host *host) {
 
-  int       result;
-  int       waitstatus;
   int       status;
   IOBuffer  buffer;
@@ -53,9 +51,32 @@
       exit (1);
   }
+  HarvestHost (host[0].pid);
+  return (TRUE);
+}
 
-  /* check current child status */
+void DownHost (Host *host) {
+  CLOSE (host[0].stdin);
+  CLOSE (host[0].stdout);
+  CLOSE (host[0].stderr);
+  host[0].job = NULL;
+  PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
+}
+
+void OffHost (Host *host) {
+  CLOSE (host[0].stdin);
+  CLOSE (host[0].stdout);
+  CLOSE (host[0].stderr);
+  host[0].job = NULL;
+  PutHost (host, PCONTROL_HOST_OFF, STACK_BOTTOM);
+}
+
+int HarvestHost (int pid) {
+  
+  int       result;
+  int       waitstatus;
+
   /* I probably should loop a few time with max timeout larger than 10ms... */
   usleep (10000);
-  result = waitpid (host[0].pid, &waitstatus, WNOHANG);
+  result = waitpid (pid, &waitstatus, WNOHANG);
   switch (result) {
     case -1:  /* error with waitpid */
@@ -83,6 +104,6 @@
 
     default:
-      if (result != host[0].pid) {
-	fprintf (stderr, "waitpid error: mis-matched PID (%d vs %d).  programming error\n", result, host[0].pid);
+      if (result != pid) {
+	fprintf (stderr, "waitpid error: mis-matched PID (%d vs %d).  programming error\n", result, pid);
 	exit (1);
       }
@@ -101,18 +122,2 @@
   return (TRUE);
 }
-
-void DownHost (Host *host) {
-  CLOSE (host[0].stdin);
-  CLOSE (host[0].stdout);
-  CLOSE (host[0].stderr);
-  host[0].job = NULL;
-  PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
-}
-
-void OffHost (Host *host) {
-  CLOSE (host[0].stdin);
-  CLOSE (host[0].stdout);
-  CLOSE (host[0].stderr);
-  host[0].job = NULL;
-  PutHost (host, PCONTROL_HOST_OFF, STACK_BOTTOM);
-}
Index: /trunk/Ohana/src/opihi/pcontrol/pcontrol.c
===================================================================
--- /trunk/Ohana/src/opihi/pcontrol/pcontrol.c	(revision 4762)
+++ /trunk/Ohana/src/opihi/pcontrol/pcontrol.c	(revision 4763)
@@ -19,5 +19,5 @@
   rl_attempted_completion_function = command_completer;
   rl_event_hook = CheckSystem;
-  rl_set_keyboard_input_timeout (100000); 
+  rl_set_keyboard_input_timeout (1000); 
 
   set_str_variable ("HISTORY", opihi_history);
@@ -30,4 +30,7 @@
   /* ignore the history file.  to change this, see, eg, mana.c */
   signal (SIGINT, SIG_IGN);
+  signal (SIGPIPE, gotsignal);
+  signal (SIGTSTP, gotsignal);
+  signal (SIGTTIN, gotsignal);
   return;
 }
@@ -44,2 +47,7 @@
   return;
 }
+
+void gotsignal (int signum) {
+  fprintf (stderr, "got signal : %d\n", signum);
+  return;
+}
Index: /trunk/Ohana/src/opihi/scripts/psched.pro
===================================================================
--- /trunk/Ohana/src/opihi/scripts/psched.pro	(revision 4762)
+++ /trunk/Ohana/src/opihi/scripts/psched.pro	(revision 4763)
@@ -1,14 +1,32 @@
 
 controller exit true
-controller host add kiawe
-controller host add alala
+# controller host add kiawe
+$Ntest = 0
+# controller host add alala
 # verbose on
+pulse 1000
+controller pulse 1000
+
+macro load.machines
+  if ($0 != 2)
+    echo "load.machines (nmach)"
+    break
+  end
+
+  for i 0 $1
+    $n = $i + 1
+    sprintf host "po%02d" $n
+    controller host add $host
+  end
+end
 
 task test
   command partest
-  periods -poll 0.1
-  periods -exec 0.1
+  # polling period is no longer valid: we check for completed controller tasks
+  # correction: still valid for local tasks
+  periods -poll 0.20
+  periods -exec 0.001
   periods -timeout 10.0
-  nmax 5
+  nmax 1024
   host anyhost
 
@@ -18,5 +36,8 @@
     queuedelete stdout
     queuedelete stderr
-    memory leaks
+    date date
+    queuepush done "$date"
+    $Ntest ++
+#   memory leaks
 #   queuesize stdout -var Nstdout
 #    for i 0 $Nstdout
@@ -42,2 +63,36 @@
   end
 end
+
+# pulse == 100ms
+# poll/exit = 0.2  : 29 sec / 100 jobs
+# poll/exit = 0.1  : 20 sec / 100 jobs
+# poll/exit = 0.05 : 17 sec / 100 jobs
+# poll/exit = 0.01 : 18 sec / 100 jobs
+
+# pulse == 10ms
+# poll/exit = 0.2  : 20 sec / 100 jobs
+# poll/exit = 0.10 : 12 sec / 100 jobs
+# poll/exit = 0.05 : 12 sec / 100 jobs
+# poll/exit = 0.01 :  9 sec / 100 jobs
+
+# we are limited here by how quickly we can send data to the 
+# controller.  this is limited by the occasional 'CheckSystem'
+# loops, with ~40ms minimum.
+
+# seems to be faster on po01 from kiawe (less interference?)
+
+# pulse == 1ms, controller pulse == 1ms
+# poll/exit = 0.01 :  3 sec / 100 jobs
+# 2 mach, 3 sec
+# 4 mach, 3 sec
+# 8 mach, 3 sec
+
+# 16 machines, 500 jobs, 13 sec: 26ms / job
+# 32 machines, 1024 jobs, 26 sec: 26ms / job
+# job harvesting rate is still the limitation.  Each job harvest requires:
+#  - jobstack exit
+#  - stdout
+#  - stderr
+#  - delete
+#  - jobstack crash
+
