Index: /branches/eam_branches/20091201/Ohana/src/opihi/include/pcontrol.h
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/include/pcontrol.h	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/include/pcontrol.h	(revision 26715)
@@ -98,4 +98,14 @@
   int          requested;
 } JobOutput;
+
+/* A machine has a unique name and may have multiple Hosts (each of which can run a single job)
+   We use this to track aspects of the analysis per machine, to eg, limit the number of jobs 
+   desired on a single machine */
+typedef struct {
+  char *name;
+  int Nhosts;		      // how many hosts are selected for this machine (whatever state)
+  int NjobsRealhost;
+  int NjobsWanthost;
+} Machine;
 
 /* data to define a job */
@@ -140,4 +150,5 @@
 } Host;
 
+/* the Jobs and Hosts are managed in a set of Stacks which define their state */
 typedef struct {
   void **object;
@@ -280,4 +291,24 @@
 void   LinkJobAndHost (Job *job, Host *host);
 
+/*** MachineOps.c ***/
+void InitMachines ();
+void FreeMachines ();
+Machine *FindMachineByName (char *name);
+Machine *AddMachine (char *name);
+int DelMachine (char *name);
+int AddMachineHost (Host *host);
+int DelMachineHost (Host *host);
+int AddMachineJob (Host *host, Job *job);
+int DelMachineJob (Host *host, Job *job);
+int PrintMachines ();
+int CheckMachineJobs (Host *host, Job *job);
+int GetMaxUnwantedHostJobs (void);
+void SetMaxUnwantedHostJobs (int value);
+
+float GetMaxConnectTime (void);
+void SetMaxConnectTime (float value);
+float GetMaxWantHostWait (void);
+void SetMaxWantHostWait (float value);
+
 void pcontrol_exit (int n);
 
Index: /branches/eam_branches/20091201/Ohana/src/opihi/lib.shell/ListOps.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/lib.shell/ListOps.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/lib.shell/ListOps.c	(revision 26715)
@@ -3,6 +3,6 @@
 
 /*** local static variables used to track the command lists  ***/
-static List *lists;			/* variable to store the list of all lists */
-static int  Nlists;			/* number of currently available lists */
+static List *lists = NULL;	/* variable to store the list of all lists */
+static int  Nlists = 0;		/* number of currently available lists */
 
 void InitLists () {
@@ -16,5 +16,7 @@
   int i, j;
 
-  for (i = 0; i < Nlists; i++) {
+  // Nlists is a bit weird: it is the currently highest valid list, not the number of lists
+  // Nlists = 0 is never allocated
+  for (i = 1; i < Nlists + 1; i++) {
     for (j = 0; j < lists[i].Nlines; j++) {
       free (lists[i].line[j]);
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/Makefile
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/Makefile	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/Makefile	(revision 26715)
@@ -73,4 +73,8 @@
 $(SRC)/controller_status.$(ARCH).o \
 $(SRC)/controller_jobstack.$(ARCH).o \
+$(SRC)/controller_hoststack.$(ARCH).o \
+$(SRC)/controller_machines.$(ARCH).o \
+$(SRC)/controller_parameters.$(ARCH).o \
+$(SRC)/controller_version.$(ARCH).o \
 $(SRC)/controller_verbose.$(ARCH).o \
 $(SRC)/controller_run.$(ARCH).o \
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller.c	(revision 26715)
@@ -1,26 +1,36 @@
 # include "pantasks.h"
 
-int controller_host    	PROTO((int, char **));
-int controller_exit    	PROTO((int, char **));
-int controller_status  	PROTO((int, char **));
-int controller_jobstack PROTO((int, char **));
-int controller_verbose  PROTO((int, char **));
-int controller_run     	PROTO((int, char **));
-int controller_stop    	PROTO((int, char **));
-int controller_check   	PROTO((int, char **));
-int controller_output  	PROTO((int, char **));
-int controller_pulse   	PROTO((int, char **));
+int controller_host    	  PROTO((int, char **));
+int controller_exit    	  PROTO((int, char **));
+int controller_status  	  PROTO((int, char **));
+int controller_jobstack   PROTO((int, char **));
+int controller_hoststack  PROTO((int, char **));
+int controller_machines   PROTO((int, char **));
+int controller_parameters PROTO((int, char **));
+int controller_verbose    PROTO((int, char **));
+int controller_version    PROTO((int, char **));
+int controller_run     	  PROTO((int, char **));
+int controller_stop    	  PROTO((int, char **));
+int controller_check   	  PROTO((int, char **));
+int controller_output  	  PROTO((int, char **));
+int controller_pulse   	  PROTO((int, char **));
 
 static Command controller_cmds[] = {
-  {1, "exit",     controller_exit,     "shutdown controller"},
-  {1, "host",     controller_host,     "define host for controller"},
-  {1, "check",    controller_check,    "check controller host/job"},
-  {1, "run",      controller_run,      "start controller operation / set run levels"},
-  {1, "stop",     controller_run,      "stop controller (no disconnect)"},
-  {1, "status",   controller_status,   "check controller status"},
-  {1, "jobstack", controller_jobstack, "check controller status"},
-  {1, "verbose",  controller_verbose,  "set controller verbosity"},
-  {1, "output",   controller_output,   "print controller output"},
-  {1, "pulse",    controller_pulse,    "set controller pulse"},
+  {1, "check",     controller_check,      "check controller host/job"},
+  // {1, "delete",    controller_delete,   "delete job on controller"},
+  {1, "exit",      controller_exit,       "shutdown controller"},
+  {1, "host",      controller_host,       "define host for controller"},
+  {1, "hoststack", controller_hoststack,  "define host for controller"},
+  // {1, "job",       controller_job,      "add jobs to controller"},
+  {1, "jobstack",  controller_jobstack,   "check controller status"},
+  {1, "machines",  controller_machines,   "print controller machine status"},
+  {1, "parameters",controller_parameters, "modify controller parameters"},
+  {1, "output",    controller_output,     "print controller output"},
+  {1, "run",       controller_run,        "start controller operation / set run levels"},
+  {1, "status",    controller_status,     "check controller status"},
+  {1, "stop",      controller_run,        "stop controller (no disconnect)"},
+  {1, "verbose",   controller_verbose,    "set controller verbosity"},
+  {1, "version",   controller_version,    "show controller version"},
+  {1, "pulse",     controller_pulse,      "set controller pulse"},
 };
 
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_hoststack.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_hoststack.c	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_hoststack.c	(revision 26715)
@@ -0,0 +1,35 @@
+# include "pantasks.h"
+
+int controller_hoststack (int argc, char **argv) {
+
+  int status;
+  char command[1024];
+  IOBuffer buffer;
+
+  if (argc != 2) {
+    gprint (GP_ERR, "USAGE: controller hoststack (hoststack)\n");
+    gprint (GP_ERR, "       (hoststack) : pending, busy, exit, crash, hung, done\n");
+    return (FALSE);
+  }
+
+  /* check if controller is running */
+  status = CheckControllerStatus ();
+  if (!status) {
+    gprint (GP_LOG, "controller is not active\n");
+    return (TRUE);
+  }
+
+  // XXX this has an error?  test this out...
+  sprintf (command, "hoststack %s", argv[1]);
+  InitIOBuffer (&buffer, 0x100);
+
+  status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
+
+  if (status) {
+    gwrite (buffer.buffer, 1, buffer.Nbuffer, GP_LOG);
+  } else {
+    gprint (GP_LOG, "controller is not communicating\n");
+  }
+  FreeIOBuffer (&buffer);
+  return (TRUE);
+}
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_machines.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_machines.c	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_machines.c	(revision 26715)
@@ -0,0 +1,35 @@
+# include "pantasks.h"
+
+int controller_machines (int argc, char **argv) {
+
+  int status;
+  char command[1024];
+  IOBuffer buffer;
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: controller machines\n");
+    gprint (GP_ERR, "       prints status of controller machines\n");
+    return (FALSE);
+  }
+
+  /* check if controller is running */
+  status = CheckControllerStatus ();
+  if (!status) {
+    gprint (GP_LOG, "controller is not active\n");
+    return (TRUE);
+  }
+
+  // XXX this has an error?  test this out...
+  sprintf (command, "machines");
+  InitIOBuffer (&buffer, 0x100);
+
+  status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
+
+  if (status) {
+    gwrite (buffer.buffer, 1, buffer.Nbuffer, GP_LOG);
+  } else {
+    gprint (GP_LOG, "controller is not communicating\n");
+  }
+  FreeIOBuffer (&buffer);
+  return (TRUE);
+}
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_parameters.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_parameters.c	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_parameters.c	(revision 26715)
@@ -0,0 +1,46 @@
+# include "pantasks.h"
+
+int controller_parameters (int argc, char **argv) {
+
+  int status;
+  char command[1024];
+  IOBuffer buffer;
+
+  if (argc < 2) goto usage;
+  if (argc > 4) goto usage;
+  if (argc == 3) goto usage;
+  if ((argc == 4) && strcmp(argv[2], "=")) goto usage;
+
+  /* check if controller is running */
+  status = CheckControllerStatus ();
+  if (!status) {
+    gprint (GP_LOG, "controller is not active\n");
+    return (TRUE);
+  }
+
+  // XXX this has an error?  test this out...
+  if (argc == 2) {
+    sprintf (command, "parameters %s", argv[1]);
+  } else {
+    sprintf (command, "parameters %s = %s", argv[1], argv[3]);
+  }
+  InitIOBuffer (&buffer, 0x100);
+
+  status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
+
+  if (status) {
+    gwrite (buffer.buffer, 1, buffer.Nbuffer, GP_LOG);
+  } else {
+    gprint (GP_LOG, "controller is not communicating\n");
+  }
+  FreeIOBuffer (&buffer);
+  return (TRUE);
+
+  usage:
+
+  gprint (GP_LOG, "USAGE: controller parameters (param) [= value])\n");
+  gprint (GP_LOG, "  valid parameters: connect_time, wanthost_wait, unwanted_host_jobs\n");
+  gprint (GP_LOG, "  (minimum matching word is allowed)\n");
+  gprint (GP_LOG, "  example: controller parameters connect = 2.0\n");
+  return (FALSE);
+}
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_version.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_version.c	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pantasks/controller_version.c	(revision 26715)
@@ -0,0 +1,34 @@
+# include "pantasks.h"
+
+int controller_version (int argc, char **argv) {
+
+  int status;
+  char command[1024];
+  IOBuffer buffer;
+
+  if (argc != 1) {
+    gprint (GP_ERR, "USAGE: controller version\n");
+    return (FALSE);
+  }
+
+  /* check if controller is running */
+  status = CheckControllerStatus ();
+  if (!status) {
+    gprint (GP_LOG, "controller is not active\n");
+    return (TRUE);
+  }
+
+
+  sprintf (command, "version");
+  InitIOBuffer (&buffer, 0x100);
+
+  status = ControllerCommand (command, CONTROLLER_PROMPT, &buffer);
+
+  if (status) {
+    gwrite (buffer.buffer, 1, buffer.Nbuffer, GP_LOG);
+  } else {
+    gprint (GP_LOG, "controller is not communicating\n");
+  }
+  FreeIOBuffer (&buffer);
+  return (TRUE);
+}
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckDoneJob.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckDoneJob.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckDoneJob.c	(revision 26715)
@@ -28,4 +28,8 @@
 
   if ((status1 == PCLIENT_DOWN) || (status2 == PCLIENT_DOWN)) {
+
+    // decrement the machine job-host counters
+    DelMachineJob (host, job);
+
     // unlink host & job
     if (DEBUG || VerboseMode()) gprint (GP_ERR, "host %s is down\n", host[0].hostname);
@@ -53,4 +57,7 @@
   }
 
+  // decrement the machine job-host counters
+  DelMachineJob (host, job);
+
   /* job's state is either EXIT or CRASH (verify?) */
   // unlink host & job
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckIdleHost.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckIdleHost.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckIdleHost.c	(revision 26715)
@@ -1,11 +1,11 @@
 # include "pcontrol.h"
 
-// The connection to the remote host is only allow to live for MAX_CONNECT_TIME seconds.  We
-// disconnect and reconnect if a remote host has been connected for too long.  This is a
-// (temporary?) work-around for the problem that the remote pclient job tends to grow too large
-// over time.
+// The connection to the remote host is only allowed to live for MAX_CONNECT_TIME seconds.
+// We disconnect and reconnect if a remote host has been connected for too long.  This is
+// a (temporary?) work-around for the problem that the remote pclient job tends to grow
+// too large over time.
 
-# define MAX_CONNECT_TIME 36000.0
-
+static float MAX_WANTHOST_WAIT = 10.0;
+static float MAX_CONNECT_TIME = 36000.0;
 static FILE *logfile = NULL;
 
@@ -70,4 +70,5 @@
 
     // if (logfile) fprintf (logfile, "start needhost %s (job host %s) : %s\n", host[0].hostname, job[0].hostname, job[0].argv[0]);
+    AddMachineJob (host, job);
 
     /* take the job off the stack and unlock the stack */
@@ -90,4 +91,5 @@
 
     // if (logfile) fprintf (logfile, "start wanthost %s (job host %s) : %s\n", host[0].hostname, job[0].hostname, job[0].argv[0]);
+    AddMachineJob (host, job);
 
     /* take the job off the stack and unlock the stack */
@@ -103,4 +105,6 @@
     if (job[0].mode != PCONTROL_JOB_ANYHOST) continue;
 
+    if (!CheckMachineJobs (host, job)) continue;
+
     /* we have found an appropriate job; link it to the host and send to StartJob */
     job[0].host = (struct Host *) host;
@@ -108,4 +112,5 @@
 
     // if (logfile) fprintf (logfile, "start  anyhost %s (job host %s) : %s\n", host[0].hostname, job[0].hostname, job[0].argv[0]);
+    AddMachineJob (host, job);
 
     /* take the job off the stack and unlock the stack */
@@ -124,7 +129,10 @@
     gettimeofday (&now, (void *) NULL);
     dtime = DTIME (now, job[0].start);
-    if (dtime < 10.0) continue;
+    if (dtime < MAX_WANTHOST_WAIT) continue;
+
+    if (!CheckMachineJobs (host, job)) continue;
 
     if (logfile) fprintf (logfile, "start wanthost(2) %s (job host %s) : %s\n", host[0].hostname, job[0].hostname, job[0].argv[0]);
+    AddMachineJob (host, job);
 
     /* we have found an appropriate job; link it to the host and send to StartJob */
@@ -145,4 +153,26 @@
 }
 
+void SetMaxWantHostWait (float value) {
+
+  MAX_WANTHOST_WAIT = value;
+  return;
+}
+
+float GetMaxWantHostWait (void) {
+
+  return MAX_WANTHOST_WAIT;
+}
+
+void SetMaxConnectTime (float value) {
+
+  MAX_CONNECT_TIME = value;
+  return;
+}
+
+float GetMaxConnectTime (void) {
+
+  return MAX_CONNECT_TIME;
+}
+
 /** note : host and job popped off IDLE and PENDING stacks, 
     unless no job is available **/
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckSystem.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckSystem.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/CheckSystem.c	(revision 26715)
@@ -122,8 +122,10 @@
     if (!Njobchecks && !Nhostchecks && (RunLevel != PCONTROL_RUN_NONE)) {
       CheckLiveHosts(0.040);
+      // fprintf (stderr, "sleep a bit\n");
       usleep (100000); // idle if no jobs are waiting
     } else {
       // if we only have busy jobs, pause a moment before trying again
       if (!Ndonejobs) {
+	// fprintf (stderr, "sleep a bit\n");
 	usleep (100000);
       }
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/HostOps.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/HostOps.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/HostOps.c	(revision 26715)
@@ -214,4 +214,6 @@
   host[0].job      = NULL;
 
+  AddMachineHost (host);
+
   PutHost (host, PCONTROL_HOST_ALLHOSTS, STACK_BOTTOM);
   PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
@@ -225,4 +227,6 @@
   copy = PullStackByID (HostPool_AllHosts, host[0].HostID);
   ASSERT (copy == host, "programming error: ALLHOSTS entry does not match");
+
+  DelMachineHost (host);
 
   FreeIOBuffer (&host[0].comms_buffer);
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/KillJob.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/KillJob.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/KillJob.c	(revision 26715)
@@ -19,4 +19,8 @@
       job[0].host = NULL;
       host[0].job = NULL;
+
+      // decrement the machine job-host counters
+      DelMachineJob (host, job);
+
       HarvestHost (host[0].pid);
       PutHost (host, PCONTROL_HOST_DOWN, STACK_BOTTOM);
@@ -74,4 +78,8 @@
       job[0].host = NULL;
       host[0].job = NULL;
+
+      // decrement the machine job-host counters
+      DelMachineJob (host, job);
+
       PutHost (host, PCONTROL_HOST_IDLE, STACK_BOTTOM);
       PutJob (job, PCONTROL_JOB_CRASH, STACK_BOTTOM);
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/MachineOps.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/MachineOps.c	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/MachineOps.c	(revision 26715)
@@ -0,0 +1,207 @@
+# include "pcontrol.h"
+
+static int MAX_UNWANTED_HOST_JOBS = 5;
+
+static Machine **machines = NULL;
+static int      Nmachines = 0;
+static int      NMACHINES = 0;
+
+void InitMachines () {
+
+  if (machines != NULL) return;
+
+  NMACHINES = 10;
+  Nmachines =  0;
+
+  ALLOCATE (machines, Machine *, NMACHINES);
+  memset (machines, 0, NMACHINES*sizeof(Machine *));
+
+  return;
+}
+
+void FreeMachines () {
+
+  int i;
+
+  for (i = 0; i < NMACHINES; i++) {
+    FREE (machines[i]);
+  }
+  FREE (machines);
+
+  return;
+}
+
+// find a machine matching the given name (if not found, return NULL)
+Machine *FindMachineByName (char *name) {
+
+  int i;
+
+  for (i = 0; i < Nmachines; i++) {
+    if (!strcmp (machines[i][0].name, name)) {
+      return machines[i];
+    }
+  }
+  return NULL;
+}
+
+// add a new machine (if not new, return TRUE)
+Machine *AddMachine (char *name) {
+
+  Machine *machine;
+
+  machine = FindMachineByName (name);
+  if (machine) return machine;
+
+  ALLOCATE (machines[Nmachines], Machine, 1);
+  machines[Nmachines][0].name = strcreate (name);
+  machines[Nmachines][0].Nhosts = 0;
+  machines[Nmachines][0].NjobsRealhost = 0;
+  machines[Nmachines][0].NjobsWanthost = 0;
+
+  machine = machines[Nmachines];
+  Nmachines ++;
+
+  if (Nmachines >= NMACHINES - 1) {
+    NMACHINES += 10;
+    REALLOCATE (machines, Machine *, NMACHINES);
+    memset (&machines[Nmachines], 0, (NMACHINES - Nmachines)*sizeof(Machine *));
+  }
+
+  return machine;
+}
+
+// delete a new machine (if not new, return TRUE)
+int DelMachine (char *name) {
+
+  return TRUE;
+}
+
+int AddMachineHost (Host *host) {
+
+  Machine *machine;
+
+  // find or add machine matching this host name
+  machine = AddMachine (host[0].hostname); // Can this fail?
+  machine[0].Nhosts ++;
+  // XXX do we need this? host[0].machine = machine;
+  return (TRUE);
+}
+
+int DelMachineHost (Host *host) {
+
+  Machine *machine;
+
+  // machine = host[0].machine;
+  machine = FindMachineByName (host[0].hostname);
+  if (machine == NULL) return (FALSE);
+
+  machine[0].Nhosts --;
+  if (machine[0].Nhosts < 0) {
+    fprintf (stderr, "warning: mis-match in host count for machine %s\n", machine[0].name);
+    machine[0].Nhosts = 0;
+  }
+
+  return (TRUE);
+}
+
+int AddMachineJob (Host *host, Job *job) {
+
+  Machine *machine;
+
+  // find machine matching the real host name
+  machine = FindMachineByName (host[0].hostname); // Can this fail?
+  ASSERT (machine, "cannot find machine associated with host");
+  machine[0].NjobsRealhost ++;
+
+  // skip jobs that do not have a targeted host
+  if (job[0].hostname == NULL) {
+    return (TRUE);
+  }
+
+  // do not double count jobs on the wanted host
+  if (!strcmp (job[0].hostname, host[0].hostname)) {
+    return (TRUE);
+  }
+
+  // find machine matching the want host name (these are running on an unwanted host)
+  machine = FindMachineByName (job[0].hostname); // Can this fail?
+  if (machine == NULL) return (TRUE);
+  machine[0].NjobsWanthost ++;
+
+  return (TRUE);
+}
+
+int DelMachineJob (Host *host, Job *job) {
+
+  Machine *machine;
+
+  // find machine matching the real host name
+  machine = FindMachineByName (host[0].hostname); // Can this fail?
+  ASSERT (machine, "cannot find machine associated with host");
+  machine[0].NjobsRealhost --;
+
+  // skip jobs that do not have a targeted host
+  if (job[0].hostname == NULL) {
+    return (TRUE);
+  }
+
+  // do not double count jobs on the wanted host
+  if (!strcmp (job[0].hostname, host[0].hostname)) {
+    return (TRUE);
+  }
+
+  // find machine matching the want host name
+  machine = FindMachineByName (job[0].hostname); // Can this fail?
+  if (machine == NULL) return (TRUE);
+  machine[0].NjobsWanthost --;
+
+  return (TRUE);
+}
+
+int PrintMachines () {
+
+  int i;
+  Machine *machine;
+
+  gprint (GP_LOG, "Nmachines: %d\n", Nmachines);
+  for (i = 0; i < Nmachines; i++) {
+    machine = machines[i];
+    gprint (GP_LOG, "%s : %d : %d : %d\n", machine[0].name, machine[0].Nhosts, machine[0].NjobsRealhost, machine[0].NjobsWanthost);
+  }
+
+  return (TRUE);
+}
+
+int CheckMachineJobs (Host *host, Job *job) {
+
+  Machine *machine;
+
+  machine = FindMachineByName (job[0].hostname);
+  if (machine == NULL) return (TRUE);
+  // fprintf (stderr, "wanthost: %s, Ntotal: %d, Nmax: %d\n", job[0].hostname, machine[0].NjobsWanthost + machine[0].NjobsRealhost, machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS);
+  // if (machine[0].NjobsWanthost + machine[0].NjobsRealhost >= machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS) {
+  if (machine[0].NjobsWanthost >= MAX_UNWANTED_HOST_JOBS) {
+    // fprintf (stderr, "too many outstanding jobs wanting host %s, delay job %s for now\n", job[0].hostname, job[0].argv[0]);
+    return (FALSE);
+  }
+
+  machine = FindMachineByName (host[0].hostname);
+  // fprintf (stderr, "realhost: %s, Ntotal: %d, Nmax: %d\n", host[0].hostname, machine[0].NjobsWanthost + machine[0].NjobsRealhost, machine[0].Nhosts + MAX_UNWANTED_HOST_JOBS);
+  if (machine[0].NjobsWanthost >= MAX_UNWANTED_HOST_JOBS) {
+    // fprintf (stderr, "too many outstanding jobs wanting host %s, delay job %s for now\n", job[0].hostname, job[0].argv[0]);
+    return (FALSE);
+  }
+  return (TRUE);
+}
+
+void SetMaxUnwantedHostJobs (int value) {
+
+  MAX_UNWANTED_HOST_JOBS = value;
+  return;
+}
+
+int GetMaxUnwantedHostJobs (void) {
+
+  return MAX_UNWANTED_HOST_JOBS;
+}
+
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/Makefile
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/Makefile	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/Makefile	(revision 26715)
@@ -37,4 +37,5 @@
 $(SRC)/IDops.$(ARCH).o \
 $(SRC)/JobOps.$(ARCH).o \
+$(SRC)/MachineOps.$(ARCH).o \
 $(SRC)/StackOps.$(ARCH).o \
 $(SRC)/PclientCommand.$(ARCH).o \
@@ -53,5 +54,7 @@
 $(SRC)/kill.$(ARCH).o \
 $(SRC)/pulse.$(ARCH).o \
+$(SRC)/parameters.$(ARCH).o \
 $(SRC)/run.$(ARCH).o \
+$(SRC)/machines.$(ARCH).o \
 $(SRC)/status.$(ARCH).o \
 $(SRC)/stdout.$(ARCH).o \
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/host.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/host.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/host.c	(revision 26715)
@@ -96,6 +96,6 @@
 usage:
   gprint (GP_LOG, "USAGE: host (command) (hostname)\n");
-  gprint (GP_ERR, "  valid commands: add, on, retry, check, off, delete\n");
-  gprint (GP_ERR, "  -threads Nthreads is optional for 'add'\n");
+  gprint (GP_LOG, "  valid commands: add, on, retry, check, off, delete\n");
+  gprint (GP_LOG, "  -threads Nthreads is optional for 'add'\n");
   return (FALSE);
 }
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/init.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/init.c	(revision 26714)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/init.c	(revision 26715)
@@ -8,6 +8,8 @@
 int jobstack    PROTO((int, char **));
 int kill_pc     PROTO((int, char **));
+int machines    PROTO((int, char **));
+int parameters  PROTO((int, char **));
+int run         PROTO((int, char **));
 int status      PROTO((int, char **));
-int run         PROTO((int, char **));
 int stderr_pc   PROTO((int, char **));
 int stdout_pc   PROTO((int, char **));
@@ -19,20 +21,22 @@
 
 static Command cmds[] = {  
-  {1, "host",      host,      "add / delete / modify host"},
-  {1, "hoststack", hoststack, "list hosts for a single stack"},
-  {1, "status",    status,    "get system status"},
-  {1, "stop",      run,       "stop controller processing"},
-  {1, "run",       run,       "set controller runlevel"},
-  {1, "verbose",   verbose,   "set the verbose mode for job"},
-  {1, "version",   version,   "show version information"},
-  {1, "job",       job,       "add job"},
-  {1, "jobstack",  jobstack,  "list jobs for a single stack"},
-  {1, "check",     check,     "get job or host status"},
-  {1, "delete",    delete,    "delete job"},
-  {1, "kill",      kill_pc,   "kill job"},
-  {1, "stderr",    stderr_pc, "get stderr buffer for job"},
-  {1, "stdout",    stdout_pc, "get stdout buffer for job"},
-# ifndef THREADED
-  {1, "pulse",     pulse,     "set system pulse"},
+  {1, "check",      check,      "get job or host status"},
+  {1, "delete",     delete,     "delete job"},
+  {1, "host",       host,       "add / delete / modify host"},
+  {1, "hoststack",  hoststack,  "list hosts for a single stack"},
+  {1, "job",        job,        "add job"},
+  {1, "jobstack",   jobstack,   "list jobs for a single stack"},
+  {1, "kill",       kill_pc,    "kill job"},
+  {1, "machines",   machines,   "list machines"},
+  {1, "parameters", parameters, "get / set system parameters"},
+  {1, "run",        run,        "set controller runlevel"},
+  {1, "status",     status,     "get system status"},
+  {1, "stderr",     stderr_pc,  "get stderr buffer for job"},
+  {1, "stdout",     stdout_pc,  "get stdout buffer for job"},
+  {1, "stop",       run,        "stop controller processing"},
+  {1, "verbose",    verbose,    "set the verbose mode for job"},
+  {1, "version",    version,    "show version information"},
+# ifndef THREADED   	        
+  {1, "pulse",      pulse,      "set system pulse"},
 # endif
 }; 
@@ -47,4 +51,5 @@
   InitJobStacks ();
   InitHostStacks ();
+  InitMachines ();
 }
 
@@ -52,3 +57,4 @@
   FreeJobStacks ();
   FreeHostStacks ();
+  FreeMachines ();
 }
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/machines.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/machines.c	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/machines.c	(revision 26715)
@@ -0,0 +1,9 @@
+# include "pcontrol.h"
+
+int machines (int argc, char **argv) {
+
+  PrintMachines ();
+
+  return (TRUE);
+}
+
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/parameters.c
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/parameters.c	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/parameters.c	(revision 26715)
@@ -0,0 +1,57 @@
+# include "pcontrol.h"
+
+int parameters (int argc, char **argv) {
+
+  int ivalue;
+  float value;
+
+  if (argc < 2) goto usage;
+  if (argc > 4) goto usage;
+  if (argc == 3) goto usage;
+  if ((argc == 4) && strcmp(argv[2], "=")) goto usage;
+
+  if (!strncasecmp (argv[1], "connect_time", strlen(argv[1]))) {
+    if (argc == 2) {
+      value = GetMaxConnectTime();
+      gprint (GP_LOG, "Max Connect Time : %f\n", value);
+      return (TRUE);
+    }
+
+    value = atof(argv[3]);
+    SetMaxConnectTime(value);
+    return (TRUE);
+  }
+
+  if (!strncasecmp (argv[1], "wanthost_wait", strlen(argv[1]))) {
+    if (argc == 2) {
+      value = GetMaxWantHostWait();
+      gprint (GP_LOG, "Max WantHost Wait : %f\n", value);
+      return (TRUE);
+    }
+
+    value = atof(argv[3]);
+    SetMaxWantHostWait(value);
+    return (TRUE);
+  }
+
+  if (!strncasecmp (argv[1], "unwanted_host_jobs", strlen(argv[1]))) {
+    if (argc == 2) {
+      ivalue = GetMaxUnwantedHostJobs();
+      gprint (GP_LOG, "Max Unwanted Host Jobs : %d\n", ivalue);
+      return (TRUE);
+    }
+
+    ivalue = atof(argv[3]);
+    SetMaxUnwantedHostJobs(ivalue);
+    return (TRUE);
+  }
+
+  usage:
+
+  gprint (GP_LOG, "USAGE: parameters (param) [= value])\n");
+  gprint (GP_LOG, "  valid parameters: connect_time, wanthost_wait, unwanted_host_jobs\n");
+  gprint (GP_LOG, "  (minimum matching word is allowed)\n");
+  gprint (GP_LOG, "  example: parameters connect = 2.0\n");
+  return (FALSE);
+}
+
Index: /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/test/machines.sh
===================================================================
--- /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/test/machines.sh	(revision 26715)
+++ /branches/eam_branches/20091201/Ohana/src/opihi/pcontrol/test/machines.sh	(revision 26715)
@@ -0,0 +1,27 @@
+
+macro load.hosts
+  parameters unwant = 1
+  parameters want = 2.0
+
+  host add pikake
+  host add pikake
+
+  host add ipp022
+  host add ipp022
+  host add ipp022
+  host add ipp022
+
+  machines
+end
+
+macro load.jobs
+  job -host pikake sleep 10
+  job -host pikake sleep 10
+  job -host pikake sleep 10
+  job -host pikake sleep 10
+  job -host pikake sleep 10
+  job -host pikake sleep 10
+  job -host pikake sleep 10
+  job -host pikake sleep 10
+end
+
