<?php /* This code is writed by Grigori A. Kochanov. * The script can be used, modified and redistributed freely * under the terms and conditions of the BSD public license. * * Requirements: PHP 5 CLI compiled with --enable-pcntl, POSIX functions not disabled * UNIX-style systems only * * version: 1 */
class Daemon{
//show demonstration messages const DEBUG_MODE = true;
//exit if sleeping more then MAX_SLEEP_HOURS const MAX_SLEEP_HOURS = 6;
//path to the pid file const PID_FILE_PATH='daemon.pid';
//service parameters const i_sleep = 1; const i_run = 2; const i_exit = 3; private $role; private $child_pid;
/** * Checks the configuration, register signal handler and start the multi-process daemon emulation * */ public function __construct(){ //check the PHP configuration if (!defined('SIGHUP')){ trigger_error('PHP is compiled without --enable-pcntl directive',E_USER_ERROR); } //check if the pid file is writable if (file_exists(self::PID_FILE_PATH ) && !is_writable(self::PID_FILE_PATH) || !file_exists(self::PID_FILE_PATH ) && !is_writable(dirname(self::PID_FILE_PATH)) ){ trigger_error('can not open PID file '.self::PID_FILE_PATH.' for writing', E_USER_ERROR); } // tick required as of PHP 4.3.0 declare(ticks = 2);
// setup signal handlers pcntl_signal(SIGTERM,array($this,'sigTermHandler')); pcntl_signal(SIGCONT,array($this,'sigContHandler')); pcntl_signal(SIGALRM,array($this,'sigAlrmHandler')); //register the shutdown function to waken the child register_shutdown_function(array($this,'wakeUpChild'));
//the parent will work $this->role = self::i_run; if (self::DEBUG_MODE){ echo "Root PID: ".posix_getpid()."\n"; } do{ //child sleeps if ($this->role == self::i_sleep ){ if (self::DEBUG_MODE){ echo 'process ', $pid," will sleep\n"; } sleep(0xFFFFFFFF); } //if we are asked to exit - let's do it if ($this->role == self::i_exit ){ @unlink(self::PID_FILE_PATH ); exit; } if ($this->role == self::i_run){ //spawn a child and continue the work $this->child_pid = pcntl_fork(); $pid = posix_getpid(); if (!$this->child_pid){ //it's a child - go to bed $this->role = self::i_sleep; pcntl_alarm(3600*self::MAX_SLEEP_HOURS); // max time to sleep, then exit } } }while ($this->role == self::i_sleep);
//write the PID file_put_contents(self::PID_FILE_PATH,$pid);
if (self::DEBUG_MODE){ echo 'process ',$pid, " continues opertions\n"; } }
/** * Catch the SIGTERM signal * */ private function sigTermHandler(){ if (self::DEBUG_MODE){ echo "SIGTERM CAUGHT\n"; } // I was asked to exit - pass the call to the child and remove the PID file if ($this->child_pid){ posix_kill($this->child_pid, SIGTERM); @unlink(self::PID_FILE_PATH ); } exit; }
/** * Catch the SIGCONT signal * */ private function sigContHandler(){ // I am waken up to run $this->role = self::i_run; }
/** * Catch the SIGALRM signal * */ private function sigAlrmHandler(){ //time is out $this->role = self::i_exit; }
/** * Send the signal to a child to wake him up to continue the work * */ public function wakeUpChild(){ if ($this->child_pid){ posix_kill($this->child_pid, SIGCONT); } }
/** * Send the SIGTERM to the process and the child * */ public function terminate(){ posix_kill(posix_getpid(), SIGTERM); }
//end of the class }
?>
|