<?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
}
?>
|