<?php

require_once( "Fork.php" );

// Needed in order to use pcntl_signal()
declare (ticks 1);

//
// Worker thread.
//
class CopyThread extends PHP_Fork 
{
    
//
    // Constructor.
    //
    
function CopyThread$name )
    {
      
$this->PHP_Fork$name );
    }

    
//
    // Primary run function.
    //
    
function run()
    {
      
// Start with no pending job.
      
$this->setVariable'is_done'true );

      
// Do nothing.
      
while ( 
      {
        
$this->setAlive();
        
sleep);
      }

    }

    
//
    // Message handler to run a job.
    //
    
function RunJob$Job )
    {
      if ( 
$this->_isChild 
      {
        
// Thread is now in use.
        
$this->setVariable'is_done'false );

        
// Get job information.
        
$Job = &$Job];

        
// Copy file.
        
echo "Copying " $Job"From" ] . " " $Job"To" ] . "\n";
        
copy$Job"From" ] , $Job"To" ] );

        
// Done.
        
$this->setVariable'is_done'true );
      }
      else 
        
// Never change this line, it requires no adjustments...
        // (Yeah, I changed it anyway ;)
        
return $this->register_callback_funcfunc_get_args(), __FUNCTION__ );
    }

    
//
    // Get status of worker.
    // Returns true if thread is waiting for work.
    //
    
function GetDone()
    { 
      return 
$this->getVariable'is_done' );
    } 
}

//
// Thread pool.
// Interface to a pool of copying threads.
//
class ThreadPool
{
  var 
$CopyThreads;
  var 
$MaxThreads;

  
//
  // Waits for all running threads to finish.
  //
  
function WaitForThreadsToFinish()
  {
    
// While threads are running...
    
do
    {
      
$is_done true;
      for ( 
$Index 0$Index $this->MaxThreads$Index++ ) 
      {
        if ( 
false == $this->CopyThreads$Index ]->GetDone() )
          
$is_done false;
      }

      if ( ! 
$is_done )
        
sleep);
    } 
    while ( ! 
$is_done );
  }

  
//
  // Add a file to the list of files to be copied.
  // This function will wait for a free copy thread.
  //
  
function Queue$InputName$OutputName )
  {
    
// Index of the worker thread (-1 means we don't have one yet).
    
$Thread = -1;

    
// Find a free thread or wait for a thread to finish...
    
do
    {
      
// For each thread...
      
for ( $Index 0$Index $this->MaxThreads$Index++ ) 
      {
        
// Is it free?
        
if ( $this->CopyThreads$Index ]->GetDone() )
          
$Thread $Index// <- Use this thread.
      
}
    
      
// Did we find a free thread?
      
if ( -== $Thread )
        
sleep); // Nope... try again latter.
    

    while ( -
== $Thread );

    
// Create the job entry.
    
$Job = array();
    
$Job"From" ] = $InputName;
    
$Job"To"   ] = $OutputName;

    
// Start the thread working on this job.
    
$this->CopyThreads$Thread ]->RunJob$Job );
  }

  
//
  // Constructor.
  // Must be told the max number of copy threads to create.
  //
  
function ThreadPool$MaxThreads )
  {
    
$this->MaxThreads $MaxThreads;
    
$this->CopyThreads = array();

    for ( 
$Index 0$Index $MaxThreads; ++$Index )
    {
      
$this->CopyThreads$Index ] = new CopyThread"ThreadPoolWorker-" $Index );
      
$this->CopyThreads$Index ]->start();
    }

  }
}
?>