 Scheduler is based off of a proof-of-concept spawning system
 called "spawner".  The basic idea: load the tasks to process and
 spawn them off as individual processes.  The scheduler is single-threaded,
 but the spawned processes make processing happen in parallel.

 About the spawner process...
 Originally I used a script to spawn processes, but I found a bug.
 Bash has a problem: spawned processes have their return code
 generated before output handles are flushed.
 This means, shell "wait" may return before data is written
 by stdout/stderr.  This leads to a tight race condition where
 data used by one shell script step is not yet available.

 Example bash race condition:
 =====
 #!/bin/sh
 # Sometimes the wait completes before the contents of "file" is written.
 export MaxThread=2

 # Repeat the test 10 times -- some should fail (if no fail, re-run this script)
 for loop in 1 2 3 4 5 6 7 8 9 10 ; do
 # Initialize
 rm -f file* > /dev/null 2>&1
 Thread=0

 # The loop
 echo test | while read i ; do
  (date >> file$Thread) &
  ((Thread=$Thread+1))
  if [ "$Thread" -ge "$MaxThread" ] ; then
	wait
	Thread=0
  fi
 done
 wait  # ensure that all processes finish!
 # sync # enable a call to sync after the wait in order to bypass the problem

 cat file[0-9]* > file
 # display file contents
 echo "File contains:"
 cat file
 echo "EOF"
 done # end of loop
 =====

 As a workaround: "spawner".
 This program took a command-line that says the number of processes to
 spawn at any given time.
 Then it reads commands from stdin -- one command per line.
 All output is sent to stdout WHEN THE PROCESS FINISHES!
 All error is sent to stderr AS IT HAPPENS!

 Spawner stops:
   - When there is nothing left to stdin.
   - When any application ends with a non-zero return code.
 Spawner returns:
   - 0 if all processes ended with zero, or
   - Return code from first failed process.

 How spawner became the scheduler:
   - Data can come from stdin (for testing), but usually comes from the
     database job queue.
   - The jobs to spawn come from a configuration file.  The data only
     identifies the type of job and the parameters for it.
