Add daemon support
git-svn-id: https://svn.fournier38.fr/svn/ProgSVN/trunk@4009 bf3deb0d-5f1a-0410-827f-c0cc1f45334c
This commit is contained in:
148
daemon.php
Normal file
148
daemon.php
Normal file
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
require_once ("domframework/fork.php");
|
||||
require_once ("domframework/file.php");
|
||||
|
||||
/** Manage a daemon.
|
||||
* Allow to start, stop, get status of a callable method
|
||||
*/
|
||||
class daemon
|
||||
{
|
||||
/** Set the directory to store the PID of the daemon
|
||||
*/
|
||||
private $runDir = "/var/run";
|
||||
|
||||
/** The constructor check if /proc is mounted
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
if (! file_exists ("/proc"))
|
||||
throw new \Exception ("Can't manage daemon: /proc doesn't exists", 500);
|
||||
}
|
||||
|
||||
/** Get/set the directory to store the PID of the daemon
|
||||
* @param string|null $val The directory
|
||||
*/
|
||||
public function runDir ($val = null)
|
||||
{
|
||||
if ($val === null)
|
||||
return $this->runDir;
|
||||
if (! is_string ($val))
|
||||
throw new \Exception ("Can not set daemon runDir: not a string", 500);
|
||||
$this->runDir = "$val";
|
||||
}
|
||||
|
||||
/** Start the callable method. The terminal is closed. All the displayed
|
||||
* messages from the child are silently dropped.
|
||||
* If some parameters are provided, the called child method will receive them
|
||||
* This function fork and return the child PID
|
||||
* @param string $name The name of daemon to start.
|
||||
* @param callable $callable The callback method to use in child
|
||||
* @param mixed|null $params The params to provide to child method
|
||||
* @return The child PID
|
||||
*/
|
||||
public function start ($name, $callable, $params = array ())
|
||||
{
|
||||
$file = new \file ();
|
||||
if (! $file->is_writeable ($this->runDir))
|
||||
throw new \Exception (sprintf ("Run Directory '%s' is not writeable",
|
||||
$this->runDir), 500);
|
||||
if (! $file->is_readable ($this->runDir))
|
||||
throw new \Exception (sprintf ("Run Directory '%s' is not readable",
|
||||
$this->runDir), 500);
|
||||
if ($file->file_exists ($this->runDir."/$name.pid"))
|
||||
{
|
||||
$pid = $file->file_get_contents ($this->runDir."/$name.pid");
|
||||
if (file_exists ("/proc/$pid"))
|
||||
throw new \Exception (sprintf (
|
||||
"Can't start the daemon: already running with PID %d", $pid), 500);
|
||||
}
|
||||
$fork = new \fork ();
|
||||
$pid = $fork->startDetachedChild ($name, $callable, $params);
|
||||
file_put_contents ($this->runDir."/$name.pid", $pid);
|
||||
return $pid;
|
||||
}
|
||||
|
||||
/** Stop a $name daemon
|
||||
* @param string $name The name of daemon to stop. The name must be the same
|
||||
* as the name used in the start method
|
||||
* @param integer $maxWaitStop The waiting maximum time after SIGTERM before
|
||||
* sending SIGKILL
|
||||
* @param integer $maxWaitKill The waiting maximum time after SIGKILL before
|
||||
* raising an error
|
||||
*/
|
||||
public function stop ($name, $maxWaitStop = 3, $maxWaitKill = 3)
|
||||
{
|
||||
$file = new \file ();
|
||||
if (! $file->is_writeable ($this->runDir))
|
||||
throw new \Exception (sprintf ("Run Directory '%s' is not writeable",
|
||||
$this->runDir), 500);
|
||||
if (! $file->is_readable ($this->runDir))
|
||||
throw new \Exception (sprintf ("Run Directory '%s' is not readable",
|
||||
$this->runDir), 500);
|
||||
if (! $file->file_exists ($this->runDir."/$name.pid"))
|
||||
throw new \Exception (sprintf (
|
||||
"PID file %s not found : can't stop the daemon",
|
||||
$this->runDir."/$name.pid"), 500);
|
||||
$pid = $file->file_get_contents ($this->runDir."/$name.pid");
|
||||
if (! file_exists ("/proc/$pid"))
|
||||
{
|
||||
$file->unlink ($this->runDir."/$name.pid");
|
||||
throw new \Exception (
|
||||
"Can't stop daemon $name. There is no process with the PID $pid",
|
||||
500);
|
||||
}
|
||||
posix_kill ($pid, SIGTERM);
|
||||
usleep (10000);
|
||||
$startWait = time ();
|
||||
while (time () < $startWait + $maxWaitStop)
|
||||
{
|
||||
// If the child is zombie and is connected to me, pcntl_waitpid allow it
|
||||
// to be destroyed to close correctely the parent
|
||||
pcntl_waitpid ($pid, $status, WNOHANG);
|
||||
if (! file_exists ("/proc/$pid"))
|
||||
{
|
||||
$file->unlink ($this->runDir."/$name.pid");
|
||||
return true;
|
||||
}
|
||||
usleep (100000);
|
||||
echo ".";
|
||||
}
|
||||
posix_kill ($pid, SIGKILL);
|
||||
$startWait = time ();
|
||||
while (time () < $startWait + $maxWaitKill)
|
||||
{
|
||||
if (! file_exists ("/proc/$pid"))
|
||||
{
|
||||
$file->unlink ($this->runDir."/$name.pid");
|
||||
return true;
|
||||
}
|
||||
usleep (100000);
|
||||
echo "X";
|
||||
}
|
||||
throw new \Exception ("Can't stop and can't kill the process $pid", 500);
|
||||
}
|
||||
|
||||
/** Status of a daemon
|
||||
* @param string $name The name of daemon to have status. The name must be
|
||||
* the same as the name used in the start method
|
||||
*/
|
||||
public function status ($name)
|
||||
{
|
||||
$file = new \file ();
|
||||
if (! $file->is_writeable ($this->runDir))
|
||||
throw new \Exception (sprintf ("Run Directory '%s' is not writeable",
|
||||
$this->runDir), 500);
|
||||
if (! $file->is_readable ($this->runDir))
|
||||
throw new \Exception (sprintf ("Run Directory '%s' is not readable",
|
||||
$this->runDir), 500);
|
||||
if (! $file->file_exists ($this->runDir."/$name.pid"))
|
||||
return "The daemon is be stopped";
|
||||
$pid = $file->file_get_contents ($this->runDir."/$name.pid");
|
||||
if (! file_exists ("/proc/$pid"))
|
||||
{
|
||||
$file->unlink ($this->runDir."/$name.pid");
|
||||
return "The daemon is stopped, but the PID file was remaining. Delete";
|
||||
}
|
||||
return "The daemon is running on PID $pid\n";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user