Created
October 21, 2009 10:06
-
-
Save axgle/215008 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare (ticks=1); // Be sure that each signal is handled when it is received. | |
ini_set("max_execution_time", "0"); // Give us eternity to execute the script. We can always kill -9 | |
ini_set("max_input_time", "0"); | |
set_time_limit(0); | |
$GLOBALS['mtd_main_thread_pid']=posix_getpid(); | |
$GLOBALS['child'.$GLOBALS['mtd_main_thread_pid']] = 0; | |
function mtd_sig_handler($signo) { | |
switch ( $signo ) { | |
case SIGCHLD: | |
$GLOBALS['child'.$GLOBALS['mtd_main_thread_pid']]--; | |
print("SIGCHLD received\n"); | |
break; | |
default: | |
break; | |
} | |
} | |
pcntl_signal(SIGCHLD, "mtd_sig_handler"); | |
// Main class | |
abstract class MTDaemon { | |
/* | |
* Configuration vaiables | |
*/ | |
// max concurrent threads | |
// should be implemented with sem_get('name', $max_aquire) but this can't be dynamically updated as this var. | |
protected $max_threads = 4; | |
// sleep time when no job | |
protected $idle_sleep_time = 5; | |
/* | |
* Constructor | |
* | |
* @params $threads : number of concurrent threads, default 4 | |
* @params $idelsleeptime : time to sleep when no job ready (getNext return null), in seconds, default 5 | |
*/ | |
public function __construct($threads = null, $idlesleeptime = null, $sPIDFileName = null) { | |
global $argv; | |
// Init some variables | |
if ( $threads ) $this->max_threads = $threads; | |
if ( $idlesleeptime ) $this->idle_sleep_time = $idlesleeptime; | |
} | |
protected function _prerun() { | |
global $argv; | |
print($argv[0].': Starting daemon with '.$this->max_threads.' slots'); | |
} | |
/* | |
* Hook called just after the main loop | |
* Cleans up all semaphores and removes PID file | |
*/ | |
protected function _postrun() { | |
global $argv; | |
print($argv[0].': daemon exited.'); | |
} | |
/* | |
* Main loop, request next job using getNext() and execute run($job) in a separate thread | |
* _prerun and _postrun hooks are called before and after the main loop -> usefull for cleanup and so on. | |
*/ | |
public function handle() { | |
$this->run = true; | |
$this->_prerun(); | |
while ( $this->run ) { | |
$child=$GLOBALS['child'.$GLOBALS['mtd_main_thread_pid']]++; | |
if ( $child >=$this->max_threads ){ | |
pcntl_wait($status); | |
} | |
try { | |
$next = &$this->getNext($slot); | |
} catch( Exception $e ) { | |
MTLog::getInstance()->error('getNext() method: '.$e->getMessage()); | |
$this->bTerminate = true; | |
continue; | |
} | |
/* | |
* If no job | |
*/ | |
if ( !$next ) { | |
//print("no job\n"); | |
sleep ($this->idle_sleep_time); | |
continue; | |
} else { | |
// Fork off new child & do some work | |
$pid = pcntl_fork(); | |
if ( $pid==-1 ) { | |
$this->bTerminate = true; // Wait till children finish | |
continue; | |
} else if ( $pid ) { | |
unset ($next); | |
usleep(10); // HACK : give the hand to the child -> a simple way to better handle zombies | |
continue; | |
} else { | |
try { | |
$res = $this->run($next, $slot); | |
} catch( Exception $e ) { | |
print('run() method: '.$e->getMessage()); | |
$res = -1; | |
} | |
unset ($next); | |
exit ($res); | |
} | |
} | |
} | |
$this->_postrun(); | |
exit (0); | |
} | |
/* | |
* Request data of the next element to run in a thread | |
* This function will return the next element to process, or null if there is currently no job and the daemon should wait. | |
* | |
* slot = where the thread will be executed | |
* return null or false if no job currently | |
*/ | |
abstract public function getNext($slot); | |
/* | |
* Process the element fetched by getNext in a new thread | |
* This function is run in a separated thread (after forking) and take as argument the element to process (given by getNext). | |
* | |
* slot = where the thread will be executed | |
* return the exiting status of the thread | |
*/ | |
abstract public function run($next, $slot); | |
/* | |
* | |
*/ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment