Index: trunk/Ohana/src/opihi/pantasks/Makefile
===================================================================
--- trunk/Ohana/src/opihi/pantasks/Makefile	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/Makefile	(revision 11084)
@@ -7,5 +7,5 @@
 LIB     =       $(HOME)/lib
 INC     =       $(HOME)/include
-HELP    =       $(DESTHELP)/pantasks
+DATA    =       $(DESTDATA)/pantasks
 
 # link flags 
@@ -16,4 +16,10 @@
 # sched user commands and support functions ########################
 
+client = \
+$(SRC)/pantasks_client.$(ARCH).o \
+$(SRC)/client_shell.$(ARCH).o \
+$(SRC)/invalid.$(ARCH).o \
+$(SRC)/init_client.$(ARCH).o
+
 single = \
 $(SRC)/init.$(ARCH).o \
@@ -21,5 +27,24 @@
 $(SRC)/stop.$(ARCH).o \
 $(SRC)/pantasks.$(ARCH).o \
-$(SRC)/CheckSystem.$(ARCH).o
+$(SRC)/thread_locks.$(ARCH).o \
+$(SRC)/job_threads.$(ARCH).o \
+$(SRC)/task_threads.$(ARCH).o \
+$(SRC)/controller_threads.$(ARCH).o 
+
+server = \
+$(SRC)/pantasks_server.$(ARCH).o \
+$(SRC)/server_run.$(ARCH).o \
+$(SRC)/server_load.$(ARCH).o \
+$(SRC)/InputQueue.$(ARCH).o \
+$(SRC)/ListenClients.$(ARCH).o \
+$(SRC)/server.$(ARCH).o \
+$(SRC)/status_server.$(ARCH).o \
+$(SRC)/init_server.$(ARCH).o \
+$(SRC)/CheckPassword.$(ARCH).o \
+$(SRC)/thread_locks.$(ARCH).o \
+$(SRC)/job_threads.$(ARCH).o \
+$(SRC)/task_threads.$(ARCH).o \
+$(SRC)/controller_threads.$(ARCH).o \
+$(SRC)/input_threads.$(ARCH).o
 
 funcs = \
@@ -61,22 +86,4 @@
 $(SRC)/ipptool2book.$(ARCH).o
 
-client = \
-$(SRC)/pantasks_client.$(ARCH).o \
-$(SRC)/client_shell.$(ARCH).o \
-$(SRC)/invalid.$(ARCH).o \
-$(SRC)/init_client.$(ARCH).o
-
-server = \
-$(SRC)/pantasks_server.$(ARCH).o \
-$(SRC)/server_threads.$(ARCH).o \
-$(SRC)/server_run.$(ARCH).o \
-$(SRC)/server_load.$(ARCH).o \
-$(SRC)/InputQueue.$(ARCH).o \
-$(SRC)/ListenClients.$(ARCH).o \
-$(SRC)/server.$(ARCH).o \
-$(SRC)/status_server.$(ARCH).o \
-$(SRC)/init_server.$(ARCH).o \
-$(SRC)/CheckPassword.$(ARCH).o
-
 libs = \
 $(DESTLIB)/libshell.a \
@@ -103,7 +110,9 @@
 $(single) $(client) $(server) $(funcs) $(cmds) : $(INC)/pantasks.h
 
-install: $(DESTBIN)/pantasks $(DESTBIN)/pantasks_client $(DESTBIN)/pantasks_server help
+install: $(DESTBIN)/pantasks $(DESTBIN)/pantasks_client $(DESTBIN)/pantasks_server help modules
 
 help: clean-help cmd.basic.help cmd.data.help cmd.astro.help pantasks.help
+
+modules: pantasks.modules
 
 .PHONY: pantasks pantasks_client pantasks_server
Index: trunk/Ohana/src/opihi/pantasks/TaskOps.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/TaskOps.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/TaskOps.c	(revision 11084)
@@ -1,3 +1,4 @@
 # include "pantasks.h"
+# include <regex.h>
 
 static Task **tasks;
@@ -75,8 +76,8 @@
   gprint (GP_LOG, " Task Status\n");
 
-  snprintf (format, 128, "  AV %%-%ds %5s %%-%ds\n", nameLength, "Njobs", cmdLength);
+  snprintf (format, 128, "  AV %%-%ds %5s  %5s %5s %5s %%-%ds\n", nameLength, "Njobs", "Ngood", "Nfail", "Ntime", cmdLength);
   gprint (GP_LOG, format, "Name", "Command");
 
-  snprintf (format, 128, "%%-%ds %%5d %%-%ds\n", nameLength, cmdLength);
+  snprintf (format, 128, "%%-%ds %%5d  %%5d %%5d %%5d %%-%ds\n", nameLength, cmdLength);
   for (i = 0; i < Ntasks; i++) {
     valid = CheckTimeRanges (tasks[i][0].ranges, tasks[i][0].Nranges);
@@ -93,7 +94,7 @@
     }
     if (tasks[i][0].argv == NULL) {
-      gprint (GP_LOG, format, tasks[i][0].name, tasks[i][0].Njobs, "(dynamic)");
-    } else {
-      gprint (GP_LOG, format, tasks[i][0].name, tasks[i][0].Njobs, tasks[i][0].argv[0]);
+      gprint (GP_LOG, format, tasks[i][0].name, tasks[i][0].Njobs, tasks[i][0].Nsuccess, tasks[i][0].Nfailure, tasks[i][0].Ntimeout, "(dynamic)");
+    } else {
+      gprint (GP_LOG, format, tasks[i][0].name, tasks[i][0].Njobs, tasks[i][0].Nsuccess, tasks[i][0].Nfailure, tasks[i][0].Ntimeout, tasks[i][0].argv[0]);
     }
     if (verbose) {
@@ -146,9 +147,10 @@
 
 /* list known tasks */
-void ListTaskStats () {
+void ListTaskStats (char *regex) {
 
   int i, j, valid, nameLength;
   char *start, *stop;
   char format[128];
+  regex_t preg;
 
   gprint (GP_LOG, "\n");
@@ -158,4 +160,8 @@
   }
 
+  if (regex != NULL) {
+    regcomp (&preg, regex, REG_EXTENDED);
+  }
+
   /* find string lengths */
   nameLength = 0;
@@ -173,4 +179,7 @@
   snprintf (format, 128, "%%-%ds", nameLength);
   for (i = 0; i < Ntasks; i++) {
+      
+    if ((regex != NULL) && regexec (&preg, tasks[i][0].name, 0, NULL, 0)) continue;
+
     valid = CheckTimeRanges (tasks[i][0].ranges, tasks[i][0].Nranges);
     if (tasks[i][0].active) {
Index: trunk/Ohana/src/opihi/pantasks/controller_threads.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/controller_threads.c	(revision 11084)
+++ trunk/Ohana/src/opihi/pantasks/controller_threads.c	(revision 11084)
@@ -0,0 +1,32 @@
+# include "pantasks.h"
+
+/** things related to CheckController **/
+
+static int CheckControllerRun = FALSE;
+
+void CheckControllerSetState (int state) {
+  CheckControllerRun = state;
+}
+int CheckControllerGetState () {
+  return (CheckControllerRun);
+}
+
+void *CheckControllerThread (void *data) {
+
+  gprintInit ();  // each thread needs to init the printing system
+  while (1) {
+
+    // check for thread suspend
+    if (!CheckControllerRun) {
+      usleep (100000); // idle if thread action is suspended
+      continue;
+    }
+
+    // one run of the task checker
+    SerialThreadLock ();
+    CheckController ();
+    CheckControllerOutput ();
+    SerialThreadUnlock ();
+    usleep (10000); // allow other threads a chance to run
+  }
+}
Index: trunk/Ohana/src/opihi/pantasks/init.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/init.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/init.c	(revision 11084)
@@ -15,4 +15,5 @@
 int run             PROTO((int, char **));
 int stop            PROTO((int, char **));
+int halt            PROTO((int, char **));
 int pulse           PROTO((int, char **));
 int status_sys      PROTO((int, char **));
@@ -38,5 +39,6 @@
   {"stderr",     task_stderr,  "define a file for the job stderr dump"},
   {"run",        run,          "run the scheduler"},
-  {"stop",       stop,         "stop the scheduler"},
+  {"stop",       stop,         "stop the scheduler (continue job harvesting)"},
+  {"halt",       halt,         "halt the scheduler (no job harvesting)"},
   {"pulse",      pulse,        "set the scheduler update period"},
   {"status",     status_sys,   "get system status"},
Index: trunk/Ohana/src/opihi/pantasks/input_threads.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/input_threads.c	(revision 11084)
+++ trunk/Ohana/src/opihi/pantasks/input_threads.c	(revision 11084)
@@ -0,0 +1,32 @@
+# include "pantasks.h"
+
+/** things related to CheckInputs **/
+
+static int CheckInputsRun = TRUE;
+
+void CheckInputsSetState (int state) {
+  CheckInputsRun = state;
+}
+int CheckInputsGetState () {
+  return (CheckInputsRun);
+}
+
+void *CheckInputsThread (void *data) {
+
+  gprintInit ();  // each thread needs to init the printing system
+  while (1) {
+
+    // check for thread suspend
+    if (!CheckInputsRun) {
+      usleep (100000); // idle if thread action is suspended
+      continue;
+    }
+
+    // one run of the task checker
+    SerialThreadLock ();
+    CheckInputs ();
+    SerialThreadUnlock ();
+    fprintf (stderr, "I");
+    usleep (10000); // allow other threads a chance to run
+  }
+}
Index: trunk/Ohana/src/opihi/pantasks/ipptool2book.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/ipptool2book.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/ipptool2book.c	(revision 11084)
@@ -80,5 +80,5 @@
   }
   if (strcmp(bookName, argv[2])) {
-    gprint (GP_ERR, "WARNING: metadata output name does not match expected bookname\n");
+    gprint (GP_ERR, "WARNING: metadata output name %s does not match expected bookname %s\n", bookName, argv[2]);
   }
   free (line);
Index: trunk/Ohana/src/opihi/pantasks/job_threads.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/job_threads.c	(revision 11084)
+++ trunk/Ohana/src/opihi/pantasks/job_threads.c	(revision 11084)
@@ -0,0 +1,31 @@
+# include "pantasks.h"
+
+/** things related to CheckJobs **/
+
+static int CheckJobsRun = FALSE;
+
+void CheckJobsSetState (int state) {
+  CheckJobsRun = state;
+}
+int CheckJobsGetState () {
+  return (CheckJobsRun);
+}
+
+void *CheckJobsThread (void *data) {
+
+  gprintInit ();  // each thread needs to init the printing system
+  while (1) {
+
+    // check for thread suspend
+    if (!CheckJobsRun) {
+      usleep (100000); // idle if thread action is suspended
+      continue;
+    }
+
+    // one run of the task checker
+    SerialThreadLock ();
+    CheckJobs ();
+    SerialThreadUnlock ();
+    usleep (10000); // allow other threads a chance to run
+  }
+}
Index: trunk/Ohana/src/opihi/pantasks/pantasks.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/pantasks.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/pantasks.c	(revision 11084)
@@ -10,4 +10,8 @@
 void program_init (int *argc, char **argv) {
   
+  pthread_t jobsThread;
+  pthread_t tasksThread;
+  pthread_t controllerThread;
+
   auto_break = TRUE;
 
@@ -26,6 +30,21 @@
   set_str_variable ("RCFILE", opihi_rcfile);
 
-# ifdef HELPDIR_DEFAULT
-  set_str_variable ("HELPDIR", MACRO_NAME(HELPDIR_DEFAULT));
+# ifdef DATADIR_DEFAULT
+  { 
+    char *datadir;
+    char *helpdir;
+    char *modules;
+    datadir = MACRO_NAME(DATADIR_DEFAULT);
+    /* set_str_variable ("DATADIR", datadir); */
+    ALLOCATE (helpdir, char, strlen(datadir) + strlen("/help") + 2);
+    sprintf (helpdir, "%s/help", datadir);
+    set_str_variable ("HELPDIR", helpdir);
+    free (helpdir);
+    ALLOCATE (modules, char, strlen(datadir) + strlen("/modules") + 2);
+    sprintf (modules, "%s/modules", datadir);
+    set_str_variable ("MODULES:0", modules);
+    set_int_variable ("MODULES:n", 1);
+    free (helpdir);
+  }
 # endif
 
@@ -33,4 +52,9 @@
   signal (SIGTSTP, gotsignal);
   signal (SIGTTIN, gotsignal);
+
+  /* start up the background threads here */
+  pthread_create (&tasksThread,      NULL, &CheckTasksThread, 	   NULL);
+  pthread_create (&jobsThread,       NULL, &CheckJobsThread, 	   NULL);
+  pthread_create (&controllerThread, NULL, &CheckControllerThread, NULL);
   return;
 }
@@ -61,2 +85,9 @@
   exit (status);
 }
+
+/* pantasks runs three (or four) threads:
+   - one thread parses commands from the connected clients
+   - one thread runs the scheduler loop
+   - one thread may run the controller loop independently
+   - the main thread runs readline and accepts user input
+*/
Index: trunk/Ohana/src/opihi/pantasks/pantasks_client.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/pantasks_client.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/pantasks_client.c	(revision 11084)
@@ -25,6 +25,21 @@
   set_str_variable ("RCFILE", opihi_rcfile);
 
-# ifdef HELPDIR_DEFAULT
-  set_str_variable ("HELPDIR", MACRO_NAME(HELPDIR_DEFAULT));
+# ifdef DATADIR_DEFAULT
+  {
+      char *datadir;
+      char *helpdir;
+      char *modules;
+      datadir = MACRO_NAME(DATADIR_DEFAULT);
+      /* set_str_variable ("DATADIR", datadir); */
+      ALLOCATE (helpdir, char, strlen(datadir) + strlen("/help") + 2);
+      sprintf (helpdir, "%s/help", datadir);
+      set_str_variable ("HELPDIR", helpdir);
+      free (helpdir);
+      ALLOCATE (modules, char, strlen(datadir) + strlen("/modules") + 2);
+      sprintf (modules, "%s/modules", datadir);
+      set_str_variable ("MODULES:0", modules);
+      set_int_variable ("MODULES:n", 1);
+      free (helpdir);
+  }
 # endif
 
Index: trunk/Ohana/src/opihi/pantasks/pantasks_server.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/pantasks_server.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/pantasks_server.c	(revision 11084)
@@ -16,8 +16,8 @@
 int main (int argc, char **argv) {
   
+  pthread_t jobsThread;
+  pthread_t tasksThread;
+  pthread_t inputsThread;
   pthread_t clientsThread;
-  pthread_t tasksThread;
-  // pthread_t jobsThread;
-  pthread_t inputsThread;
   pthread_t controllerThread;
   int InitSocket, BindSocket;
@@ -47,5 +47,5 @@
   pthread_create (&clientsThread,    NULL, &ListenClients,    	   NULL);
   pthread_create (&tasksThread,      NULL, &CheckTasksThread, 	   NULL);
-  // pthread_create (&jobsThread,       NULL, &CheckJobsThread,  	   NULL);
+  pthread_create (&jobsThread,       NULL, &CheckJobsThread,  	   NULL);
   pthread_create (&controllerThread, NULL, &CheckControllerThread, NULL);
   pthread_create (&inputsThread,     NULL, &CheckInputsThread,     NULL);
Index: trunk/Ohana/src/opihi/pantasks/run.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/run.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/run.c	(revision 11084)
@@ -15,6 +15,10 @@
   }
 
-  InitTaskTimers ();
-  rl_event_hook = CheckSystem;
+  CheckTasksSetState (TRUE);
+  CheckControllerSetState (TRUE);
+  CheckJobsSetState (TRUE);
+
+  // InitTaskTimers ();
+  // rl_event_hook = CheckSystem;
 
   return (TRUE);
Index: trunk/Ohana/src/opihi/pantasks/server.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/server.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/server.c	(revision 11084)
@@ -7,4 +7,5 @@
 int server_run	    PROTO((int, char **));
 int server_stop	    PROTO((int, char **));
+int server_halt	    PROTO((int, char **));
 int cd              PROTO((int, char **));
 int pwd        	    PROTO((int, char **));
@@ -20,4 +21,5 @@
   {"run",    server_run,  "run scheduler"},
   {"stop",   server_stop, "stop scheduler"},
+  {"halt",   server_halt, "halt scheduler"},
   {"cd",     cd,     "set local directory"},
   {"pwd",    pwd,    "check local directory"},
Index: trunk/Ohana/src/opihi/pantasks/server_run.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/server_run.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/server_run.c	(revision 11084)
@@ -9,5 +9,5 @@
 
   CheckTasksSetState (TRUE);
-  // CheckJobsSetState (TRUE);
+  CheckJobsSetState (TRUE);
   CheckControllerSetState (TRUE);
   CheckInputsSetState (TRUE);
@@ -24,4 +24,18 @@
   CheckTasksSetState (FALSE);
   // CheckJobsSetState (FALSE);
+  // CheckControllerSetState (FALSE);
+  CheckInputsSetState (FALSE);
+  return (TRUE);
+}
+
+int server_halt (int argc, char **argv) {
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: server halt\n");
+    return (FALSE);
+  }
+
+  CheckTasksSetState (FALSE);
+  CheckJobsSetState (FALSE);
   CheckControllerSetState (FALSE);
   CheckInputsSetState (FALSE);
Index: trunk/Ohana/src/opihi/pantasks/status.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/status.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/status.c	(revision 11084)
@@ -4,8 +4,15 @@
 
   gprint (GP_LOG, "\n");
-  if (rl_event_hook == NULL) {
-    gprint (GP_LOG, " Scheduler is stopped\n");
+
+  // if (rl_event_hook == NULL) {
+
+  if (CheckTasksGetState()) {
+    gprint (GP_LOG, " Scheduler is running\n");
   } else {
-    gprint (GP_LOG, " Scheduler is running\n");
+    if (CheckJobsGetState()) {
+      gprint (GP_LOG, " Scheduler is stopped, harvesting jobs\n");
+    } else {
+      gprint (GP_LOG, " Scheduler is running\n");
+    }
   }
   if (CheckControllerStatus()) {
Index: trunk/Ohana/src/opihi/pantasks/stop.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/stop.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/stop.c	(revision 11084)
@@ -8,6 +8,22 @@
   }
 
-  rl_event_hook = NULL;
+  CheckTasksSetState (FALSE);
+  // CheckControllerSetState (FALSE);
+  // CheckJobsSetState (FALSE);
 
   return (TRUE);
 }
+
+int halt (int argc, char **argv) {
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: halt\n");
+    return (FALSE);
+  }
+
+  CheckTasksSetState (FALSE);
+  CheckControllerSetState (FALSE);
+  CheckJobsSetState (FALSE);
+
+  return (TRUE);
+}
Index: trunk/Ohana/src/opihi/pantasks/task.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/task.c	(revision 11055)
+++ trunk/Ohana/src/opihi/pantasks/task.c	(revision 11084)
@@ -23,5 +23,9 @@
   if ((N = get_argument (argc, argv, "-stats"))) {
     remove_argument (N, &argc, argv);
-    ListTaskStats ();
+    if (argc == 2) {
+      ListTaskStats (argv[N]);
+    } else {
+      ListTaskStats (NULL);
+    }      
     return (TRUE);
   }
Index: trunk/Ohana/src/opihi/pantasks/task_threads.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/task_threads.c	(revision 11084)
+++ trunk/Ohana/src/opihi/pantasks/task_threads.c	(revision 11084)
@@ -0,0 +1,40 @@
+# include "pantasks.h"
+
+/** things related to CheckTasks **/
+
+static int CheckTasksRun = FALSE;
+
+void CheckTasksSetState (int state) {
+  CheckTasksRun = state;
+}
+int CheckTasksGetState () {
+  return (CheckTasksRun);
+}
+
+void *CheckTasksThread (void *data) {
+
+  gprintInit ();  // each thread needs to init the printing system
+  while (1) {
+
+    // check for thread suspend
+    if (!CheckTasksRun) {
+      usleep (100000); // idle if thread action is suspended
+      continue;
+    }
+
+    // one run of the task checker
+    SerialThreadLock ();
+    CheckTasks ();
+    SerialThreadUnlock ();
+    usleep (10000); // allow other threads a chance to run
+  }
+}
+
+/* the threaded version of pantasks does not worry about limiting the 
+   time spent in one of the test loops -- comms with the client are
+   in a separate thread anyway...
+*/
+
+int TestElapsedCheck () {
+  return (FALSE);
+}
Index: trunk/Ohana/src/opihi/pantasks/thread_locks.c
===================================================================
--- trunk/Ohana/src/opihi/pantasks/thread_locks.c	(revision 11084)
+++ trunk/Ohana/src/opihi/pantasks/thread_locks.c	(revision 11084)
@@ -0,0 +1,14 @@
+# include "pantasks.h"
+
+/* this mutex is used by the serialized threads */
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void SerialThreadLock () {
+    pthread_mutex_lock (&mutex);
+}
+
+void SerialThreadUnlock () {
+    pthread_mutex_unlock (&mutex);
+}
+
